android线程相关

首先,探讨一个问题,
android的UI操作只能在UI线程(即主线程)操作,为什么呢?
原因如下:
android在invalidate()时,会进行判断,如下:

void checkThread() {
2.
if (mThread != Thread.currentThread()) {
3.
throw new CalledFromWrongThreadException(
4.
"Only the original thread that created a view hierarchy can touch its views.");
5.
}
6.
}

Android UI是通过invalidate()方法去刷新界面的,而invalidate()方法没有进行线程同步,允许多个线程同时访问,invalidate()方法是线程不安全的,所以UI线程就就是不安全的。
线程不安全测策略性能较好。

android采用了UI操作只能在UI线程操作的策略,但是一些耗时的操作在UI线程执行的话,超过5秒易引起ANR,所以就有了耗时操作放到非主线程执行的说法,执行完后通知主线程更新UI.

配合上面的这些规定,android提供了以下几种方式:

1.handler+message机制
使用举例:
1.handler在UI线程处理消息:

public abstract class BaseTwoHandler<T> extends Handler {
//避免内存泄露,对activity的引用采取弱引用,因为有时会出现activity已destroy,message还存在,activity无法回收
    WeakReference<T> weakReference;
    public BaseTwoHandler(T t){
        weakReference=new WeakReference<>(t);
    }

    @Override
    public void handleMessage(Message msg) {
        T t=weakReference.get();
        if(t!=null){
            handleMessage(t,msg);
        }

    }

    public abstract void handleMessage(T t, Message message);
}
//子类继承basehandler
//在Java中,非静态(匿名)内部类会默认隐性引用外部类对象。而静态内部类不会引用外部类对象。
private static class TimeHandler extends BaseHandler<ChantingActivity> {

        public TimeHandler(ChantingActivity a) {
            super(a);
        }

        @Override
        public void handleMessage(Message msg, @NonNull ChantingActivity chantingActivity) {
            switch (msg.what){
                case UPDATE_COUNT_TIME:                   
                ..........
                    break;
                case SHOW_CONTINUE_DIALOG:   
                .........                 
                    break;
            }

        }
    }

在主线程实例化此handler,此handler即和主线程绑定。
子线程发送消息:

Message msg = handler.obtainMessage();
msg.obj = count;
msg.what = UPDATE_COUNT_TIME;
handler.sendMessage(msg);

activity的ondestroyzhong

if(handler != null){                handler.removeCallbacksAndMessages(null);
}

2.handler在子线程处理消息,进行耗时操作

子类化handler
class MyHandler extends Handler{ 
public MyHandler() {} 
public MyHandler(Looper looper){ 
super (looper); 
} 

public void handleMessage(Message msg){ 
//....这里运行耗时的过程
} 
} 
} 

将子线程与handler绑定
有了Handler子类,则可以在UI线程中进行创建和初始化

HandlerThread handlerThread = new HandlerThread( "backgroundThread" ); 
handlerThread.start(); 
MyHandler myHandler = new MyHandler(handlerThread.getLooper()); 
Message msg = myHandler.obtainMessage();
//....此处对msg进行赋值,可以创建一个Bundle进行承载
msg.sendToTarget();

之后如果需要调用线程,只要对handler传入msg,就可以执行相应的过程了
最后,很重要的一点,HandlerThread 不随Activity的生命周期结束而消亡,所以必须复写Ondestory(),调用HandlerThread .stop()

2.AsyncTask异步
使用Android系统工具类 AsyncTask(Params,Progress,Result)
AsyncTask是一个轻量级线程,三个泛型参数分别是 Params传入参数,int型Progress为进度条进度,Result为返回值。

要使用AsyncTask,必须继承之并复写其中的几个重要的函数。

onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。

doInBackground(Params…), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。

onProgressUpdate(Progress…),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.

注:Task必须在UI线程中创建,并调用并且只能调用一次execute方法,该方法的参数为传入的泛型Params。
其余函数最好不要手动调用,容易造成线程崩溃。多次调用Task,容易造成线程池溢出。

3.Activity.runOnUIThread(Runnable)

这个方法相当简单,我们要做的只是以下几步
1、编写后台线程,这回你可以直接调用UI控件
2、创建后台线程的实例
3、调用UI线程对应的Activity的runOnUIThread方法,将后台线程实例作为参数传入其中。
注意:无需调用后台线程的start方法

4.View.Post(Runnable)

该方法和方法二基本相同,只是在后台线程中能操控的UI控件被限制了,只能是指定的UI控件View。方法如下

1、编写后台线程,这回你可以直接调用UI控件,但是该UI控件只能是View
2、创建后台线程的实例
3、调用UI控件View的post方法,将后台线程实例作为参数传入其中。

5.View.PostDelayed(Runnabe,long)
该方法是方法三的补充,long参数用于制定多少时间后运行后台进程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值