一、多任务实现的基本原理
- 默认情况下,同一个应用程序的所有组件都运行在同一个进程中,大部分应用程序是按这种方式运行的
- 在具体应用中需要通过设置mainifest文件中组件的android:process属性,是该组件运行在不同的进程中
- 元素也支持android:process属性,用于指定所有组件的默认进程
进程的层次结构
- 前台进程
- 可见进程
- 服务进程
- 后台进程
- 空进程
安卓中的线程
Android是单线程的模型,我们创建的Service、Activity均是在一个主线程处理,即UI线程。应用程序默认是一个单任务单线程的程序
UI线程运行着许多重要的逻辑,如事件处理、用户输入输出、Service等
虽然我们感觉上许多任务在同时运行,但实际上却是通过调度算法进行的串行运行。
因此,我们编写的代码实际上是穿插在主线程运行的,如果我们插入的代码比较耗时,就会阻塞UI线程上其他逻辑的执行,从而造成页面卡顿。如果卡顿超过5秒,系统就会触发ANR错误。所以,执行耗时的操作,需要创建新的线程执行。
注意:Android中的UI toolkit不是线程安全的,不能在非UI线程更新UI,所有对界面的更新都必须在UI线程执行
多任务的实现原理
- Android中的两种线程:UI主线程和工作线程
- 通常把耗时的操作放到工作线程执行,操作完成后,再通知主线程做出相应的响应
AsyncTask
- AsyncTask是android提供的异步处理的辅助类,可以实现耗时任务在其他线程处理,而处理结果在UI线程执行
- 屏蔽了线程和Handler,进行了高度封装
- 具有特定功能的回调方法:
onPreExecute():预处理方法 publishProgress():更新进度方法 onPostExecute():返回结果的方法
示例代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btn;
private TextView txt;
private ProgressBar progress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = findViewById(R.id.btn);
txt = findViewById(R.id.txt);
progress = findViewById(R.id.progress_horizontal);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn:
progress.setVisibility(ProgressBar.VISIBLE);
MyAsyncTask myAsyncTask = new MyAsyncTask();
myAsyncTask.execute(1000);
break;
}
}
private class MyAsyncTask extends AsyncTask<Integer, Integer, String> {
private final static String TAG = "MyAsyncTask";
public MyAsyncTask() {
super();
}
@Override
protected void onPreExecute() {
Log.d(TAG, "onPreExecute, thread id is: " + Thread.currentThread().getId());
}
@Override
protected void onPostExecute(String s) {
Log.d(TAG, "onPostExecute, thread id is: " + Thread.currentThread().getId());
txt.setText(s);
}
@Override
protected void onProgressUpdate(Integer... values) {
Log.d(TAG, "onProgressUpdate, thread id is: " + Thread.currentThread().getId());
progress.setProgress(values[0]);
}
@Override
protected String doInBackground(Integer... integers) {
Log.d(TAG, "doInBackground, thread id is: " + Thread.currentThread().getId());
for (int i = 0; i <= 10; i++) {
publishProgress(i*10);
try {
Thread.sleep(integers[0]);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "更新完成";
}
}
}
Handler机制
Handler是通过消息队列进行通信的机制
- Handler:负责消息的发送和处理,通过它实现工作线程和UI线程的消息通讯
- Looper:负责管理线程的消息队列和消息循环
- Message:线程间通讯的消息载体,Message充当消息封装的功能
- MessageQueue:消息队列,先进先出,保存待线程处理的消息
Looper类
Looper类是android系统封装消息循环和消息队列的一个类,线程可以通过Looper对象读写某个消息队列
Looper.myLooper():获得当前线程的Looper对象
Looper.getMainLooper():获得当前进程的主线程的Looper对象
Looper.prepare():创建消息队列
Looper.loop():进入消息循环
二、Service
Service是一个能够在后台执行长时间运行的操作应用程序组件,不提供用户界面,应用在后台启动一个Service运行,即使用户切换到另一个应用此Service业务继续运行
特点
- 无法与用户直接交互
- 必须由用户或其他程序启动
- 优先级介于前台应用和后台应用之间
Service具有自己的生命周期。Service生命周期与Activity生命周期是分离的,当Activity被暂停、销毁时,Service组件还可以继续处理其他任务
安卓支持服务的原因:
- 允许执行后台任务
- 实现同一设备上应用之间的跨进程通信
创建方式
- 自启动方式:startService
- 绑定方式:bindService
自启动方式
绑定方式
服务的生命周期
创建自启动类型服务
- 通过startService()方法创建一个启动型的Service
- 启动服务时需要通过intent显示或者隐式启动,Intent可以携带一部分数据,在Service的onStartCommand中可以使用其数据
- 默认启动的服务存在于主线程中,会导致主线程阻塞,故通常采用新线程模式启动服务
继承Service
继承IntentService
IntentService
IntentService是Service的子类,用于处理异步请求。大多数服务不需要处理多个请求,所以用IntentService是很好的选择。
客户端可以通过startService(Intent)方法传递请求Intent信息
IntentService实际上是实际上是