Android学习笔记二十五.Service组件入门(三)使用IntentService

使用IntentService
1.Service缺陷
    由于Service本身存在以下两个问题:
    (1)Service不会专门启动一条单独的进程,Service与他所在应用位于同一进程中;
    (2)Service也不是专门一条新的线程,如果我们在Service中直接处理耗时的任务,那么就会导致应用程序出现假性"卡死"。如果我们需要在Service处理耗时任务,也可以在Service的onCreate()方法中启动一条新线程来处理该耗时任务(如上例)。但是,问题来了,启动Service的Activity可能随时被用户退出,如果在子线程还没有结束的情况下,Activity已经被用户退出了,此时那些子线程所在的进程就变成了空进程(即没有任何活动组件的进程),系统需要内存时可能会优先终止该进程。如果宿主进程被终止,那么该进程内的所有子线程也会被终止,这样就可能导致子线程无法执行完成。
2.IntentService原理
    IntetnService是Service的子类,它不是普通的Service,通过IntentService恰好弥补了Service上述的两个不足。IntentService主要使用队列来管理请求Intent,每当客户端代码通过Intent请求启动IntentService时,IntentService会将该Intent加入队列中,然后开启一条新的worker线程来处理该Intent。对于异步的startService()请求,IntentService会按次序依次处理队列中的Intent,该线程保证同一时刻只处理一个Intent。由于IntentService使用新的worker线程处理Intent请求,因此IntentService不会阻塞主线程,所有IntentService自己就可以处理耗时任务了。
3.IntentService使用特征
(1)IntentService会创建单独的worker线程来处理所有的Intent请求;
(2)IntentService会创建单独的worker线程来处理onHandleIntent()方法实现的代码,因此开发者无需处理多线问题;
(3)当所有请求处理完成后,IntentService会自动停止,因此开发者无须调用StopSelf()方法来停止该Service。
(4)为Service的onBind()方法提供了默认实现,默认实现的onBind()方法返回null;
(5)为Service的onStartCommand()方法提供了默认实现,该实现会将请求Intent添加到队列中。
注释:扩展IntentService实现Service无须重写onBind()、onStartCommand()方法,只要重写onHandleIntent()方法即可
4.源码实战
实现:分别启动普通Service和IntentService,且同时处理耗时任务,对比两者效果。
技术分享
(1)\src\com\example\android_intentservice\ServiceAndIntentService.java
实现:通过两个按钮分别启动普通Service和IntentService
package com.example.android_intentservice;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class ServiceAndIntentService extends Activity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
 }
 //1.启动普通Service按钮方法
 public void startService(View source)
 {
  Intent intent = new Intent(this,MyService.class);	//创建需要启动的service的Intent
  startService(intent);	 //启动Intent指定的Service
 }
 //2.启动IntentService按钮方法
 public void startIntentService(View source)
 {
  Intent intent = new Intent(this,MyIntentService.class);
  startService(intent);
 }
}
(2)\res\layout\main.xml
实现:设置Button属性android:onClick,为按钮绑定响应方法
   
 ......
  <Button
      android:onClick="startService"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="启动普通Service" />
  <Button
          android:onClick="startIntentService"
          android:layout_width="186dp"
          android:layout_height="wrap_content"
          android:text="启动IntentService" />
(3)\src\com\example\android_intentservice\MyService.java
实现:实现一个普通Service执行耗时任务(20s),观察是否导致ANR异常(Application Not Responding)
package com.example.android_intentservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
 @Override
 public IBinder onBind(Intent intent) {
  return null;
 }
 //当启动Service,调用该方法执行相应代码
 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  long endTime = System.currentTimeMillis()+20*1000;
  System.out.println("onStart");
  while(System.currentTimeMillis()<endTime)
  {
   synchronized(this)
   {
    try
    {
     wait(endTime-System.currentTimeMillis());
    }catch(Exception e)
    {
    }
   }
  }
  System.out.println("---普通Service耗时任务执行完成---");
  return START_STICKY;
 }
 
}
(4)\src\com\example\android_intentservice\MyIntentService.java
实现:实现一个IntentService执行耗时任务(20s),观察是否导致ANR异常
package com.example.android_intentservice;
import android.app.IntentService;
import android.content.Intent;
public class MyIntentService extends IntentService {
 public MyIntentService() {
  super("MyIntentService");
 }
 //IntentService会使用单独的线程来执行方法的代码
 @Override
 protected void onHandleIntent(Intent intent) {
  //该方法内可以执行任何耗时任务,比如下载文件等,此处只是让线程暂停20s
  long endTime = System.currentTimeMillis()+20*1000;
  System.out.println("onStart");
  while(System.currentTimeMillis()<endTime)
  {
   synchronized(this)
   {
    try
    {
     wait(endTime-System.currentTimeMillis());
    }catch(Exception e)
    {
    }
   }
  }
  System.out.println("---IntentService耗时任务执行完成---");
 }
}


(5)AndroidManifest.xml
实现:在工程文件中为MyService、MyIntentService配置<service../>信息
  
  <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
          ..........
        </activity>
        <!--配置service-->
        <service android:name=".MyService"/>
        <service android:name=".MyIntentService"/>
    </application>

效果演示:
a.当点击"启动普通service"时的效果
技术分享技术分享

b.连续点击7次"启动IntentService"的效果
技术分享



升华笔记:
1.普通Service是在onStartCommand()方法内执行耗时任务;IntentService在onHandleIntent()方法内执行耗时任务;
2.普通Service在没有创建一个新线程的情况下,其执行耗时任务主要是在应用程序的主线程中完成的,由于普通Service的执行会阻塞主线程,因此启动该Service执行耗时任务会导致程序出现ANR异常;
3.IntentService主要使用队列来管理请求Intent,每当客户端代码通过Intent请求启动IntentService时,IntentService会将该Intent加入队列中,然后开启一条新的worker线程来处理该Intent。由于IntentService会使用单独的线程来完成该耗时任务,因此启动MyIntentService不会阻塞前台线程,程序界面就不会失去响应。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。