zoukankan      html  css  js  c++  java
  • 在非主线程中更新UI

    在非主线程中调用了showMessage方法,结果报错:Can't create handler inside thread that has not called Looper.prepare()

    1. private void showMessage(String msg) { 
    2.         Toast toast = Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT); 
    3.         toast.setGravity(Gravity.CENTER, 0, 0); 
    4.         toast.show(); 
    5.     } 

    原来Android中非主线程不能更新UI,Handler.post()方法可以解决这个问题:于是将showMessage方法稍作修改就可以了:

    1. private void showMessage(String msg) { 
    2.         mSg = msg; 
    3.         mHandler.post(new Runnable() { 
    4. @Override
    5. public void run() { 
    6.                   Toast toast = Toast.makeText(getApplicationContext(), mSg, Toast.LENGTH_SHORT); 
    7.                   toast.setGravity(Gravity.CENTER, 0, 0); 
    8.                   toast.show(); 
    9.             } 
    10.         }); 

    对下面程序的一些个人看法:

       1:  package com.example.progressbardemo;
       2:   
       3:  import java.security.PublicKey;
       4:   
       5:  import android.os.Bundle;
       6:  import android.os.Handler;
       7:  import android.app.Activity;
       8:  import android.view.Menu;
       9:  import android.widget.ProgressBar;
      10:   
      11:  public class MainActivity extends Activity {
      12:      
      13:      
      14:      private ProgressBar mProgressBar;
      15:      private  int mProgressStatus = 0;
      16:      
      17:      //创建一个Handler对象
      18:      
      19:      private Handler mHandler = new Handler();
      20:      
      21:      @Override
      22:      protected void onCreate(Bundle savedInstanceState) {
      23:          super.onCreate(savedInstanceState);
      24:          setContentView(R.layout.activity_main);
      25:          
      26:          mProgressBar = (ProgressBar) findViewById(R.id.progressbar2);
      27:          //设定进度条的最大值,其将为该进度条显示的基数
      28:          mProgressBar.setMax(1000);
      29:          //新创建一个线程
      30:          new Thread( new Runnable() {
      31:              @Override
      32:              public void run() {
      33:                  // TODO Auto-generated method stub
      34:                  //循环1000次,不停更新mprogresstatus 的值
      35:                  while(mProgressStatus++<1000)
      36:                  {
      37:                      //将一个runnable对象添加到消息队列中,并且当执行到该对象时执行run方法
      38:                      mHandler.post(new Runnable() {  //http协议里面也有post,他的意思是将此线程里面的东西交给另一个线程处理
      39:                          
      40:                          @Override
      41:                          public void run() {
      42:                              // TODO Auto-generated method stub
      43:                              //重新设置进度条当前的值
      44:                              mProgressBar.setProgress(mProgressStatus);
      45:                          }
      46:                      });
      47:                  }
      48:              }
      49:          }).start();    
      50:      }
      51:   
      52:      @Override
      53:      public boolean onCreateOptionsMenu(Menu menu) {
      54:          // Inflate the menu; this adds items to the action bar if it is present.
      55:          getMenuInflater().inflate(R.menu.main, menu);
      56:          return true;
      57:      }
      58:   
      59:  }

    public final boolean post (Runnable r) 
    Since: API Level 1 
    Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.
     

        是不是可以这么理解:mhandle.post(Runnable r) 执行这条语句时,其实主线程UI已经与handle建立了联系,然后Runnable其实就是在主线程中运行的,只不过他是在主线程的消息队列当中运行的。这句话就好比在非主线程中调用handler的sendmessage()方法,然后在主线程中调用handlemessage()方法去处理截获到的消息。

        handler.post(Runnable  r) 中的Runnable 会在handler 所在的线程执行, 也就是View 所在的UI线程。这个就是所谓的线程间异步通信。也就是说,非主线程中可以调用主线程中的handle类以及方法去处理主线程的消息队列。也就是老师您说的候车室一样,主线程当中的handle可以处理消息队列中的很多消息。然后Looper一般默认存在在主线程中,他里面就是一个消息队列Looper可以控制消息队列的出与进。

        new Handler()默认的Looper是主线程的, //每个Looper里面都有一个消息队列
    h = new Handler(Looper l)//l为主线程的Looper。此时h为l附属的handler,h的消息由post放在l的线程的队列中,由l所在的线程处理消息。(每个线程都有一个消息队列,h的消息由post放进I的线程所在的消息队列中去),这些也就是说明了,异步可以更新主线程UI。

    参考这篇文章:

    http://blog.sina.com.cn/s/blog_70677d110100s2kz.html

    Thread + Handler方法:

    具体是在需要重绘的地方调用handler的sendMessage方法发送消息,紧接着会os会触发handler中的handlerMessage方法,在handlerMessage方法中再调用view的invalidate或者postInvalidate方法就能实现重绘。
    下面是我分别针对invalidate方法,给出view重绘代码,仅供参考:

    Java代码 复制代码 收藏代码

    1. class CustomizeView extends WhichView { 
    2. public CustomizeView(Context context) { 
    3. super(context); 
    4. final Handler handler = new Handler(); 
    5. new Thread(new Runnable() { 
    6. @Override
    7. public void run() { 
    8. // delay some minutes you desire.
    9. handler.post(new Runnable() { 
    10. public void run() { 
    11. concreteUpdateUI(); 
    12. invalidate(); 
    13. }); 
    14. }).start(); 
    15. protected void concreteUpdateUI() { 
    16. // Add concrete movement for UI updates.
    17. // ...
    18. }

    或者这样实现也可以。

    Java代码 复制代码 收藏代码

    1. class CustomizeView extends TextView { 
    2. public CustomizeView(Context context) { 
    3. super(context); 
    4. new Thread(new UIUpdateThread()).start(); 
    5. class UIUpdateThread implements Runnable { 
    6. final Handler mHandler = new Handler(); 
    7. final Runnable mUpdateResults = new Runnable() { 
    8. public void run() { 
    9. concreteUpdateUI(); 
    10. invalidate(); 
    11. }; 
    12. public void run() { 
    13. // delay some minutes you desire.
    14. mHandler.post(mUpdateResults); 
    15. protected void concreteUpdateUI() { 
    16. // Add concrete movement for UI updates.
    17. // ...

    其他方法:

    如果你对于Android的Thread+Handler方式感觉繁琐,不妨试试Activity提供的另外一种简单的方法runOnUiThread,runOnUiThread可以帮助你在线程中执行UI更新操作,我们只需要在线程中写上类似

    MyActivity .this.runOnUiThread(new Runnable() {

    @Override

    public void run() {

    // refresh ui 的操作代码

    }

    });

    这里需要注意的是runOnUiThread是Activity中的方法,在线程中我们需要告诉系统是哪个activity调用,所以前面显示的指明了activity。

  • 相关阅读:
    Codeforces 1163E 高斯消元 + dfs
    Codeforces 1159E 拓扑排序
    Codeforces 631E 斜率优化
    Codeforces 1167F 计算贡献
    Codeforces 1167E 尺取法
    Gym 102007I 二分 网络流
    Codeforces 319C DP 斜率优化
    Codeforces 1163D DP + KMP
    Comet OJ
    Vue 的响应式原理中 Object.defineProperty 有什么缺陷?为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?
  • 原文地址:https://www.cnblogs.com/zhuxuekui/p/3605778.html
Copyright © 2011-2022 走看看