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:
- Es scheint, dass die
onDestroy()
Methode nicht aufgerufen werden würde wenn man den Bildschirm dreht? - Ein neuer
Service
wird nicht erstellt, wenn der Bildschirm gedreht wird? - Wie kann ich den zuvor erstellten Thread stoppen? Oder was ist der beste Weg, um mit diesem Problem umzugehen?
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