1 IntentService
1.1 为什么需要IntentService
我们遇到耗时的操作会交给Service去做,比如:我们上传多张图,上传的过程用户可能将应用置于后台,然后干别的去了,Activity就很可能会被杀死,所以可以将上传操作交给Service去做;如果担心Service被杀,通过设置startForeground(int, Notification)方法提升其优先级。
那么,在Service里面肯定不能直接进行耗时操作,都需要去开启子线程来完成耗时操作,自己去管理Service的生命周期以及子线程并非是个优雅的做法。
而官方给我们提供了IntentService,它是继承于Service并处理异步耗时请求的一个类。
1.2 作用?(或IntentService与Service的区别)
(1)可以通过startService(Intent)方式来提交请求,和启动传统Service一样;
(2)该Service会在需要的时候创建;
(3)当完成所有的任务以后会自动关闭;
(4)可以启动多次,而每一个耗时操作会以工作队列的方式在onHandleIntent()中执行,每次只会执行一个工作线程;
(5)解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题。
1.2 本质与原理
(1)本质是:Service+HandlerThread+Intent。在我的另一篇博客:拥有Looper的线程–HandlerThread
(2)实现原理:onStartCommand中回调了onStart,onStart中通过mServiceHandler发送消息到该handler的handleMessage中去。最后handleMessage中回调onHandleIntent(intent),并且执行stopSelf()关闭服务。
1.3 优点
(1)不需要自己去新建线程,不需要考虑在什么时候关闭该Service;
(2)提高子线程的优先级;
(3)减轻主线程的压力。
2 IntentService使用例子
(1)MainApplication.java
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 启动服务执行耗时操作
InitializeService.start(this);
}
}
(2)InitializeService.java
/**
* 启动初始化Service
*/
public class InitializeService extends IntentService {
// IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
public static final String ACTION_INIT_WHEN_APP_CREATE = "com.guesslive.caixiangji.service.action.app.create";
public static final String EXTRA_PARAM = "com.guesslive.caixiangji.service.extra.PARAM";
/**
* 至少要有一个空的构造方法
*/
public InitializeService() {
super("InitializeService");
}
/**
* 启动调用
* @param context
*/
public static void start(Context context) {
Intent intent = new Intent(context, InitializeService.class);
intent.setAction(ACTION_INIT_WHEN_APP_CREATE);
context.startService(intent);
}
/**
* UI线程发送Intent后执行
* 子线程中执行(主要执行的方法)
*/
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_INIT_WHEN_APP_CREATE.equals(action)) {
performInit(EXTRA_PARAM);
}
}
}
/**
* UI线程中执行
*/
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
/**
* 启动初始化操作
*/
private void performInit(String param) {
initImageLoader();//初始化图片加载控件
initRealm();//初始化Realm数据库
initUser();//初始化用户(Realm数据库)
initPush();//初始化推送
initTuSdk();//初始化图sdk
initQiNiu();//初始化七牛
initQiyu();//网易七鱼
initLogger();//注释启动,打开屏蔽打印
}
}
3 IntentService源码解析
3.1 源码
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@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(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
protected abstract void onHandleIntent(Intent intent);
}
3.2 解析
(1)原理:就是每次调用onStartCommand的时候,onStartCommand中回调了onStart,onStart中通过mServiceHandler发送消息到该handler的handleMessage中去,消息包含我们的intent。然后在该mServiceHandler的handleMessage中去回调onHandleIntent(intent)。
(2)注意下:回调完成后回调用 stopSelf(msg.arg1),注意这个msg.arg1是个int值,相当于一个请求的唯一标识。每发送一个请求,会生成一个唯一的标识,然后将请求放入队列,当全部执行完成(最后一个请求也就相当于getLastStartId == startId),或者当前发送的标识是最近发出的那一个(getLastStartId == startId),则会销毁我们的Service。
(3)如果传入的是-1则直接销毁。当任务完成销毁Service回调onDestory,可以看到在onDestroy中释放了我们的Looper:mServiceLooper.quit()。
4 CursorLoader
4.1 问题:Activity中启动子线程
(1)内存泄露
(2)无效的更新UI
Loader保证子线程与Activity或者Fragment的生命周期一致
Activity和Fragment自带LoaderManager
4.2 优点
(1)方便
(2)Activity或者Fragment的生命周期一致
(3)数据缓存与更新通知
4.3 例子(也可以模仿写一个网络加载器)
/**
* 使用加载器加载通话记录
*/
public class MainActivity extends Activity {
private static final String TAG = "jason";
// 查询指定的条目
private static final String[] CALLLOG_PROJECTION = new String[] { CallLog.Calls._ID, CallLog.Calls.NUMBER,
CallLog.Calls.CACHED_NAME, CallLog.Calls.TYPE, CallLog.Calls.DATE };
private ListView mListView;
private MyLoaderCallback mLoaderCallback = new MyLoaderCallback();
private MyCursorAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.lv_list);
mAdapter = new MyCursorAdapter(MainActivity.this, null);
mListView.setAdapter(mAdapter);
//执行Loader的回调
getLoaderManager().initLoader(0, null, mLoaderCallback);
}
private class MyLoaderCallback implements LoaderManager.LoaderCallbacks<Cursor> {
//创建Loader
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
//加载的过程在子线程中进行
CursorLoader loader = new CursorLoader(MainActivity.this, CallLog.Calls.CONTENT_URI, CALLLOG_PROJECTION,
null, null, CallLog.Calls.DEFAULT_SORT_ORDER);
Log.d(TAG, "onCreateLoader");
return loader;
}
//Loader检测底层数据,当检测到改变时,自动执行新的载入获取最新数据
//Activity/Fragment所需要做的就是初始化Loader,并且对任何反馈回来的数据进行响应。
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if (data == null)
return;
mAdapter.swapCursor(data);
Log.d(TAG, "onLoadFinished data count = " + data.getCount());
}
//OnDestroy,自动停止load
@Override
public void onLoaderReset(Loader<Cursor> loader) {
Log.d(TAG, "onLoaderReset");
mAdapter.swapCursor(null);
}
}
}