安卓多任务实现的基本原理
Posted 春招进大厂的梦想家
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓多任务实现的基本原理相关的知识,希望对你有一定的参考价值。
安卓多任务实现的基本原理
一.基本概念
操作一些耗时操作时候,如I/O读写大文件,数据库操作以及网络下载需要很长时间,为了不阻塞用户界面,出现ANR(应用程序无响应)的响应提示窗口,这个时候我们考虑使用Thread线程来进行解决.
二.android中的进程和线程
在Android系统中,如果有一个应用程序组件时第一次被启用,而且这时候,应用程序也没有其他的组件来运行,则Android系统会为应用程序创建一个linux的进程,这个Linux进程包含一个线程,称为主线程或者UI线程.
当一个组件在被启动时,如果该process已经存在了,那么该组件就直接通过这个process被启动起来,并且运行在这个process的UI线程中.
1.进程
- 默认情况下,同一个应用程序内的所有组件都是运行在同一个进程中的,大部分应用程序都是按照这种方式运行的;
- 在具体应用中,很多时候需要通过在manifest文件中进行设置,通过修改四大组件在Manifest.xml的代码块中的android:proess属性指定组件运行的进程,使其运行在不同的process中。
- 中的元素也支持android:proess属性,用于指定所有组件的默认进程。
2.进程的重要性层次结构
进程有5中层次,按其重要程度递减分为
1.前台进程(用户当前操作所必须的进程)
- 拥有一个正在与用户交互的Activity
- 拥有一个Service,这个Service绑定了某一个正在与用户交互的Activity
- 拥有一个前台Service
- 拥有一个Service且它正在执行声明周期回调方法
- 拥有一个BroadcastReceiver且这个BroadcastReceiver正在执行onRece方法
2.可见进程
- 没有任何前台组件,但是仍然会影响用户在屏幕上所见内容的进程
- 拥有一个可见但是不可与用户交互的Activity
- 拥有一个Service,这个Service绑定了一个可见但是不可与用户进行交互的Activity
3.服务进程
- 由startService()方法启动的Service进程,虽然不直接和所见内容关联,但是会执行一些用户关心的操作,例如后台播放音乐或者下载数据等等
- 若系统不足以维持前台进程和可见进程,才会牺牲服务进程的空间
4.后台进程
- 包含用户不可见的Activity的进程,这些进程对用户体验没有直接影响,可以随时在任意时间终止它们,以回收内存资源.
- 系统通过LRU(最近最少使用)列表进行多个后台进程的管理,确保最近使用的Activity最后被终止
5.空进程
- 进程不含有任何应用组件,该进程主要作用是缓存,以改善在此进程中运行组件的启动时间。
- 系统会经常终正此类进程
3.线程
Android是单线程模型,我们创建的Service、Activity以及Broadcast均是在一个主线程处理,这里我们可以理解为uI线程。(应用程序是一个默认的单线程单任务程序)
Ul Thread中运行着许多重要的逻辑,如系统事件处理,用户输入事件处理,ul绘制,Service,Alarm等
我们编写的代码穿插在主线程的逻辑中,比如对用户触摸事件的检测和响应,对用户输入的处理,自定义View的绘制等。如果我们插入的代码比价耗时,如网络请求或数据库读取,就会阻塞uI线程其他逻辑的执行,从而导致界面卡顿。
如果卡顿时间超过5秒,系统就会报ANR错误。所以,执行耗时的操作,我们需要另起线程执行。
在新线程执行完耗时的逻辑后,往往需要将结果反馈给界面,进行uI更新。Android的ul toolkit不是线程安全的,不能在非uI线程进行uI的更新
所有对界面的更新必须在uI线程进行
安卓的单线程模式遵从两个原则
- 1.不要阻塞UI进程
- 2.不要在UI线程之外访问UI组件
创建线程: 基础操作都在UI线程中运行,耗时操作可以创建新的线程去完成
- 继承Thread类
- 实现Runnable接口
安卓提供的四种常用的操作多线程的方式,分别是:
- Handle + Thread
- AsyncTask
- ThreadPoolExecutor
- IntentService
————————————————————————————————————————————————————————————————————
三、实现多任务
1.多任务的实现原理
- 在Android中,我们把除uI线程外的,其他所有的线程都叫做工作线程,也就是说Android只会存在两种线程:UI主线程(ul thread)和工作线程(work thread)
- 我们把耗时的操作放在工作线程中去做。操作完成后,再通知UI主线程做出相应的响应。
- 这就需要掌握线程间通信的方式。在Android中提供了两种线程间的通信方式:
- AsyncTask机制
- Handler机制
(1)使用AsyncTask
- AsyncTask是Android框架提供的异步处理的辅助类,它可以实现耗时操作仕具他线程执行,而处理结果在Main线程执行
- 它屏蔽掉了多线程和Handler的概念,进行了较高程度的封装。
- 使用AsyncTask的代码很容易被理解,因为他们都有一些具有特定职责的方法,如:预处理的方法onPreExecute,后台执行任务的方法dolnBackground,更新进度的方法publishProgress,返回结果的方法onPostExecute等等
(2)Handle机制
- Handler机制是通过消息队列进行通信的机制,通过使用Handler,LooperMessageQueue,和Message这几个类协调来完成
- Handler:在android里负责发送和处理消息,通过它可以实现其他线程与Main线程之间的消息通讯
- Looper:负责管理线程的消息队列和消息循环
- MessageQueue:消息队列,先进先出,它的作用是保存有待线程处理的消息
(3)Handler类
- UI主线程在创建时会被自动创建一个消息队列和消息循环,主线程的Looper通过创建一个Handler对象,对外界提供了访问消息队列的渠道
- 主线程通过Handler.handleMessage()读取消息队列中的消息
- 工作线程通过方法发送消息到主线程的消息队列Handler.sendMessage() Handler.post()
————————————————————————————————————————————————————————————————
四、.Android实现多线程的两种操作模式
1Android有两种方式实现多线程操作UI:
- 第一种是创建新线程Thread,用handler负责线程间的通信和消息。
- 第二种方式AsyncTask异步执行任务
2.使用Handler实现多任务
在新的线程中调用主线程中的Handler的postXX和sendmessage方法来实现与主线程进行通信
使用post方法实现多任务的主要步骤:
- 创建一个Handler对象;
- 将要执行的操作卸载线程对象的run方法中;
- 使用post方法运行线程对象
- 如果需要循环执行,需要在线程对象的run方法中再次调用post方法
3.Handler机制实现异步任务demo
-
xml文件中添加一个TextView
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".AsynchronousTask.HandlerAsyTaskActivity"> <TextView android:id="@+id/textview" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="hello" android:textAllCaps="false" tools:ignore="MissingConstraints" /> </androidx.constraintlayout.widget.ConstraintLayout>
-
java文件 编辑代码
package com.example.handleractivity.AsynchronousTask; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.TextView; import com.example.handleractivity.R; public class HandlerAsyTaskActivity extends AppCompatActivity { private final static int TEST = 1; private TextView textView; //这是自己创建的Handler,实现异步任务,这里用来更改UI private Handler mHandler = new Handler(){ @Override public void handleMessage(@NonNull Message msg) { textView.setText("这是工作线程文本"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_asy_task); textView = findViewById(R.id.textview); // textView.setText("这是一段文本"); new ActivityThread().start(); } /* 这是一个线程不安全的行为 */ class ActivityThread extends Thread{ @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } // textView.setText("这是工作线程文本"); //使用handler发送消息至消息队列 Message message = new Message(); message.what = TEST; mHandler.sendMessage(message); } } }
我们设置一个线程,让其休眠3秒钟,然后执行 textView.setText(“这是工作线程文本”)操作,三秒之后程序会崩溃。
原因是: 不能在除了UI线程之外的线程里边进行更改UI的操作。
那怎么才能实现呢?
使用Handler实现异步任务,自己新建一个Handler,然后在工作线程中使用handler来传递信息。handler里面进行更改UI的操作,就可了
五、Handler机制方法调用
1.使用Runnable和Handler实现五秒钟之后出现弹窗
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HandlerPost.HandlerPostActivity">
<Button
android:id="@+id/btnShowToast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开启Toast"/>
<TextView
android:text="你好"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
public class HandlerPostActivity extends AppCompatActivity implements View.OnClickListener{
//写一个Handler
Handler countHandler = new Handler();
/*线程1:启动一个Toast显示线程*/
Runnable mRunToast = new Runnable() {
@Override
public void run() {
Toast.makeText(HandlerPostActivity.this,"hello Toast",Toast.LENGTH_SHORT).show();
}
};
private Button mbtnShowToast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_post);
mbtnShowToast = findViewById(R.id.btnShowToast);
mbtnShowToast.setOnClickListener(this);
}
//添加事件监听
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnShowToast:
/**
* SystemClock.uptimeMillis()表示开机到当前的一个累计时间
*/
countHandler.postAtTime(mRunToast, SystemClock.uptimeMillis()+5*1000);
break;
}
}
}
2.开辟一个工作线程配合Handler实现计数器的功能
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HandlerPost.HandlerPostActivity"
android:orientation="vertical">
<Button
android:id="@+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动"/>
<Button
android:id="@+id/btnStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关闭"/>
<Button
android:id="@+id/btnShowToast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开启Toast"/>
<TextView
android:id="@+id/tvCount"
android:text="你好"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
public class HandlerPostActivity extends AppCompatActivity implements View.OnClickListener {
Handler countHandler = new Handler();
int count = 0;
/*线程1:启动一个Toast显示线程*/
Runnable mRunToast = new Runnable() {
@Override
public void run() {
Toast.makeText(HandlerPostActivity.this, "hello Toast", Toast.LENGTH_SHORT).show();
}
};
/*线程2:文本区计数器线程*/
Runnable mRunCount = new Runnable() {
@Override
public void run() {
textCount.setText("count: " + String.valueOf(count++));
//再调用一次,以此形成一个类似于循环的操作,一秒加一次
countHandler.postDelayed(mRunCount, 1000);
}
};
private Button mbtnShowToast;
private TextView textCount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_post);
mbtnShowToast = findViewById(R.id.btnShowToast);
mbtnShowToast.setOnClickListener(this);
findViewById(R.id.btnStart).setOnClickListener(this);
findViewById(R.id.btnStop).setOnClickListener(this);
textCount = findViewById(R.id.tvCount);
}
//添加事件监听
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnShowToast:
/**
* SystemClock.uptimeMillis()表示开机到当前的一个累计时间
*/
countHandler.postAtTime(mRunToast, SystemClock.uptimeMillis() + 5 * 1000);
break;
case R.id.btnStart:
//表示推迟一秒执行
countHandler.postDelayed(mRunCount, 1000);
break;
case R.id.btnStop:
//移除回调的过程
countHandler.removeCallbacks(mRunCount);
break;
}
}
}
运行效果;
六、AsyncTask实现多任务
- 使用Handler类来在子线程中更新UI线程总会启动一些匿名的子线程,太多的子线程给系统带来了巨大的负担
- Andoroid提供了一个工具类AdyncTask,来实现异步执行任务
- AsyncTask是抽象类,具有三种泛型:Params、Progress、Result
- **Params: **表示启动任务执行的参数,比如HTTP请求的URL
- Progress: 表示后台任务执行的百分比
- **Result: **表示后台执行任务最终返回的结果,比如String,Integer等
- 通过继承一个AsyncTask类定义一个异步任务类
- Android提供一个让程序员编写后台操作更为容易和透明AsyncTask,使得后台线程能够在UI主线程外进行处理
- 使用AsyncTask,不需要自己来写后台线程,无需终结后台线程,只需要创建AsyncTask类,并实现其中的抽象方法以及重写某些方法
下面是一个实例,点击按钮,启动进度条。进度条加载完毕,把“执行完毕”显示在文本上
1.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".AsynchronousTask.AsyncTaskDemo">
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Press it"
android:textAllCaps="false" />
<TextView
android:id="@+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="30sp"
android:text="hello world" />
<ProgressBar
android:id="@+id/progressbar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
android:layout_marginTop="50dp" />
</LinearLayout>
2.java文件
public class AsyncTaskDemo extends AppCompatActivity implements View.OnClickListener {
private final static String TAG = "AsyncTaskDemo";
private Button mBtn;
private ProgressBar progressBar;
private TextView mTxt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setConte以上是关于安卓多任务实现的基本原理的主要内容,如果未能解决你的问题,请参考以下文章