大家好,我叫王菜鸟,今天给大家分享的内容是Android中异步的处理。那下面我们就从几个方面开始介绍Android中的异步操作。
同步,异步可以理解成是形容词,修饰一次方法的调用,同步方法一旦开始,调用者必须等到方法调用返回后才进行后面的一系列操作。异步方法调用,则比较类似一次消息的发送,一旦开始就会立即返回,调用者此时不用等待被调用的操作执行完成才继续执行,而是继续处理调用者后续的操作。
我们要清楚为什么异步,那就得知道什么是并行什么是并发。并行的多个任务是同时执行的,但是对于并发来讲这个过程只是不断交换的过程。怎么理解这两个过程,比如说我们在调节婆媳关系的时候,我们一定是跑到妈那里说媳妇好话,然后屁颠屁颠跑到媳妇那里说妈也是为了咱们好。跑来跑去这个过程就叫做并发,因为对于这个整体而言你和妈沟通好了,你也和媳妇沟通好了,通过不断地交替完成了一个结果。那什么是并行呢?你不太会说话,你就想出来把村长叫来,村长和你妈沟通,你和你媳妇沟通最后结果还是和解婆媳关系。这就叫做并发。
那么在pc中怎么理解,如果pc是单核的那就谈不上并行,因为没有村长。只能靠自己和解。那如果pc是多核那就谈得上并行,可以叫上村长,如果更多核可以连村长媳妇都叫来都没问题。
如果把村长媳妇叫来,那可能存在隐患,比如你看上人家村长媳妇了,矛盾更大了,最后体现关系缓和不了,这就叫做死锁。因为你看上村长媳妇村长看上你媳妇。但是由于道德约束和法律约束,不能互换。但是喜欢就是喜欢永不放弃,这就产生了死锁。
回归我们说的为什么要异步,放入pc中看,多核可以并行那就省去了你的不少事情,就相当于因为把一半的事情都交给村长了。所以效率会更好。计算机中也一样多个线程计算效率会更高。所以提高运算效率就是异步的,目的。
首先我们作为在Android概念区别的的角度而言,Android中核心的可以划分成
- 主线程
- Binder线程
- 后台线程
当然如果您要说,主线程Binder线程等在Linux上都是启动一个线程那您理解的虽然正确,但是没有在笔者说的这个角度出发看。
需要明确的是,我们经常说的ActivityThread是主线程,这句话不准确。ActivityThread并没有继承Thread类,他只是负责应用进程中一些核心的操作,所以他严格意义上不是进程。Zygote把进程fork()出来之后,得做一些Android应用层面的初始化工作,在这个过程中会启动一套Handler机制我们将这个称之为主线程,其中的MessageQueue称之为主消息队列。其源码为:
SystemServer.run()
private void run() {
...
Looper.prepareMainLooper();//主线程looper
//加载android_servers.so库在frameworks/base/services/目录
System.loadLibrary("android_servers");
...
createSystemContext(); //初始化系统上下文
//创建系统服务管理
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
try {
startBootstrapServices(); // 引导服务
startCoreServices(); // 核心服务
startOtherServices(); // 其他服务
} catch (Throwable ex) {
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
//一直loop
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
这也就是我们其实在最开始的线程里面启动了一套Handler机制。只不过谷歌把UI操作都让这个loop处理。所以我们贴切的称之为主线程。
Binder线程是进行Binder机制通信的线程,也就是Android中的跨进程通信。
Binder线程如果我们是应用开发者很难感知的到Binder线程的存在,因为他是在native层创建的,我们看下源码,这部分其实作为了解,深入也没有太大意义,有兴趣的同学可以跟随笔者角度。没兴趣的忽略binder线程继续向下看哈。
还在Zygote中,当应用层需要启动一个进程时候(调用Process.start()方法)向Zygote发送socket消息,最后执行到app_main.cpp中的onZygoteInit。
app_main.cpp中的onZygoteInit()
virtual void onZygoteInit() {
sp proc = ProcessState::self();
//启动新binder线程
proc->startThreadPool();
}
继续看看如何启动线程池
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock); //Linux中多线程同步,俗称加锁
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
追踪spawnPooledThread方法
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
//获取Binder线程名,此时命名规则Binder:_x
String8 name = makeBinderThreadName();
//isMain=true
sp t = new PoolThread(isMain);
t->run(name.string());
}
}
这个时候mIsMain=true,通过名称判断joinThreadPool加入线程池
class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop() {
IPCThreadState::self()->joinThreadPool(mIsMain);//此时true
return false;
}
const bool mIsMain;
};
void IPCThreadState::joinThreadPool(bool isMain)
{
//创建Binder线程(isMain代表主线程信号)
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
set_sched_policy(mMyThreadId, SP_FOREGROUND); //设置前台调度策略
status_t result;
do {
processPendingDerefs(); //清除队列的引用
result = getAndExecuteCommand(); //处理与Binder交互和binder响应的操作
...
} while (result != -ECONNREFUSED && result != -EBADF);
mOut.writeInt32(BC_EXIT_LOOPER); // 线程退出循环
...
}
也就是在getAndExecuteCommand()这个过程会和Linux底层打交道将BC_ENTER_LOOPER交给底层识别
我们在代码里面new Thread()这个就叫做后台进程
我们这里并没有继承关系,或者组合关系等,我们只是说常见的一些用到的类,后面我们说这些类分别有什么作用
Thread
针对Thread我们都知道继承实现run方法,或者把一个Runnable接口给Thread。
class MyThread extends Thread{
@Override
public void run() {
}
}
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
}
});
我们还知道只要不调用Thread的start()方法,就没有开启一个线程,Thread就相当于还是一个普通类。
HandlerThread
HandlerThread是一个集成了Looper,MessageQueue的线程。在其run方法中会调用Looper.prepare()方法,我们看代码吧。
HandlerThread.java
//Call back method that can be explicitly overridden if needed to execute some setup before Looper loops.
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();//启动一套Handler机制
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);//设置线程策略
onLooperPrepared();
Looper.loop();
mTid = -1;
}
很显然我们如果需要做一些事情就放入onLooperPrepared()方法中
AsyncQueryHandler
对于这个,构造中创建了一个HandlerThread自己内部实现了一个Handler叫做WorkerHandler类,这个类封装了对ContentProvider的一些操作。原理一样,大概浏览下代码
HandlerThread.java
public AsyncQueryHandler(ContentResolver cr) {
super();
mResolver = new WeakReference(cr);
synchronized (AsyncQueryHandler.class) {
if (sLooper == null) {
HandlerThread thread = new HandlerThread("AsyncQueryWorker");//是的吧
thread.start();
sLooper = thread.getLooper();
}
}
mWorkerThreadHandler = createHandler(sLooper);
}
protected Handler createHandler(Looper looper) {
return new WorkerHandler(looper);
}
Excutor
public interface Executor {
void execute(Runnable command);
}
这个只是一个接口。后面和AsyncTask结合那就发挥更大的作用了
IntentService.java
在内部实现了HandlerThread自己实现了Handler叫做ServiceHandler做处理
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
做的处理是:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);//是个abstract方法
stopSelf(msg.arg1);
}
}
原理一样,都是HandlerThread的应用。
就是利用我们上面说的那些进行异步,只不过我要单独提出来Handler机制和AsyncTask,后面我会专门详解,掌握了这两个基石很多困惑会迎刃而解。