2016-11-05 4 views
0

Heute habe ich ein Problem in meinem Android-Projekt. Ich benutze einen Service mit einem Thread darin, um Ortsinformationen in einem Zeitraum von 10s zu protokollieren. Wenn ich jedoch die Bildschirmausrichtung (Hochformat -> Querformat) ändere, wurde der Zeitraum einfach durcheinander gebracht.Wie man einen Thread in einem Dienst stoppt

Ich denke, dass ich einen anderen Thread laufen lassen kann, so dass ich einen weiteren Thread hinterher laufen habe, sobald ich den Bildschirm rotiere. Ich habe Protokollnachrichten gedruckt und es scheint, dass ich richtig rate.

Hier ist mein Code:

public class LocationService extends Service 
{ 
    public Location loc; 
    public LocationService() 
    { 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int id) 
    { 
     Thread thread = new Thread(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE); 
       if (ContextCompat.checkSelfPermission(LocationService.this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) 
       { 
        loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); 
        if(loc == null) // fall back to network if GPS is not available 
        { 
         loc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); 
        } 
        if(loc != null) 
        { 
         Timer timer = new Timer(); 
         final String time = (new Date()).toString(); 
         timer.scheduleAtFixedRate(new TimerTask() 
         { 
          @Override 
          public void run() 
          { 
           Log.d(time, "hehe"); 
           double currentLat = loc.getLatitude(); 
           double currentLng = loc.getLongitude(); 
           Intent done = new Intent(); 
           done.setAction("location"); 
           done.putExtra("currentLat", currentLat); 
           done.putExtra("currentLng", currentLng); 
           sendBroadcast(done); 
           //Toast.makeText(LocationService.this, String.valueOf(currentLat) + String.valueOf(currentlng), Toast.LENGTH_LONG).show(); 
          } 
         }, 10000, 10000); 
        } 
       } 
       else 
       { 
        Toast.makeText(LocationService.this, "Please allow app to access your location", Toast.LENGTH_LONG).show(); 
       } 
      } 
     }); 
     thread.start(); 

     return START_STICKY; // stay running 
    } 

    @Override 
    public IBinder onBind(Intent intent) 
    { 
//  // TODO: Return the communication channel to the service. 
//  throw new UnsupportedOperationException("Not yet implemented"); 
     return null; 
    } 

// @Override 
// public void onDestroy() 
// { 
//  Log.d("hehe","onDestroy"); 
//  super.onDestroy(); 
// } 

} 

Hier ist der Code für die Aktivität:

public class MainActivity extends AppCompatActivity 
{ 
    private Toolbar toolbar; 
    private FragmentManager fragmentManager; 
    private LocalFragment localFragment; 
    private ServerFragment serverFragment; 
    private QueryFragment queryFragment; 
    private FragmentTransaction transaction; 
    public SQLiteHelper dbHelper; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     dbHelper = new SQLiteHelper(this); 

     //garb handlers 
     fragmentManager = getFragmentManager(); 
     localFragment = (LocalFragment) fragmentManager.findFragmentById(R.id.fragment_local); 
     serverFragment = (ServerFragment) fragmentManager.findFragmentById(R.id.fragment_server); 
     queryFragment = (QueryFragment) fragmentManager.findFragmentById(R.id.fragment_query); 

     // initial visibility 
     transaction = fragmentManager.beginTransaction(); 
     if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) 
     { 
      // toolbar (must be put in checking orientation because landscape layout does not have toolbar here) 
      toolbar = (Toolbar) findViewById(R.id.toolbar); 
      toolbar.setTitle(R.string.toolbar_title); 
      setSupportActionBar(toolbar); 

      transaction.show(localFragment); 
      transaction.hide(serverFragment); 
      transaction.hide(queryFragment); 
      transaction.commit(); 
     } 
     else // ORIENTATION_LANDSCAPE 
     { 
      transaction.hide(queryFragment); // landscape orientation does not need query function (?) 
      transaction.show(localFragment); 
      transaction.show(serverFragment); 
      transaction.commit(); 
     } 

     // register network status receiver 
     IntentFilter intentFilter = new IntentFilter(); 
     intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 
     NetworkStatusReceiver myNetworkReceiver = new NetworkStatusReceiver(); 
     registerReceiver(myNetworkReceiver, intentFilter); 

     // start location service 
     Intent intent = new Intent(this, LocationService.class); 
     intent.setAction("location"); 
     startService(intent); 

     // register location receiver 
     IntentFilter intentFilterLocation = new IntentFilter(); 
     intentFilterLocation.addAction("location"); 
     LocationReceiver myLocationReceiver = new LocationReceiver(); 
     registerReceiver(myLocationReceiver, intentFilterLocation); 



    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) 
    { 
     MenuInflater inflater = getMenuInflater(); 
     inflater.inflate(R.menu.menu_main_activity, menu); 
     return super.onCreateOptionsMenu(menu); 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) 
    { 
     transaction = fragmentManager.beginTransaction(); 
     // handle click event 
     if(item.getItemId() == R.id.action_online) 
     { 
      transaction.hide(localFragment); 
      transaction.hide(queryFragment); 
      transaction.show(serverFragment); 
      transaction.commit(); 
     } 
     else if(item.getItemId() == R.id.action_offline) 
     { 
      transaction.hide(serverFragment); 
      transaction.hide(queryFragment); 
      transaction.show(localFragment); 
      transaction.commit(); 
     } 
     else // Query 
     { 
      transaction.hide(localFragment); 
      transaction.hide(serverFragment); 
      transaction.show(queryFragment); 
      transaction.commit(); 
     } 

     return super.onOptionsItemSelected(item); 
    } 

    // receiver for network change action 
    private class NetworkStatusReceiver extends BroadcastReceiver 
    { 
     @Override 
     public void onReceive(Context context, Intent intent) 
     { 
      String action = intent.getAction(); 
      if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) // if receive network change event broadcast 
      { 
       Toast.makeText(context, "Network status changed!", Toast.LENGTH_LONG).show(); 

       // why I cannot use another thread to do so? CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 
//    Thread thread = new Thread(new Runnable() 
//    { 
//     @Override 
//     public void run() 
//     { 
         int type = 0; 
         ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 
         NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); // get current network type 
         if (networkInfo != null && networkInfo.isAvailable()) 
         { 
          type = networkInfo.getType(); 
          String typeName = networkInfo.getTypeName(); // (?) 
          //serverFragment = (ServerFragment)fragmentManager.findFragmentById(R.id.fragment_server); 
          if (type == ConnectivityManager.TYPE_WIFI) // wifi 
          { 
           WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE); 
           WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 
           Log.d("wifiInfo", wifiInfo.toString()); 
           Log.d("SSID",wifiInfo.getSSID()); 
           serverFragment.setNetworkStatusText("WIFI: " + wifiInfo.getSSID()); // thread issues here. WTF 
          } else if (type == ConnectivityManager.TYPE_MOBILE) // Cellar 
          { 
           serverFragment.setNetworkStatusText("Mobile Data"); 
          } else // no network 
          { 
           serverFragment.setNetworkStatusText("No Network"); 
          } 
         } else // no network 
         { 
          serverFragment.setNetworkStatusText("No Network"); 
         } 
//     } 
//    }); 
//    thread.start(); 
      } 
     } 
    } 

    // receiver for location per 10s 
    public class LocationReceiver extends BroadcastReceiver 
    { 
     @Override 
     public void onReceive(Context context, Intent intent) 
     { 
      String action = intent.getAction(); 
      if(action.equals("location")) 
      { 
       double currentLat = intent.getDoubleExtra("currentLat", 0.0); 
       double currentLng = intent.getDoubleExtra("currentLng", 0.0); 
       Date now = new Date(); 
       localFragment.addNewLocation(now, currentLat, currentLng); // add to list for listview 

       // TODO: 11/5/16 implement SQLite insert 
       dbHelper.addEntry(now, currentLat, currentLng); 

       Toast.makeText(MainActivity.this, "Current Location: " + String.valueOf(currentLat) + ", " + String.valueOf(currentLng), Toast.LENGTH_LONG).show(); 
      } 
     } 
    } 

    public void setNetworkStatus(String networkStatus) 
    { 
     serverFragment.setNetworkStatusText(networkStatus); 
    } 
} 

Meine Frage sind:

  1. Es scheint, dass die onDestroy() Methode nicht aufgerufen werden würde wenn man den Bildschirm dreht?
  2. Ein neuer Service wird nicht erstellt, wenn der Bildschirm gedreht wird?
  3. Wie kann ich den zuvor erstellten Thread stoppen? Oder was ist der beste Weg, um mit diesem Problem umzugehen?
+0

können Sie den Bind-Service verwenden, mit dem Sie auf das Thread-Objekt zugreifen können und dann, wenn Sie mit der Arbeit im Thread fertig sind, können Sie den Thread unterbrechen, also den Thread stoppen. – Raman

Antwort

2

Es scheint, dass die onDestroy() Methode nicht aufgerufen werden würde, wenn der Bildschirm drehen?

Nein, ist es nicht. Wenn Sie die Bildschirmausrichtung ändern, wird die Activity gelöscht und eine neue erstellt, aber Ihre Service wird noch ausgeführt. Die Bildschirmausrichtung hat keinen Einfluss darauf.

Wird beim Drehen des Bildschirms keine neue Service erstellt?

Nr. A Service ist im Wesentlichen ein Singleton. Android wird keine neue Instanz von Service erstellen, wenn bereits eine läuft. onStartCommand() wird jedoch erneut aufgerufen, da Ihre ActivitystartService() aufruft, wenn sie erstellt wird.

Wie kann ich den zuvor erstellten Thread stoppen? Oder was ist der beste Weg, um mit diesem Problem umzugehen?

Der einfachste Weg, um damit umzugehen, ist in onStartCommand() einzuchecken, wenn Ihr Thread bereits läuft. Wenn ja, müssen Sie es nicht erneut starten. Speichern Sie einen Verweis auf Ihre Thread in einer Mitgliedsvariablen (ein Feld) in Ihrem Service und rufen Sie isAlive() darauf, um zu sehen, ob es ausgeführt wird.

Auch in onDestroy() sollten Sie sicherstellen, dass Ihre Thread heruntergefahren wird, sonst wird es auch nach Ihrer Service läuft weiter laufen. Um dies zu tun, sollten Sie eine boolean Elementvariable (Feld) in der Thread erstellen, die Sie in jeder Schleife überprüfen. Stellen Sie unter onDestroy() Ihres Service das boolean so ein, dass das Thread beendet wird.

Verwandte Themen