android实现线程的三种方法,[原创]Android创建后台线程的三种方式

本文介绍了在Android应用开发中如何使用AsyncTask进行轻量级后台任务处理,包括其参数、回调方法和注意事项。此外,讲解了如何借助HandlerThread创建更复杂的后台线程,并利用synchronized、wait()和notify()进行线程同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android

应用层遵循单线程模型原则,在Activity被创建之时,会启用主线程(main),也就是UI线程。UI线程负责刷新UI界面和与UI相关的操作(控件监听、事件响应等)。由于Android的FC机制,主线程一旦被阻塞5s以上,则应用程序强制关闭。所以UI线程不能被阻塞,所以一些大量耗时的操作,必须放在后台线程运行。

后台运行的线程一般有如下几个特点:耗时较长,消耗资源较多,并且不一定会有结果或者确切的返回值(例如读取大型图片、音乐,或者下载网络资源),如果放在UI线程之中,极易导致应用程序崩溃,或者造成长时间的黑屏,影响用户体验。

创建后台线程的方法有多种,最近学到三种方法

1、使用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,容易造成线程池溢出。

2、使用Handler和HandlerThread

误区: Handler handler = new Handler ();

handler.post(r);

这种做法看似创建了一个线程,但实际上handler只是直接调用Runnable中的run()

方法,而不执行线程的start()函数,所以这两句代码执行后,程序仍然在UI线程中执行。所以我们引入HandlerThread,因为HandlerThread中有一个Looper对象,用以循环消息队列。

为了使用Looper,必须子类化Handler,并复写它的构造函数。

class

MyHandler

extends Handler{

public

MyHandler() {}

public

MyHandler(Looper looper){

super (looper);

}

public

void

handleMessage(Message msg){

//....这里运行耗时的过程

}

}

}

handleMessage(Message msg)函数用以接收消息,msg则是从UI线程中发出的消息,可以传递各种对象,根据这些对象和数值进行操作。

有了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()

3、使用线程同步 synchronized、 wait()、

notify()

使用线程同步机制synchronized实现多线程操作,相对来说比较复杂,但也是灵活性最佳、效率最高的一种做法,在产品开发当中也使用得最广。本人水平相当有限,也只学得一点皮毛。

synchronized相当于一把锁,当线程运行的时候,会同时有几个线程访问一个对象,对其进行操作或者修改。这可能引起很不良的后果(例如改变判定条件,或者在别的线程还没使用完的时候对象已经被析构等等),所以必须对一些对象进行加锁,保证它在同一时间只允许被一个线程访问。

synchronized使用方法有两种:

<1> 同步方法

在方法名前加入synchronized关键字,则该方法在同一时间内只允许一个线程访问它,其代码逻辑较为简单,但使用起来不太灵活,并且大大降低效率,耗时太长的同步方法甚至会使得多线程失去原本的意义成为单线程

<2>同步参数 对某一个代码块加锁,并且以synchronized(obj)的方式,表明该代码块内的obj对象是线程同步的。这个做法使得代码灵活性大大加强,缩小同步代码块的范围,并且可以在不同的函数体和类内进行同步,唯一遗憾的是实现起来比较复杂,容易产生一些问题

而wait()和notify(),必须在synchronized锁的代码块内执行,否则系统将会报错。

有了以上基础,就可以很容易的创建后台线程了

Private Runnable backgroundRunnable = new

Runnable () {

@Override

public

void

run() {

if(isFinish){

//.....

break;

}

for(;;){

synchronized(this){

//....写耗时过程

wait();

}

}

}

}

UI线程中,就是一般的创建线程过程了

Thread backgroundThread = new

Thread (backgroundRunnable);

backgroundThread.start();

这样,在后台线程中会不断的循环,当执行完一次过程以后就会wait()休眠。然后在OnTouchListener或者OnClickListener内相应的位置执行

synchronized(backgroundRunnable){

backgroundRunnable.notify();

}

当用户触摸屏幕产生一个event的时候,线程就会被唤醒,执行下一次循环。

最后,还是内存安全问题,必须复写Activity中的OnDestory()方法,将标志量isFinish设为false,并且backgroundThread

.stop()

author:zyn

email:26860002@qq.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值