1、今天我们来分析Service中的一个小技巧:前台服务(Forground Service)
----------------------------------------------------------------------------------------------------------------------------------------
【问题】:我们都知道服务是运行在后台的,如果系统出现内存不足的情况,那么此时,系统就可能回收后代的服务,那么我们如何保证服务可以一直运行?
【解决】:在服务中,有一个前台服务的概念,调用startForground()方法。
我们看看官网对前台服务及startForeground()的描述:
看了官方的解释后,我们再来看看如何使用,上代码:
- public class MyService extends Service{
- ......
- @Override
- public void onCreate() {
- super.onCreate();
- Intent intent = new Intent(getBaseContext(), MainActivity.class);
- PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0 , intent, PendingIntent.FLAG_CANCEL_CURRENT);
- Notification no = new Notification.Builder(getBaseContext()) // 启动服务后,在前台添加一个Notification
- .setWhen(System.currentTimeMillis())
- .setSmallIcon(R.mipmap.ic_launcher)
- .setTicker("Create a front desk Service!")
- .setContentTitle("This is a front desk service")
- .setContentText("A service skill!!!")
- .setContentIntent(pi)
- .setAutoCancel(true)
- .setDefaults(Notification.DEFAULT_ALL)
- .build();
- startForeground(1, no);
- Log.d(TAG, "onCreate executed");
- }
- }
我们再看一下官方文档:
以上的代码是在Service的创建中添加了一个Notification,调用startForground()就可以保证:只要服务一直存在,那么在前台就会一直显示这个Notification。
如果我们在onDestroy()中调用stopForground()方法,会销毁这个Notification,但是Service还是存活的,此时Service就会面临被System干掉的风险。
如果直接STOP SERVICE,那么Notification和Service都会销毁。
----------------------------------------------------------------------------------------------------------------------------------------
2、接下来,我们再来看一个Service的另外一个小技巧:IntentService
【问题】:我们知道服务的代码逻辑是在主线程中执行的,如果我们在主线程中需要执行一些耗时的操作,那么很有可能出现ANR(程序暂无响应)的状况。
这个时候,我们可以采用Android的多线程编程(小编在之前的 AsyncTask 贴中讲解过多线程,可以回顾)的方式,我们来看一段代码:
- public class MyService extends Service{
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- // 处理具体的逻辑 // 开启一个线程处理耗时操作
- }
- }).start();
- return super.onStartCommand(intent, flags, startId);
- }
- }
现在,服务可以启动起来了,但是如果不调用StopService()或stopSelf()方法,服务会一直运行,现在我们修改一下代码:
- public class MyService extends Service{
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- // 处理具体的逻辑 // 开启一个线程处理耗时操作
- stopSelf(); // 让服务执行完逻辑后自行停止
- }
- }).start();
- return super.onStartCommand(intent, flags, startId);
- }
- }
上面的代码就是一个标准的Service的书写形式,主要包含两个知识点:Thread子线程的创建和stopSelf()方法的调用。
其实,在一般的使用过程中,一部分程序员很容易忘记以上两个要点,存在遗忘,那么有没有更好的办法能够实现上面两个需求呢?
【解决】:在Android中,专门提供了一个IntentService类(android.app.IntentService),这个类就能很好的满足我们的需求!我们直接通过代码来看:
(1)新建一个MyIntentService类继承自IntentService,代码:
- public class MyIntentService extends IntentService{
- public MyIntentService() {
- super("MyIntentService");
- }
- @Override
- protected void onHandleIntent(Intent intent) {
- Log.d("MyIntentService", "MyIntentServiceThread id is " + Thread.currentThread().getId());
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.d("MyIntentService", "onDestroy executed");
- }
- }
以上代码做了几件事:
1、提供了一个无参的构造方法,并且调用了父类的有参构造函数(这个就不需要我说为什么了吧);
2、子类实现父类的onHandleIntent()抽象方法,这个方法好就好在,它是一个已经运行在子线程中的方法。也就是说,服务调用了它,那么执行的逻辑就如同Thread子线程。
onHandleIntent = Thread().start() + stopSelf()
3、onHandleIntent()执行完后会销毁服务?会selfStop()?接着往下看代码。
----------------------------------------------------------------------------------------------------------------------------------------
(2)在xml文件中,创建一个MyIntentService服务按钮:
- <Button
- android:id="@+id/start_intent_service"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/intent_service"/>
(3)接下来,修改MainActivity中的代码:
- public class MainActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- Button startIntentService = (Button) super.findViewById(R.id.start_intent_service);
- startIntentService.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Log.d("MyIntentService", "MainActivity Thread id is " + Thread.currentThread().getId()); // 查看主线程的id
- Intent intentService = new Intent(getBaseContext(), MyIntentService.class);
- startService(intentService);
- }
- });
- }
- }
(4)最后,在AndroidMainfest中注册服务:
- <service android:name=".MyIntentService" />
【结果】:直接看一下代码执行的效果。
从打出的LOG可以看出:
(1)MyIntentService和MainActivity所在进程的id是不一样的;
(2)onHandleIntent()方法在执行完逻辑后确实销毁了服务,效果等同于stopSelf()。
从上面的分析可以看出onHandleIntent()方法确实相当的好用!
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。