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主要用於異步消息的處理:當發出一個消息以後,首先進入一個消息隊列,發送消息的函數即刻返回,而另一個部分在消息隊列中逐一將消息取出,而後對消息進行處理,也就是發送消息和接收消息不是同步的處理。 這種機制一般用來處理相對耗時比較長的操做異步
Handler對象在進行初始化的時候,會默認的自動綁定消息隊列。利用類post方法,能夠將Runnable對象發送到消息隊列中,按照隊列的機制按順序執行不一樣的Runnable對象中的run方法。ide
建立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; } });