Android 线程非静态内部类+弱引用避免内存泄漏
程序员文章站
2022-04-19 17:36:55
...
分享一篇文章说明(非静态内部类(包括匿名内部类),默认就会持有外部类的引用,当非静态内部类对象的生命周期比外部类对象的生命周期长时,就会导致内存泄漏。)
目前在我的项目中也都尽量采用了非静态内部类+弱引用的方式来处理线程,给自己简单记录一下
Android典型(容易造成内存泄漏)场景一:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxjava);
Message message=Message.obtain();
message.what=1;
handler.sendMessage(message);
}
private Handler handler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
//........................
}
}
};
引用文章 ---- 也许有人会说, mHandler 并未作为静态变量持有 Activity 引用, 生命周期可能不会比 Activity 长,应该不一定会导致内存泄露呢, 显然不是这样的!
熟悉 Handler 消息机制的都知道, mHandler 会作为成员变量保存在发送的消息 msg 中, 即 msg 持有handler 的引用, 而 handler 是 Activity 的非静态内部类实例, 即 handler 持有 Activity 的引用, 那么我们就可以理解为 msg 间接持有 Activity 的引用。 msg 被发送后先放到消息队列
MessageQueue 中, 然后等待 Looper 的轮询处理(MessageQueue 和 Looper 都是与线程相关联的,MessageQueue 是 Looper 引用的成员变量, 而 Looper 是保存ThreadLocal 中的)。 那么当 Activity退出后, msg 可能仍然存在于消息对列 MessageQueue 中未处理或者正在处理, 那么这样就会导致Activity 无法被回收, 以致发生 Activity 的内存泄露。
通常在 Android 开发中如果要使用内部类, 但又要规避内存泄露, 一般都会采用静态内部类+弱引用的方式。
Activiy 代码示例:
public class TestActivity extends AppCompatActivity {
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxjava);
handler=new MyHandler(this);
Message message = Message.obtain();
message.what = 1;
handler.sendMessage(message);
}
private class MyHandler extends Handler {
private WeakReference<TestActivity> weakReference;
public MyHandler(TestActivity testActivity) {
weakReference = new WeakReference<>(testActivity);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
TestActivity testActivity = weakReference.get();
if(testActivity!=null){
switch (msg.what){
//.............
}
}
}
}
/*handler通过弱引用的方式持有 Activity, 当 GC 执行垃圾回收时, 遇到 Activity 就会回收并释
放所占据的内存单元。 这样就不会发生内存泄露了。
上面的做法确实避免了 Activity 导致的内存泄露, 发送的 msg 不再已经没有持有 Activity 的引用
了, 但是 msg 还是有可能存在消息队列 MessageQueue 中, 所以更好的是在 Activity 销毁时就将
handler的回调和发送的消息给移除掉。*/
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
}
fragemnt:
public class BlankFragment extends Fragment {
private Handler handler;
public BlankFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view=inflater.inflate(R.layout.fragment_blank, container, false);
handler=new MyHandler(getActivity());
Message message=Message.obtain();
message.what=1;
handler.sendMessage(message);
return view;
}
private class MyHandler extends Handler {
private WeakReference<Activity> weakReference;
public MyHandler(Activity activity) {
weakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Activity activity = weakReference.get();
if (activity != null) {
switch (msg.what) {
//......................
}
}
}
}
@Override
public void onDetach() {
super.onDetach();
handler.removeCallbacksAndMessages(null);
}
}
还有 Thread和AsyncTask的写法一样都会容易造成泄漏,我们可以按照Handler的方法来处理。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxjava);
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
Activity Thread参考例子:
public class TestActivity extends AppCompatActivity {
// private Handler handler;
// private MyAsyncTask myAsyncTask;
private Thread mythread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxjava);
//第一种写法,匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//第二种写法,非静态内部类+弱引用
mythread= new Thread(new MyThreadRunnable(this));
mythread.start();
}
private class MyThreadRunnable implements Runnable {
private WeakReference<TestActivity> weakReference;
public MyThreadRunnable(TestActivity testActivity) {
weakReference = new WeakReference<>(testActivity);
}
@Override
public void run() {
TestActivity testActivity=weakReference.get();
if(testActivity!=null){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mythread.destroy();
}
}
Activity AsyncTask 参考例子:
public class TestActivity extends AppCompatActivity {
// private Handler handler;
// private MyAsyncTask handler;
private MyAsyncTask myAsyncTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxjava);
//第一种写法,匿名内部类
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... voids) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}.execute();
//第二种写法,非静态内部类+弱引用
myAsyncTask= new MyAsyncTask(this);
myAsyncTask.execute();
}
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private WeakReference<TestActivity> weakReference;
public MyAsyncTask(TestActivity testActivity) {
weakReference = new WeakReference<>(testActivity);
}
@Override
protected Void doInBackground(Void... voids) {
TestActivity testActivity=weakReference.get();
if(testActivity!=null){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
myAsyncTask.cancel(true);
}
}