zoukankan      html  css  js  c++  java
  • handler

    https://www.jianshu.com/p/f70ee1765a61

    如何判断当前线程是不是主线程

    Looper.myLooper() == Looper.getMainLooper()
    Looper.getMainLooper().getThread() == Thread.currentThread()
    Looper.getMainLooper().isCurrentThread()

    进度条的显示,可以直接在子线程里面处理。特例。

    更新ui显示只能在主线程。

    https://baike.baidu.com/item/handler/10404534?fr=aladdin

    Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作

    1. 传递Message。用于接受子线程发送的数据, 并用此数据配合主线程更新UI。
    在Android中,对于UI的操作通常需要放在主线程中进行操作。如果在子线程中有关于UI的操作,那么就需要把数据消息作为一个Message对象发送到消息队列中,然后,由Handler中的handlerMessage方法处理传过来的数据信息,并操作UI。当然,Handler对象是在主线程中初始化的,因为它需要绑定在主线程的消息队列中。
    类sendMessage(Message msg)方法实现发送消息的操作。 在初始化Handler对象时重写的handleMessage方法来接收Message并进行相关操作。
    2. 传递Runnable对象。用于通过Handler绑定的消息队列,安排不同操作的执行顺序。

    Handler对象在进行初始化的时候,会默认的自动绑定消息队列。利用类post方法,可以将Runnable对象发送到消息队列中,按照队列的机制按顺序执行不同的Runnable对象中的run方法。

    • voidhandleMessage(Message msg):处理消息的方法,通常是用于被重写!
    • sendEmptyMessage(int what):发送空消息
    • sendEmptyMessageDelayed(int what,long delayMillis):指定延时多少毫秒后发送空信息
    • sendMessage(Message msg):立即发送信息
    • sendMessageDelayed(Message msg):指定延时多少毫秒后发送信息
    • final booleanhasMessage(int what):检查消息队列中是否包含what属性为指定值的消息 如果是参数为(int what,Object object):除了判断what属性,还需要判断Object属性是否为指定对象的消息

    创建handler(),并实现处理消息的方法。

    public void handleMessage(@NonNull Message msg);

    按钮1和按钮2点击事件,模拟耗时操作,开启线程,然后发msg给hander; 处理函数根据消息参数,执行不同动作。

    hander2 是在子线程处理接收消息,bt3,主线程发往子线程。

    子线程创建handler需要加looper。

    Looper.prepare();

    Looper.loop();

    子线程没有做控件操作,因为只有主线程才能进行UI操作。

    package com.example.handlerdemo;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.util.Log;
    import android.view.View;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.Random;
    
    public class MainActivity extends AppCompatActivity {
        private TextView txt;
        private String str = "";
        //1.实例化
        //2.在子线程中发送(空)消息
        private Handler handler = new Handler(){
            //3.由Handler对象接收消息,并处理
            //只要Handler发消息了,必然出发该方法,并且会传入一个Message对象
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                if(msg.what == 1) {
                    //btn1
                    txt.setText(str);
                }else if(msg.what == 2) {
                    //btn2
                    String str2 = "what:"+msg.what+",arg1:"+msg.arg1
                            +",arg2:"+msg.arg2+",随机数"+((Random)msg.obj).nextInt();
                    Toast.makeText(MainActivity.this, str2, Toast.LENGTH_SHORT).show();
                }
            }
        };
    
        Handler handler2;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            txt = findViewById(R.id.txt);
    
            new Thread(){
                @Override
                public void run() {
                    super.run();
                    Looper.prepare();   //准备,开始一个消息循环。系统会自动为主线程开启消息循环
                    handler2 = new Handler(){
                        @Override
                        public void handleMessage(@NonNull Message msg) {
                            super.handleMessage(msg);
                            Log.e("TAG","由主线程传递过来的Message,它的what是:"+msg.what);
                        }
                    };
                    Looper.loop();  //循环。相当于产生了一个while(true){....}
                }
            }.start();
        }
    //每个线程仅有一个Looper,对应一个MessageQueue
        public void myclick(View view) {
            switch (view.getId()){
                case R.id.btn1:
                    new Thread(){
                        @Override
                        public void run() {
                            str = get();
                            Log.e("TAG",str+"========");
                            //发消息
                            //handler.sendMessage()
                            //发空消息.参数:what?是Message对象的一个属性
                            handler.sendEmptyMessage(1);
    
    //                        runOnUiThread(new Runnable() {
    //                            @Override
    //                            public void run() {
    //                                //txt.setText(msg);
    //                            }
    //                        });
                        }
                    }.start();
                    break;
                case R.id.btn2:
                    new Thread(){
                        @Override
                        public void run() {
                            str = get()+"~~~~~~~";
                            //what :用于区分handler发送消息的不同线程来源
                            // arg1,arg2:如果子线程需要想主线程传递整型数据,则可用这些参数
                            // obj:Object  。
                            Message msg = new Message();
                            msg.what = 2;
                            msg.arg1 = 666;
                            msg.arg2 = 2333;
                            msg.obj = new Random();
                            //handler.sendEmptyMessage(2);
                            handler.sendMessage(msg);
                        }
                    }.start();
                    break;
                case R.id.btn3:
                    handler2.sendEmptyMessage(1000);
                    break;
                case R.id.btn4:
                    startActivity(new Intent(this,TimerActivity.class));
                    break;
                case R.id.btn5:
                    startActivity(new Intent(this,MemoryLeakActivity.class));
                    break;
            }
        }
    
        private String get() {
            try {
                URL url = new URL("http://www.imooc.com/api/teacher?type=3&cid=1");
    
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(6000);
    
                if(conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    InputStream in = conn.getInputStream();
                    byte[] b = new byte[1024];
                    int len = 0;
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    
                    while((len = in.read(b))>-1){
                        baos.write(b,0,len);
                    }
    
                    String msg = new String(baos.toByteArray());
                    return msg;
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
        }
    }

    使用post实现秒表。

    package com.example.handlerdemo;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.os.SystemClock;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    
    public class TimerActivity extends AppCompatActivity {
    
        private TextView title,timer,txt;
        private ImageView btn;
    
        private boolean flag = false;    //1.用于区别当前对按钮的点击是属于开启计时器还是停止计时器2.控制while循环
    
        //post      postDelay     postAtTime
        private Handler handler = new Handler();
        private int i;
        private String time;
        private Runnable runnable = new Runnable() {
            @Override
            public void run() {
                int min = i / 60;
                int sec = i % 60;
                // 00:00
                time = (min < 10 ? "0" + min : "" + min) + ":" + (sec < 10 ? "0" + sec : "" + sec);
                timer.setText(time);
                i++;
    
                handler.postDelayed(runnable,1000);
            }
        };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_timer);
    
            title = findViewById(R.id.title);
            timer = findViewById(R.id.timer);
            txt = findViewById(R.id.txt);
            btn = findViewById(R.id.btn);
    
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(flag == false) {
                        flag = true;
                        title.setText("工作中...");
                        btn.setImageResource(R.mipmap.stop);
                        txt.setText("");
                        i = 1;
                        new Thread() {
                            @Override
                            public void run() {
                                //递归
                                handler.postDelayed(runnable, 1000);
                            }
                        }.start();
                    }else{
                        flag = false;
                        title.setText("计时器");
                        btn.setImageResource(R.mipmap.start);
                        txt.setText("用时:"+time);
    
                        handler.removeCallbacks(runnable);
                    }
                }
            });
    
    
            /*
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //在post方法中,我们可以处理一切和视图相关的操作
                    new Thread(){
                        @Override
                        public void run() {
                            super.run();
    //                        try {
    //                            sleep(2000);
    //                        } catch (InterruptedException e) {
    //                            e.printStackTrace();
    //                        }
    
                            //运行机制:判断当前线程是不是主线程
                            //如果是:则直接执行Runnable对象的run方法
                            //如果不是:则由handler调用post方法
    //                        runOnUiThread(new Runnable() {
    //                            @Override
    //                            public void run() {
    //                                btn.setImageResource(R.mipmap.stop);
    //                            }
    //                        });
    
    //                        handler.post(new Runnable() {
    //                            @Override
    //                            public void run() {
    //                                btn.setImageResource(R.mipmap.stop);
    //                            }
    //                        });
    
    //                        handler.postDelayed(new Runnable() {
    //                            @Override
    //                            public void run() {
    //                                btn.setImageResource(R.mipmap.stop);
    //                            }
    //                        },3000);    //3000:指定是等待多长时间
    
    //                        handler.postAtTime(new Runnable() {
    //                            @Override
    //                            public void run() {
    //                                btn.setImageResource(R.mipmap.stop);
    //                            }
    //                        }, SystemClock.uptimeMillis() +3000);  //参数2:时间点。当前系统时间+3秒
                        }
                    }.start();
                }
            });*/
        }
    }

    内存泄漏

    延迟的Message对象-->Handler对象-->当前Activity对象

    延迟发送的message,

    或者发送大量的message,等同于消息没有处理完成,activity意外销毁。

    由于占用了 activity引用。窗体销毁了,但是没有释放资源。

    使用弱引用解决,或者直接在退出时候销毁

    handler.removeCallbacksAndMessages(null);

    package com.example.handlerdemo;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.util.Log;
    import android.view.View;
    import android.widget.TextView;
    
    import java.lang.ref.WeakReference;
    
    public class MemoryLeakActivity extends AppCompatActivity {
        private TextView txt;
    //    private Handler handler = new Handler(){
    //        @Override
    //        public void handleMessage(@NonNull Message msg) {
    //            super.handleMessage(msg);
    //                txt.setText("这是延迟发送消息后产生的新文本");
    //        }
    //    };
        private MyHandler handler = new MyHandler(this);
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_memory_leak);
    
            txt = findViewById(R.id.txt);
    
            findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //延迟的Message对象-->Handler对象-->当前Activity对象
                    handler.sendEmptyMessageDelayed(0,5*1000);
                }
            });
        }
    
        //解决Handler引发的内存泄露问题
        //1.主动清除所有的Message
        //2.弱引用
    //    @Override
    //    protected void onDestroy() {
    //        super.onDestroy();
    //        handler.removeCallbacksAndMessages(null);
    //    }
    
        private static class MyHandler extends Handler{
            private WeakReference<MemoryLeakActivity> wr;
    //        private MemoryLeakActivity mla;
    
            public MyHandler(MemoryLeakActivity mla){
    //            this.mla = mla;
                wr = new WeakReference<>(mla);
            }
    
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                Log.e("TAG","延迟处理消息");
                MemoryLeakActivity mla = wr.get();
                mla.txt.setText("xxxx");
            }
        }
    }

     关于handler内存问题

    https://blog.csdn.net/androidsj/article/details/79865091

    public static class MyHandler extends Handler {
            private WeakReference<Activity> reference
            public MyHandler(Activity activity) {
                reference = new WeakReference<Activity>(activity);
            }
            @Override
            public void handleMessage(Message msg) {
                if (reference.get() != null) {
                    switch (msg.what) {
                    case 0:
                        // do something...
                        break;
                    default:
                        // do something...
                        break;
                    }
                }
            }
        }
    静态内部类实现,据说这是最标准的写法。
    private MyHandler handler = new MyHandler(this);
        static class MyHandler extends Handler {
            WeakReference weakReference;
            public MyHandler(SecondActivity activity) {
                weakReference = new WeakReference(activity);
            }
     
            @Override
            public void handleMessage(Message msg) {
                
            }
        }
    另一种情况:
    不规范的写法:
     private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
     
            };
        };
    正确的写法:
     private Handler mHandler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                return false;
            }
        });    
  • 相关阅读:
    REST论文原文
    Rest无状态的一点理解(转)
    Kafka入门
    C#中@的用法总结(转)
    反应器(Reactor)用于事件多路分离和分派的体系结构模式
    数据库的脏读、不可重复读、幻读
    面向对象执行过程内存分析
    基于oracle的sql优化
    深入理解Spring中bean的生命周期
    Spring 框架原理
  • 原文地址:https://www.cnblogs.com/yuguangyuan/p/13232492.html
Copyright © 2011-2022 走看看