我从Activity
传递一个在mainUI线程上创建的处理程序并传递给执行某些网络操作的线程,当我获得结果时,我使用处理程序将结果发送回活动。
当我浏览这些链接时,这种方法在内存泄漏方面存在问题:
Inner ClassHandler Memory Leak
Android Developers
所以我实施了WeakReference
,并使用WeakReference
保留了活动实例。但即使活动被破坏,我仍然看到Activity
实例仍然存在。
我创建了一个Handler
内部活动,并将活动实例作为弱引用传递给处理程序。
当我的Handler
响应10secs后传递给它的消息时,Activity
被销毁。但弱引用仍然有Activity
实例,在Toast
被销毁后我看到了Activity
。
是否有一些我的理解错误?
有人可以解释如何处理传递给处理程序的消息,但UI不在吗?
import java.lang.ref.WeakReference;
import android.os.Handler;
import android.os.Message;
public abstract class SingleParamHandler <T> extends Handler
{
private WeakReference<T> mActivityReference;
public SingleParamHandler(T activity) {
mActivityReference = new WeakReference<T>(activity);
}
@Override
public void handleMessage(Message msg) {
if (mActivityReference.get() == null) {
return;
}
handleMessage(mActivityReference.get(), msg);
}
protected abstract void handleMessage(T activity, Message msg);
}
import android.app.Activity;
import android.os.Bundle;
import android.os.Message;
import android.widget.Toast;
public class MainActivity extends Activity {
MyHandler<MainActivity> handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main1);
handler = new MyHandler<MainActivity>(this);
new Thread(new MyRunnable(handler)).start();
}
public void onDestroy() {
super.onDestroy();
System.out.println("######## Activity onDestroy() ###### ");
}
private class MyRunnable implements Runnable {
private Handler mHandler;
public MyRunnable(Handler handler) {
mHandler = handler;
}
public void run() {
try {
Thread.sleep(10000);
mHandler.sendMessage(Message.obtain(handler, 1));
} catch ( Exception e) {
e.printStackTrace();
}
}
}
private static class MyHandler<T> extends SingleParamHandler<T> {
public MyHandler(T activity) {
super(activity);
}
@Override
public void handleMessage(T act, Message msg) {
if(msg.what == 1) {
Toast.makeText((MainActivity)act, "Called after activity destroyed", Toast.LENGTH_LONG).show();;
}
}
}
}
根据获得的回复,我在这里更新答案。你可以用你喜欢的方式做到这一点。但这是一种方式。
在SingleParamHandler
中添加了以下功能public void clear() {
mActivityReference.clear();
}
在Activity onDestroy()
中public void onDestroy() {
super.onDestroy();
System.out.println("######## Activity onDestroy() ###### ");
handler.clear();
}
答案 0 :(得分:5)
此处您不需要WeakReference
。 Handler
只能包含对Activity
的引用。在活动的onDestroy()
中,只需在MyHandler
上调用一个方法,即将Activity
的引用设置为null
。在null
中查看handleMessage()
。
另一个选择是:在活动的onDestroy()
中调用一个方法来中断休眠线程,使其在发送消息之前关闭。
答案 1 :(得分:3)
如果不需要,Android无法保证从内存中删除对象。换句话说,即使在调用onDestroy()
之后,Activity对象也可以保留在内存中(如果有足够的可用内存)。另一方面,如果没有足够的内存,则无法保证将onDestroy()
调用;恰恰相反,Android可以在您当前的Activity上调用onPause()
后取消整个过程(取决于Android版本)。
我认为为您的目的有更好的道路。您可能想要做的是附加,分离并可能重新附加(例如,在配置更改中)活动到您的服务。不希望垃圾收集器为你做这项工作。相反,明确地说明。
子类Activity
并覆盖生命周期方法以及startActivity()
和startActivityForResult()
,让您的服务现在知道谁负责。当然,这只是一种尽力而为的方法,因为一些回调不能保证,但这只在某些不危险的情况下才有意义。例如,您的活动不会在onPause()
中与您的服务分离,但它可能会在之后被杀死。但是你的服务在同一个进程中运行,所以它同时被杀死。或者它在不同的进程中运行,但Android会注意到连接断开,可能也可能不会终止服务;如果没有,那么你需要做的就是以强大的方式实现它,以便能够处理连接丢失。
<强>更新强>
阅读评论后:你是对的,我没有特别说明。
我正在弄清楚如何避免将消息发送到在被销毁的活动中创建的处理程序
鉴于上面的代码,并假设您真的只想显示Toast
一个活动,只要它存在,以下方法应该有所帮助。
Thread
应该提供多个活动,请对其进行扩展,以便活动可以在创建后向线程注册。如果您的Thread
只投放一个Activity
,请将Activity
引用与Handler
引用一起传递到Thread
(Runnable
建设。Thread
通过Handler
发送消息之前,请检查activity.isDestroyed()
。如果未销毁活动,请发送消息。如果活动被销毁,请不要发送消息。Runnable
的{{1}}方法,要么将run()
Activity
引用设置为null
Activity
已被销毁。这应该修复上面的代码。但是,如果您的方案增长,其他方法可能更合适。