zoukankan      html  css  js  c++  java
  • android 实例-弱引用示例 Handler正确使用方法

    实际问题

    android 习惯性问题:在使用handler的时候喜欢使用内部类形式。

    private final Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                // ...
            }
        };

    看一下问题代码和现象:

    package zol.com.zolcamera;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    
    public class AActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_a);
            findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    finish();
                }
            });
            mHandler.sendEmptyMessageDelayed(0, 2000);
        }
    
        Handler mHandler = new Handler() {
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                mHandler.sendEmptyMessageDelayed(0, 2000);
            }
        };
    
        @Override
        protected void onResume() {
    
            super.onResume();
        }
    }
    package zol.com.zolcamera;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    
    public class BActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_a);
            findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(BActivity.this, AActivity.class);
                    startActivity(intent);
                }
            });
        }
    }

    上面两个Activity B跳到A 再点button回A 。重复几次。再看一下内存情况。

    可以看到内存当中有好几个AActivity,并没有释放。

    如果你使用android studio 当你写出这样的代码的时候,IDE会提示你这样写法会造成内存泄漏。

    原因是:内部实例会持有外部类引用。

    当Activity finish的时候如果handler没有在工作,没有延时消息,那么问题不大,否则是finish不掉的。

    第一种解决办法,声明成静态。内部静态类不持有外部类引用。

    第二种解决法,换一种写法,不声明成内部类。

    package zol.com.zolcamera;
    
    import android.os.Handler;
    import android.os.Message;
    
    /**
     * Created by Administrator on 2018/3/8.
     */
    
    public class MyHandler extends Handler {
    
        AActivity mAActivity;
    
        public MyHandler(AActivity aActivity) {
            mAActivity = aActivity;
        }
    
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            sendEmptyMessageDelayed(0, 2000);
        }
    
        public void clear() {
            mAActivity = null;
            removeCallbacksAndMessages(null);
        }
    }

    这里手动做了对Activity的置空。如果不放心那就用软件引用。

     /** 
         * 声明一个静态的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){  
                    // ....  
      
                }  
            }  
        }  
      

    问题二:在主线程直接new Handler 使用的是主线程Looper.如果handler工作频率很高,会影响主线程的效率。

    所以某些UI操作 (对,ui操作)使用线程来执行。

    大家都知道Thread + Handler 来实现。在子线程里new handler 必须先准备Looper.调用Looper.prepar()才能用。

    google给大家其实已经提供了现成的,那就是HandlerThread ; 

      @Override
        public void run() {
            mTid = Process.myTid();
            Looper.prepare();
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();
            Looper.loop();
            mTid = -1;
        }

    这才是准备looper的正确姿势。

    下面声明Handler 

        private HandlerThread handlerThread;
        private Handler mHandler;
        public void initHandler() {
            handlerThread = new HandlerThread("camera");
            handlerThread.start();
            mHandler = new Handler(handlerThread.getLooper(), mCallback);
        }

    这个handler才是最好的。

    package zol.com.zolcamera;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    
    public class AActivity extends AppCompatActivity implements View.OnClickListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_a);
            findViewById(R.id.bt).setOnClickListener(this);
            initHandler();
            mHandler.sendEmptyMessageDelayed(0, 2000);
        }
    
    
        private HandlerThread handlerThread;
        private Handler mHandler;
    
        public void initHandler() {
            handlerThread = new HandlerThread("camera");
            handlerThread.start();
            mHandler = new Handler(handlerThread.getLooper(), mCallback);
        }
    
        Handler.Callback mCallback = new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                return false;
            }
        };
    
        @Override
        public void finish() {
            mHandler.removeCallbacksAndMessages(null);
            super.finish();
        }
    
        @Override
        public void onClick(View v) {
            finish();
        }
    
        @Override
        protected void onResume() {
    
            super.onResume();
        }
    }

    退出时做如下操作。

       @Override
        public void finish() {
            mHandler.removeCallbacksAndMessages(null);
            super.finish();
        }

    理论是可以了。

    以上内容只经过简单试验,有问题请看官自行研究。或与本人讨论。

  • 相关阅读:
    Avoiding the Backup of Online Redo Logs
    RMAN-20201: datafile not found in the recovery catalog
    ORA-15081: failed to submit an I/O operation to a disk
    字符串替换数字问题
    jstl换行符处理
    字符串匹配问题
    careercup题目20131013
    careercup题目20131010
    careercup题目201330928
    面试题(一)
  • 原文地址:https://www.cnblogs.com/mamamia/p/8523965.html
Copyright © 2011-2022 走看看