Android之IntentService使用
文章链接:http://blog.csdn.net/qq_16628781/article/details/67110657
知识点:
- IntentService简介;
- Thread/Runnable/service开启线程;
- IntentService使用;
- IntentService源码简析和使用场景;
- 新名词记录{onHandleIntent();START_REDELIVER_INTENT;START_NOT_STICKY;消息队列:Looper,Handler等;}
概述
说到线程,大家一定是想到利Thread和Runnable了,因为他们使我们新开线程最常用到的方式了。但是实话实话,线程如果理解不透彻,是很难进行管理的。万一没弄好,那么就有可能造成问题。
同样,我们也可以在service进行耗时操作,但是但是,在service里面还是需要进行新开线程来操作的。在onStartCommand()方法里面进行新开线程。
但是有木有一种更加简单的办法进行耗时操作呢,不需要我们去new一条子线程,也不需要去管理子线程。答案是肯定的。
Android中给我们封装了service成IntentService给我们直接使用,它的好处有两点:1、不用我们手动去new一个子线程;2、不用我们去管理子线程,当任务执行完之后,IntentService会自动停止线程。
通用new新线程方式1
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//开启线程做耗时操作
}
});
thread.start();
通用new新线程方式2
在service的onStartCommand()方法中操作
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 此处进行耗时的操作
}
}).start();
return START_STICKY;
}
IntentService执行耗时操作
IntentServiceImpl继承IntentService,并实现一个需要传入工作线程名字的构造函数和onHandleIntent(Intent intent)方法。
我们具体来说下onHandleIntent(Intent intent)方法:此方法是用来实现耗时操作的回调,你可以在这里进行访问网络,io读存和其它耗时操作。参数Intent就是你调用startService(intent)里面传入的原始的intent。我在下面分别传入了3个参数,模拟进行3中不同的操作,只是让线程停止4秒钟,模拟耗时操作。然后我们就可以利用广播进行数据传递,或者将下载的内容放入本地sdcard等等。
/**
* desc:
* <p>
* author:kuyu.yaojt (tanksu)
* <p>
* email:yaojt@kuyumall.com
* <p>
* blog:http://blog.csdn.net/qq_16628781
* <p>
* date:17/3/27
*/
public class IntentServiceImpl extends IntentService {
/**
*
*/
public IntentServiceImpl() {
super("intentServiceImpl");
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentServiceImpl(String name, Handler handler) {
//传入名字,标记工作线程,主要是为了调试用。
super(name);
this.mHandler = handler;
}
private Handler mHandler;
@Override
protected void onHandleIntent(Intent intent) {
//根据Intent的不同进行不同的事务处理
System.out.println("onHandleIntent----->");
String id = intent.getExtras().getString("requestid");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String resule = "";
switch (id) {
case "t1":
resule = "结束t1工作";
break;
case "t2":
resule = "结束t2工作";
break;
case "t3":
resule = "结束t3工作";
break;
}
}
接下来是如何启动。
public void initView() {
Intent intent = new Intent(this, IntentServiceImpl.class);
intent.putExtra("requestid", "t1");
startService(intent);
Intent intent2 = new Intent(this, IntentServiceImpl.class);
intent.putExtra("requestid", "t2");
startService(intent);
Intent intent3 = new Intent(this, IntentServiceImpl.class);
intent.putExtra("requestid", "t3");
startService(intent);
}
上面代码,我们一共启动了3次,执行3个耗时的操作,但是在onHandleIntent()方法里面,并不会一起执行全部的请求,而是一个一个顺序执行,这一点尤其需要注意。
因为IntentService是继承自Service,所以也是需要在manifest文件中声明的。
<service android:name=".sdk.java.network.IntentServiceImpl">
<intent-filter>
<action android:name="con.yaojt.intentservice" />
</intent-filter>
</service>
以上就是IntentService的使用方法。下面我们将去看看他的源码,源码其实不多,大概浏览下它是怎么实现的,还有就是有神马用处?
下面的类就是IntentService的实现类,下面总的说几点(从上往下):
1. IntentService新开的线程都有自己的消息队列;
2. 在消息队列最后会回调onHandleIntent()方法;
3. 构造方法传入的name是用来区分线程和调试作用,不重要;
4. onCreate()中会为此线程得到消息队列,并构建处理的handler;
5. onStartCommand()不推荐重写。除非你需要像是向后台轮询的操作,就需要重写(详见方法中的解释);
6. 一次处理一个请求,之后挂起实例内的其它请求;
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); //设置looper
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent) msg.obj); //回调onHandleIntent()方法给用户自行处理
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name; //名字只是来标记此线程,调试用
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");//根据传入的name,创建一个线程
thread.start();//这个方法还是需要调用的
mServiceLooper = thread.getLooper(); //得到此线程的一个looper,让他来循环此线程
mServiceHandler = new ServiceHandler(mServiceLooper); //得到一个处理intent的handler
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
//这个方法系统是不推荐重写的。但是要重写onHandleIntent()抽象方法,因为系统拿到一个请求之后,就会调用此方法
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId); //这里会给实现的ServiceHandler发送一个消息,然后在handleMessage()里面进行调用onHandleIntent()方法
//START_REDELIVER_INTENT:当服务开始后,被系统杀掉了,就会重新启动,并且将最后的一个intent重新分发给onStartCommand()方法
//除非用户掉用了stopself()方法,否则会一直重新分发最后一个intent。如果传入的是一个null的intent,那么将不会调用此方法。
//START_NOT_STICKY:当服务没杀掉之后,不会重新启动,也不会传递intent,除非再次调用startService()方法。
//我们这里可以做一个向后台轮询数据的工作,在我们启动intentservice之后,如果onStartCommand()返回这个类型,
//那么这儿服务不会再启动,这样就可以避免内存不足时,我们的线程被杀掉。然后我们又可以在onStartCommand()里头,
//设置一个"闹钟"在多少分钟之后,再次调用
//startService()启动此服务,然后在onStartCommand()做一个询问后台的网络请求,因为此服务仅此一次,所以不担心被杀掉
//如此反复,那么就是一个完整的轮询工作流程了
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit(); //停止线程的消息轮询
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null; //在你需要为你的服务进行绑定的时候,才需要返回IBinder对象
}
//工作线程中有了请求之后,就会调用。一次只会异步处理一个intent请求,在此对象中需要启动的其它请求只能等待,
//而不会挂起其它IntentService的对象。当所有的请求都处理完之后,它会自动的停止自身。而不用手动去调用stopSelf()方法
//startService(Intent)启动IntentService
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
总结
IntentService是一个很好用的类,比如我们需要向后台传输n张图片,就可以使用这一个类,开启执行之后哦,我们就可以不用管它,等完成之后,会自己杀掉自己。省去了很多的操作步骤。
onStartCommand()的返回参数也是有很多的作用,SDK中说的就是用来向后台进行轮询操作。START_REDELIVER_INTENT和START_NOT_STICKY的作用需要好好理解才能够更好的使用此类。
如有任何问题,请及时与我联系。谢谢。