handler

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

如何判斷當前線程是否是主線程android

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

進度條的顯示,能夠直接在子線程裏面處理。特例。api

更新ui顯示只能在主線程。app

 

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

 

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方法。ide

 

  • void handleMessage(Message msg):處理消息的方法,一般是用於被重寫!
  • sendEmptyMessage(int what):發送空消息
  • sendEmptyMessageDelayed(int what,long delayMillis):指定延時多少毫秒後發送空信息
  • sendMessage(Message msg):當即發送信息
  • sendMessageDelayed(Message msg):指定延時多少毫秒後發送信息
  • final boolean hasMessage(int what):檢查消息隊列中是否包含what屬性爲指定值的消息 若是是參數爲(int what,Object object):除了判斷what屬性,還須要判斷Object屬性是否爲指定對象的消息

 

建立handler(),並實現處理消息的方法。函數

public void handleMessage(@NonNull Message msg);oop

按鈕1和按鈕2點擊事件,模擬耗時操做,開啓線程,而後發msg給hander; 處理函數根據消息參數,執行不一樣動做。post

 

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;
        }
    });    
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息