Anroid异步处理

Anroid异步处理

移动开发要求我们正确处理好主线程和子线程之间的关系,耗时操作放到子线程中

而异步处理技术是提高应用性能,解决主线程和子线程之间通信的关键

异步处理技术很多种,下图为完整的继承树

异步

可以看到Thread是异步处理技术的基础

创建现场有两种方法,一种继承Thread并重写run方法

一种实现Runnable

一般来讲Android应用层都基于liunx的pthreads

应用层可以分为三种类型的线程

  1. 主线程,即UI线程,若是在其他线程中更新UI,则会报错,抛出CalledFromWrongThreadException
  2. Binder线程,这个线程用于不同进程之间线程的通信,每个进程都维护了一个线程池,用来处理其他进程中线程发送的消息,进程包括系统服务,Intents,ContentProviders和Service;典型应用场景是应用提供一个给其他进程通过AIDL接口绑定的Service
  3. 后台进程

HandlerThread

HandlerThread是一个集成了Looper和MessageQueue的线程,当启动他时会自动生成Looper和MessageQueue,然后等待消息进行处理

run方法源码

@override
public void run(){
  mTid=Process.myTid();
  Looper.prepare();
  synchronized(this){
    mLooper=Looper.myLooper();
    notifyAll();
  }
  Process.setThreadPriority(mPriority);
  onLooperPrepared();
  Looper.loop();
  mTid=-1;
}

HandlerThread中只有一个消息队列,队列中的消息是顺序执行的,因此是线程安全的,吞吐量会收到一定的影响,队列中的任务可能会被前面未执行完的任务阻塞。

HandlerThread的内部机制确保了在创建Looper和发送消息之间不存在竞争关系,这个是通过HandlerThread.getLooper()实现为一个阻塞操作实现的。

AsyncQueryHandler

这是用于ContentProvider上面执行异步的CRUD操作的工具类,CRUD操作会被放到一个单独的子线程中执行,当操作结束获取到消息后,将通过消息的方式传递给调用AsyncQueryHandler的线程,也就是主线程

AsyncQueryHandler是一个抽象类,继承自Handler,通过封装ContentResolver、HandlerThread、Handler等实现对ContentProvider的异步操作

IntentService

由于Service的各个生命周期函数是运行在主线程的,本身不带异步处理技术

Android引入了IntentService,IntentService是Service的子类,具有一样的生命周期,不过它提供了在后台线程中处理异步任务的机制

它是在后台线程中顺序执行所有任务,通过给Context.startService传递一个Intent类型的参数可以启动IntentService的异步执行,如果此时IntentService正在运行中,那个这么新的Intent将会进入消息队列中进行排队等待前面任务的执行完成后才能执行,若此时没有IntentService在运行,那将会启动一个新的IntentService。

当后台线程队列中所有任务均被处理完后,IntentService将会结束它的生命周期,因此我们不需手动结束IntentService

Executor Framework

它为我们提供了这些功能

  1. 创建工作线程池,同时通过队列来控制能够在这些线程执行的任务的个数
  2. 检测导致线程意外终止的错误
  3. 等待线程执行完成并获取执行结果
  4. 批量执行线程,并通过固定的顺序获取执行结果
  5. 在合适的时机启动后台线程,从而保证线程执行结果可以很快反馈给用户

AsyncTask

AsyncTask是在Executor框架基础上进行的封装,实现将耗时任务移动到工作线程中执行即doInBackground方法,同时提供方便的接口实现工作线程和主线程的通信如onPostExecute方法与onProgressUpdate方法

若是异步处理,则最大核心线程数为系统CPU核数+1,这是由AsyncTask中的ThreadPoolExecutor指定的

Loader

Loader是Android3.0开始引入的一个异步数据加载框架,使得Activity或Fragment异步加载数据变得很简单,并且当数据源发生变化时,他能够及时发出消息通知

它所涉及的api:

  1. Loader:加载器框架的基类,当一个加载器被激活后,他就会开始监视数据源并在数据发生变化时发送新的结果

  2. AsyncTaskLoader:Loader的子类,是基于AsyncTask实现的异步数据加载类,是一个抽象类,其子类必须实现loadInBackground,在其中进行具体数据加载操作

  3. CursorLoader:AsyncTaskLoader的子类,封装了对ContentResolver的query操作,实现从ContentProvider中查询数据的功能

  4. LoaderManager:抽象类,Activity和Fragment默认会关联一个LoaderManager的对象,我们只需要通过getLoaderManager即可获取,LoaderManager是用来管理一个或多个加载其对象的

  5. LoaderManager.LoaderCallbacks:LoaderManager的回调接口,主要有三个方法

    ① onCreateLoader():初始化并返回一个新的Loader实例

    ② onLoadFinished():当一个加载器完成加载过程之后会回调这个方法

    ③ onLoaderReset():当一个加载器被重置并且数据无效时会回调这个方法

例子

package com.example.load;

import android.app.ListActivity;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.SimpleCursorAdapter;

/**
 * Created by 王小俊 on 2017/5/9.
 */

public class ContactActivity extends ListActivity
        implements LoaderManager.LoaderCallbacks<Cursor>{

    private static final int CONTACT_NAME_LOADER_ID=0;

    static final String[] CONTACTS_SUMMARY_PROJECTION =new String[]{
            ContactsContract.Contacts._ID,ContactsContract.Contacts.DISPLAY_NAME
    };

    SimpleCursorAdapter mAdapter;

    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        initAdapter();
        getLoaderManager().initLoader(CONTACT_NAME_LOADER_ID,null,this);
    }

    private void initAdapter(){
        mAdapter = new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_1, null,
                new String[]{ContactsContract.Contacts.DISPLAY_NAME},
                new int[]{android.R.id.text1}, 0);
        setListAdapter(mAdapter);

    }


    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {


        return new CursorLoader(this, ContactsContract.Contacts.CONTENT_URI,
                CONTACTS_SUMMARY_PROJECTION, null, null,
                ContactsContract.Contacts.DISPLAY_NAME + "ASC");
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        mAdapter.swapCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mAdapter.swapCursor(null);
    }
}

小结

在具体使用需考虑以下因素

  1. 尽量使用更少的系统资源,例如CPU和内存
  2. 为应用提供更好的性能和相应度
  3. 实现和使用不复杂
  4. 写出的代码是否符合好的设计,是否易于理解和维护

ps:以上内容大部分为android高级进阶内的内容

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦