定義
Handler是用來結合線程的消息隊列來發送、處理"Message對象"和"Runnable對象"的工具。
每一個Handler實例之后會關聯一個線程和該線程的消息隊列。也就是說,當你創建一個Handler的時候,從此開始,他就會自動關聯到所在的線程/消息隊列,然后它就會陸續把Message/Runnable分發到消息隊列,並在他們出隊的時候處理掉。因為android只允許在主線程中更新UI,Handler的目的就是作為線程通信的橋梁,進而再通過主線程更新UI。使用Handler這種異步回調機制,使我們可以再完成一個很長的任務后再做出相應的通知。
Handler和Message、MessageQueue、Looper之間的關系
Message
Handler接收與處理的消息對象
MessageQueue
消息隊列,以先進先出隊列形式管理所有的Message,且在初始化Looper對象時會創建一個與之關聯的MessageQueue。每個線程最多只有一個MessageQueue。MessageQueue通常都是由Looper來管理,而主線程創建時,會創建一個默認的Looper對象,而Looper對象的創建,將自動創建一個MessageQueue。其他非主線程,不會自動創建Looper。
Looper
每個線程只能夠一個Looper,管理MessageQueue,不斷從中去除Message分發給對應的Handler處理。
通俗一點講:當我們的子線程想修改Activity中的UI組件時,我們可以新建一個Handler對象,通過這個對象向主線程發送消息;而我們發送的消息會先到主線程的MessageQueue中進行等待,由Looper按先入先出順序取出,再根據Message對象的what屬性分發給對應的Handler進行處理。
Handler的主要用途
1.推送未來某個時間點將要執行的Message或者Runnable到消息隊列
通過Handler+Message的方式更新UI
public class MainActivity extends AppCompatActivity { private TextView text; private static final int UPDATE_TEXT = 1; //整型常量用於表示更新TextView這個動作 @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.id.activity_main); text = (TextView) findViewById(R.id.text); Button chaneText = (Button) findViewById(R.id.change_text); change_text.setOnClickListener(this); } //新增Handler對象,並重寫父類的handlerMessage()方法,在這里對具體的Message進行處理 private Handler handler = new Handler(){ public void handleMessage(Message msg){ //收到消息,在HandleMessage()方法中對消息進行處理 switch (msg.what){ case UPDATE_TEXT: // 在這里進行UI操作,處於主線程中 text.setText("Nice to meet you"); break; default: break; } } }; @Override public void onClick(View v){ switch(v.getId()){ case R.id.change_text: new Thread(new Runnable(){ @Override public void run(){ Message message = new Message(); message.what = UPDATE_TEXT; //將waht字段的值指定為UPDATE_TEXT handler.sendMessage(message); //調用Handler的sendMessage()方法發送消息 } }).start(); break; default: break; } } }
2.在子線程把需要在另一個線程執行的操作加入到消息隊列中去
通過Handler + Message來實現子線程加載圖片,在UI線程顯示圖片
public class ThreadActivity extends AppCompatActivity implements View.OnClickListener { private ActivityThreadBinding mBinding = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView(this, R.layout.activity_thread); // 設置點擊事件 mBinding.clickBtn.setOnClickListener(this); mBinding.resetBtn.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { // 響應load按鈕 case R.id.clickBtn: // 開啟一個線程 new Thread(new Runnable() { @Override public void run() { // 在Runnable中進行網絡讀取操作,返回bitmap final Bitmap bitmap = loadPicFromInternet(); // 在子線程中實例化Handler同樣是可以的,只要在構造函數的參數中傳入主線程的Looper即可 Handler handler = new Handler(Looper.getMainLooper()); // 通過Handler的post Runnable到UI線程的MessageQueue中去即可 handler.post(new Runnable() { @Override public void run() { // 在MessageQueue出隊該Runnable時進行的操作 mBinding.photo.setImageBitmap(bitmap); } }); } }).start(); break; case R.id.resetBtn: mBinding.photo.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.default_pic)); break; } } /*** * HttpUrlConnection加載圖片,不多說 * @return */ public Bitmap loadPicFromInternet() { Bitmap bitmap = null; int respondCode = 0; InputStream is = null; try { URL url = new URL("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1421494343,3838991329&fm=23&gp=0.jpg"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(10 * 1000); connection.setReadTimeout(5 * 1000); connection.connect(); respondCode = connection.getResponseCode(); if (respondCode == 200) { is = connection.getInputStream(); bitmap = BitmapFactory.decodeStream(is); } } catch (MalformedURLException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "訪問失敗", Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return bitmap; } }