以前項目中會遇到的內存泄漏的問題,其中就有Handler使用姿勢不正確造成的。修改過后沒有總結寫篇博客記錄,前幾天看書看到這里,順便寫篇博客記錄一下。
容易造成內存泄漏的一種Handler使用方法:將Handler聲明為Activity的內部類。在Java語言中,非靜態內部類會持有外部類的一個隱試引用,這樣就可能造成外部類無法被垃圾回收。而導致內存泄漏。
- private final Handler handler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- // ...
- }
- };
那么正確的使用就是:
1.將Handler聲明為靜態內部類。並持有外部類的若引用。
2.在子線程中使用Handler,這是需要我們自己創建一個Looper對象。
下面代碼介紹一下第一種用法:
- /**
- * 正確使用Handler方式
- */
- public class HandlerActivity extends AppCompatActivity {
- private final MyHandler mHandler = new MyHandler(this);
- /**
- * 靜態的匿名內部類不會持有外部類的引用
- */
- private static final Runnable sRunnable = new Runnable() {
- @Override
- public void run() {
- // ...你的操作
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_handler);
- mHandler.post(sRunnable);
- }
- /**
- * 聲明一個靜態的Handler內部類,並持有外部類的弱引用
- */
- private static class MyHandler extends Handler{
- private final WeakReference<HandlerActivity> mActivty;
- private MyHandler(HandlerActivity mActivty) {
- this.mActivty = new WeakReference<HandlerActivity>(mActivty);
- }
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- HandlerActivity activity = mActivty.get();
- if (activity != null){
- // ....
- }
- }
- }
- }
上面在Activity使用就需要聲明一個內部類,下面再看一個,將自定義Handler抽出去,也同樣達到效果的小栗子:
1.首先創建一個類,通過泛型將實例傳入
- public class UIHandler<T> extends Handler {
- protected WeakReference<T> ref;
- public UIHandler(T cls){
- ref = new WeakReference<T>(cls);
- }
- public T getRef(){
- return ref != null ? ref.get() : null;
- }
- }
2.看下activity中使用,直接用myHandler對象發送message即可。
- private static class UIMyHandler extends UIHandler<HandlerActivity>{
- public UIMyHandler(HandlerActivity cls) {
- super(cls);
- }
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- HandlerActivity activity = ref.get();
- if (activity != null){
- if (activity.isFinishing())
- return;
- switch (msg.what){
- case 1:{
- break;
- }
- // ...
- }
- }
- }
- }
- private UIMyHandler myHandler = new UIMyHandler(this);
最后在簡單介紹一下,Java弱引用以及軟引用還有虛引用。
個人認為,如果只是想避免OutOfMemory異常的發生,則可以使用軟引用。若果對於應用的性能更在意,想盡快回收一些占用內存比較大的對象,則可以使用弱引用。
和弱引用功能類似的是WeakHashMap,他對於一個給定的鍵,其映射的存在並不阻止垃圾回收器對該鍵的回收,回收以后,其條目從映射中有效的一處。WeakHashMap使用ReferenceQueue實現的這種機制。
java.lang.ref包中提供了幾個類:SoftReference類—>軟引用;
WeakReference類—>弱引用;
PhantomReference—>虛引用;(相當於沒有持有引用,形同虛設,隨時可能被回收)
弱引用實踐場景:自己定義Handler類采用弱引用方式,防止內存泄漏。
軟引用場景:應用中肯定會有很多的默認的圖片資源,會多次用到。如果每次都去獲取,讀取文件需要硬件操作,速度慢,導致性能降低。所以考慮將圖片緩存起來,需要時直接從內存中獲取,但是圖片占用內存空間很大,容易OutOfMemory。這時考慮軟引用。