android中在子线程中更新UI的几种方法

我们都知道android中,不允许在子线程中更新UI,凡是更新UI的操作必须放到主线程中,否则就会报如下异常:

android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

既然如此,android肯定也会给我们解决办法。

第一种:利用handler

1)private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg){
            
//这里是主线程 在这更新UI }; };
// 往handler发送一条消息 更改button的text属性
Message message = handler.obtainMessage();//当然也可以直接new 但是不推荐 因为通过obtainMessage实际是从消息池中获取的,可以节省内存
message.what =  1 ;
handler.sendMessage(message);
2)或者是通过handler的post方法回到主线程
handler.post(new Runnable() {
    @Override
    public void run() {
        
    }
});

在这有一点需要注意 在非UI线程中使用handler时,需要
Looper.prepare(); // 创建该线程的Looper对象
handler = new Handler(Looper.myLooper()) {
   public void handleMessage(android.os.Message msg) {
   Log.i( "handleMessage" , "" + msg.what);
       };
      };
 
Looper.loop();
第二种:利用异步任务
package com.personal.xiaoshuai.demo;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.widget.Toast;
class MyAsyncTask extends AsyncTask<String, Integer, Bitmap> {
    private Context context;
    public MyAsyncTask(Context context) {
        this.context = context;
    }
    /**
     * 运行在UI线程中,在调用doInBackground()之前执行
     */
    @Override
    protected void onPreExecute() {
        Toast.makeText(context, "onPreExecute", Toast.LENGTH_SHORT).show();
    }
    /**
     * 后台运行的方法,可以运行非UI线程,可以执行耗时的方法
     */
    @Override
    protected Bitmap doInBackground(String... params) {
        return null;
    }
    /**
     * 运行在ui线程中,在doInBackground()执行完毕后执行
     */
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        //在这更新UI
    }
    /**
     * 在publishProgress()被调用以后执行,publishProgress()用于更新进度
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
    }
}  
第三种:利用runOnUiThread方法中更新UI
//这个方法是activity的方法 假如当前线程是UI线程会立即执行方法体中的方法,如果当前线程不是UI线程,操作是发布到事件队列的UI线程再执行
runOnUiThread(new Runnable() {
            @Override
            public void run() {
              //在这更新UI
            }
        });
顺便给大家看一下acitivity中的源码,其实它内部也是封装的handler
/**
 * Runs the specified action on the UI thread. If the current thread is the UI
 * thread, then the action is executed immediately. If the current thread is
 * not the UI thread, the action is posted to the event queue of the UI thread.
 *
 * @param action the action to run on the UI thread
 */
public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}
第四种:View调用post方法实现更新UI
textView.post(new Runnable() {
    @Override
    public void run() {
        textView.setText("嘻嘻嘻");
    }
});
view的post方法又是如何实现从子线程中回到主线程的呢 我们看一下
/**
 * <p>Causes the Runnable to be added to the message queue.
 * The runnable will be run on the user interface thread.</p>
 *
 * @param action The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 *
 * @see #postDelayed
 * @see #removeCallbacks
 */
public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().post(action);
    return true;
}
可以看到当attachInfo != null(Android的窗口系统就是用过AttachInfo来判断View的所属窗口的)的时候还是会回到handler 假如为null还会走到下面的代码 大致我们可以猜到是放到某个执行队列中当中,我大致跟了下
源码,最终还是回到了handler 。另外AsyncTask内部其实也是对handler进行了封装。
好了,其实没有新知识,建议大家看下handler源码 可以更好的理解android机制。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android实现多线程几种方式有以下几种方法。首先,可以使用Java的Thread类来创建和管理线程。这种方式需要手动创建线程对象,并在run()方法编写线程的逻辑。其次,可以使用Java的Runnable接口来实现多线程。这种方式需要创建一个实现了Runnable接口的类,并将其作为参数传递给Thread类的构造函数。然后,可以使用Handler类来实现多线程。通过Handler的post()或postDelayed()方法,可以将任务添加到主线程的消息队列,从而在主线程执行异步操作。此外,还可以使用AsyncTask类来实现多线程。AsyncTask是Android提供的一个封装好的线程池,可以方便地在后台执行耗时操作,并在主线程更新UI。通过重写AsyncTask的doInBackground()方法来执行耗时操作,并通过onPostExecute()方法更新UI。需要注意的是,AsyncTask必须在主线程创建实例,并且execute()方法也必须在主线程调用。另外,Android 3.0之后,可以使用executeOnExecutor()方法来实现并发执行多个AsyncTask任务。总结起来,Android实现多线程几种方式包括使用Thread类、Runnable接口、Handler类和AsyncTask类。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [Android——多线程的多种实现方式](https://blog.csdn.net/abliudede/article/details/104891324)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Android开发四种常用的多线程实现方式](https://blog.csdn.net/star_nwe/article/details/130140238)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值