Here is an example application I wrote to reproduce the memory leak related issue i have met :
package a.b.mapleak;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MapLeak extends Activity
{
TextView callVoidText, getNewDataText, getDataStringText;
Button callVoidButton, getNewDataButton, getDataStringButton;
Handler callbackHandler;
MemoryLeak memleak;
private LoadAccountsTask mLoadAccountsTask = null;
private class LoadAccountsTask extends AsyncTask<Void, Void, Object[]> {
private int mCursor1;
private int mCursor2;
private Context context;
private UITask t = new UITask();
@Override
protected Object[] doInBackground(Void... params) {
runOnUiThre开发者_开发知识库ad(t);
// Create the summaries cursor
mCursor1 = 1;
mCursor2 = 2;
return new Object[] { mCursor1, mCursor2};
};
private class UITask extends Thread {
@Override
public void run() {
int i = 2;
while (i>0) {
i--;
}
Thread.State state=t.getState();
Log.e(ALARM_SERVICE, "Thread state in run is " + state.toString());
}
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getDataStringText = (TextView) findViewById(R.id.getDataString_text);
getDataStringButton = (Button) findViewById(R.id.getDataString_button);
getDataStringButton.setOnClickListener(new Button.OnClickListener() {
long i = 0;
public void onClick(View v) {
if (mLoadAccountsTask != null) mLoadAccountsTask.cancel(true);
mLoadAccountsTask = (LoadAccountsTask) new LoadAccountsTask(this).execute();
}
});
}
}
I found that the thread started in runOnUiThread
has never been exited. For some unknown to me reason the task was running, but the output from
Log.e(ALARM_SERVICE, "Thread state in run is " + state.toString());
every time was "Thread state in run is NEW" e.g. ''The thread has been created, but has never been started.''. So the thread was running continuously preventing "LoadAccountsTask" class from being garbage collected. Thus, in this example, every time the button is pressed - the new "LoadAccountsTask" appeared in memory.
But, if to replace
private class UITask extends Thread
with
private class UITask implements Run
there was no memory leak, the thread exited successfully. Of course state=t.getState(); will not work in this case and should be commented.
Do anybody have an explanation why it is so?
Focusing on your immediate concern, runOnUiThread()
takes a Runnable
. While Thread
does implement Runnable
, runOnUiThread()
will not treat it as a Thread
. Please just pass a Runnable
to runOnUiThread()
.
Second, never call runOnUiThread()
from doInBackground()
. Just perform the work from that Runnable
in onPreExecute()
or onPostExecute()
, which are executed on the main application thread.
Third, if you ever do write a real Thread
, don't busy-loop in it.
精彩评论