快速切换到主线程更新UI的几种方法

方法一: view.post(Runnable action)

假如该方法是在子线程中

textView.post(new Runnable() {
        @Override
        public void run() {
            textView.setText("更新textView");
            //还可以更新其他的控件
            imageView.setBackgroundResource(R.drawable.update);
        }
    });
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这是view自带的方法,比较简单,如果你的子线程里可以得到要更新的view的话,可以用此方法进行更新。

view还有一个方法view.postDelayed(Runnable action, long delayMillis)用来延迟发送。


方法二: activity.runOnUiThread(Runnable action)

假如该方法是在子线程中

注意:context 对象要是 主线程中的MainActivity,这样强转才可以。

public void updateUI(final Context context) {
        ((MainActivity) context).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //此时已在主线程中,可以更新UI了
            }
        });
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果没有上下文(context),试试下面的方法: 
1.用view.getContext()可以得到上下文。 
2.跳过context直接用new Activity().runOnUiThread(Runnable action)来切换到主线程。


方法三: Handler机制

首先在主线程中定义Handler,Handler mainHandler = new Handler();(必须要在主线程中定义才能操作主线程,如果想在其他地方定义声明时要这样写Handler mainHandler = new Handler(Looper.getMainLooper()),来获取主线程的 Looper 和 Queue )

获取到 Handler 后就很简单了,用handler.post(Runnable r)方法把消息处理放在该 handler 依附的消息队列中(也就是主线程消息队列)。

(1):假如该方法是在子线程中

    Handler mainHandler = new Handler(Looper.getMainLooper());
    mainHandler.post(new Runnable() {
        @Override
        public void run() {
            //已在主线程中,可以更新UI
        }
    });
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Handler还有下面的方法: 
1.postAtTime(Runnable r, long uptimeMillis); //在某一时刻发送消息 
2.postAtDelayed(Runnable r, long delayMillis); //延迟delayMillis毫秒再发送消息

(2): 假设在主线程中

    Handler myHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case 0:
                    //更新UI等
                    break;
                case 1:
                     //更新UI等
                    break;
                default:
                    break;
            }
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

之后可以把 mainHandler 当做参数传递在各个类之间,当需要更新UI时,可以调用sendMessage一系列方法来执行handleMessage里的操作。

假设现在在子线程了

    /**
      *获取消息,尽量用obtainMessage()方法,查看源码发现,该方法节省内存。
      *不提倡用Messenger msg=new Messenger()这种方法,每次都去创建一个对象,肯定不节省内存啦!
      *至于为什么该方法还存在,估计还是有存在的必要吧。(留作以后深入研究)
      */
    Message msg = myHandler.obtainMessage();
    msg.what = 0; //消息标识
    myHandler.sendMessage(msg); //发送消息
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如上代码,只是发送了个消息标识,并没有传其他参数。 
如果想传递参数,可以这样:

      msg.what = 1;  //消息标识
      msg.arg1=2;   //存放整形数据,如果携带数据简单,优先使用arg1和arg2,比Bundle更节省内存。
      msg.arg2=3;   //存放整形数据
      Bundle bundle=new Bundle();
      bundle.putString("dd","adfasd");
      bundle.putInt("love",5);
      msg.setData(bundle);
      msg.obj=bundle;   //用来存放Object类型的任意对象
      myHandler.sendMessage(msg); //发送消息            
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

总结: msg.obj它的功能比较强大一下,至于它和利用Bundle传递数据,那个会效率高一些,更节省内存一些。个人认为:从传递数据的复杂程度看,由简单到复杂依次使用,arg1, setData(), obj。会比较好一些。

当然可以用简化方法sendEmptyMessage(int what)来减少不必要的代码,这样写:

 myHandler.sendEmptyMessage(0); //其实内部实现还是和上面一样
 
 
  • 1

发送消息的其他方法有:

endEmptyMessageAtTime(int what, long uptimeMillis); //定时发送空消息
sendEmptyMessageDelayed(int what, long delayMillis); //延时发送空消息
sendMessageAtTime(Message msg, long uptimeMillis); //定时发送消息
sendMessageDelayed(Message msg, long delayMillis); //延时发送消息
sendMessageAtFrontOfQueue(Message msg); //最先处理消息(慎用)
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

方法四: 使用AsyncTask

/**
  * 该类中方法的执行顺序依次为:onPreExecute, doInBackground, onPostExecute
  */
    private class MyAsyncTask extends AsyncTask<String, Integer, String> {
        /**
         * 主线程中执行
         * 在execute()被调用后首先执行
         * 一般用来在执行后台任务前对UI做一些标记
         */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            System.out.println("MyAsyncTask.onPreExecute");
        }

        /**
         * 子线程中执行,执行一些耗时操作,关键方法
         * 在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。
         */
        @Override
        protected String doInBackground(String... params) {
            System.out.println("MyAsyncTask.doInBackground");
            //只是模拟了耗时操作
            int count = 0;
            for (int i = 0; i < 10; i++) {
                try {
                    count++;
                    publishProgress((count % 100) * 10);
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // publishProgress((int) ((count / (float) total) * 100));
            return "耗时操作执行完毕";
        }

        /**
         * 主线程中执行
         * 在调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件中
         */
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressBar.setProgress(values[0]);
            textView.setText("loading..." + values[0] + "%");
            System.out.println("MyAsyncTask.onProgressUpdate");
        }

        /**
         * 在主线程中,当后台操作结束时,此方法将会被调用
         * 计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。
         */
        @Override
        protected void onPostExecute(String aVoid) {
            super.onPostExecute(aVoid);
            System.out.println("MyAsyncTask.onPostExecute aVoid=" + aVoid);
            textView.setText(aVoid);
        }


        /**
         * 主线程中执行
         * 当异步任务取消后的,会回调该函数。在该方法内可以更新UI
         */
        @Override
        protected void onCancelled() {
            super.onCancelled();
            System.out.println("MyAsyncTask.onCancelled");
            progressBar.setProgress(0);
            textView.setText("0");
        }

        @Override
        protected void onCancelled(String s) {
            super.onCancelled(s);
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

注意:doInBackground方法是在子线程中,所以,我们在这个方法里面执行耗时操作。同时,由于其返回结果会传递到onPostExecute方法中,而onPostExecute方法工作在UI线程,这样我们就在这个方法里面更新ui,达到了异步更新ui的目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值