Android - multithreading issues when changing activity
I have a main menu with an action bar. On create, I run a thread that hits my server for a current status. When Complete, the thread calls a handler which kicks off a constantly running thread that cycles through the items and uses another handler call to change the test in the actionbar. The problem is that when I change views, I either get android.view.WindowLeaked
or View not attached to window manager
Here is some sample code
public class MainMenuActivity extends ProtectedWithActionBarActivity{
private int STATUS_COUNTER;
private final int RESULT_STATUS_LOADED = 2000;
private final int RESULT_SHOW_STATUS = 2001;
private CurrentStatusModel currentStatus;
@Override
public void onCreate(Bundle savedInstanc开发者_如何学CeState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainmenu);
ActionBar footerbar = (ActionBar)findViewById(R.id.footerbar);
footerbar.setTitle("Currently connected to " + PreferencesHelper.getCurrentEnvironment().name());
STATUS_COUNTER = 0;
statusLoadThread.start();
}
Thread statusLoadThread = new Thread()
{
@Override
public void run()
{
//set currentStatus with data from server
}
};
Thread statusDisplayThread = new Thread()
{
int sleep = 5000;
boolean threadDone = false;
public void done()
{
threadDone = true;
}
@Override
public void run()
{
while(true)
{
//pick message to send to handler
//increment STATUS_COUNTER or reset to 0 when out of bounds
try
{
sleep(sleep);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch(msg.what)
{
case RESULT_STATUS_LOADED:
statusDisplayThread.start();
break;
case RESULT_SHOW_STATUS:
ActionBar footerbar = (ActionBar)findViewById(R.id.footerbar);
String message = ((Object[])msg.obj)[0].toString();
OnClickListener listener = (OnClickListener)((Object[])msg.obj)[1];
footerbar.setTitle(message);
footerbar.setOnTitleClickListener(listener);
break;
case ActivityBase.RESULT_ERROR:
break;
}
}
};
}
I'm not sure if what I'm doing is just wrong or if there is something blatantly obvious that I am missing. What needs to happen is the threads need to stop any time I change screens. Should I use Thread.interrupt();
before starting the next activity?
AsyncTasc allows you to implement doInBackground()
, where your thread can crank away at its task. This is similar to the functionality you'd get from Thread
.
The real magic happens when you override onPreExecute()
and onPostExecute()
, which are both executed on the UI thread. This should keep you from getting messages about your Activity not being attached.
Edit - this answer contains a small code example for AsyncTask
that could get you started.
You are trying to update UI elements after the owning Activity has been detached from the windowing system.
You will make your life a lot simpler if you use AsyncTask
instead of vanilla threads (no handler needed, for one thing) and cancel()
the background tasks from your Activity.onPause()
.
Can't you set a flag in onPause
that each of your Thread
s checks for? If the flag is set then the thread drops out of its loop. Thus whenever the Activity
is moved to the background each of your Thread
s will stop. You would need to handle restarting the threads in onResume
. You could alternatively use the AsyncTask
approach, but this is not guaranteed to actually cancel when you call its cancel()
method, it only attempts to cancel the task.
精彩评论