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不会阻塞前台线程,程序界面就不会失去响应。


参考:http://wear.techbrood.com/reference/android/app/Service.html

时间: 2024-10-07 11:12:16

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

Android学习笔记二十五之ListView多布局实现

Android学习笔记二十五之ListView多布局实现 这一节是介绍ListView这个控件的最后一节,实现一个Item的多布局.像我们经常在用的各种即时通讯工具,QQ.微信等,假设他们的会话界面是ListView实现的,那么ListView就有多种Item布局,这一节,我们就来实现一个ListView的多种Item. 要实现ListView里面有多种Item,就要重写适配器的两个方法getViewTypeCount()和getItemViewType(int position),第一个方法是

Android学习笔记二十四.Service入门(二)绑定本地Service并与之通信

绑定本地Service并与之通信    通过上一篇博文的前3步,我们就算完成了一个Service及使用该Service的应用程序(Service为该应用程序的组成部分).但当程序通过startService()和stopService()启动.关闭Service时,Service与访问者之间基本上不存在太多的关联,因此Service和访问者之间也无法进行通信.数据交换.如果我们希望开发的Service能与访问者之间实现方法调用或数据交换,我们可以让访问者使用bindService()和unbin

Android学习笔记二十九之SwipeRefreshLayout、RecyclerView和CardView

Android学习笔记二十九之SwipeRefreshLayout.RecyclerView和CardView 前面我们介绍了AlertDialog和几个常用的Dialog,ProgressDialog进度条提示框.DatePickerDialog日期选择对话框和TimePickerDialog时间选择对话框.这一节我们介绍几个新的API控件SwipeRefreshLayout.RecyclerView和CardView,这几个API控件都是google在Android5.0推出的.下面我们来学

Android学习笔记二十之Toast吐司、Notification通知、PopupWindow弹出窗

Android学习笔记二十之Toast吐司.Notification通知.PopupWindow弹出窗 Toast吐司 Toast吐司是我们经常用到的一个控件,Toast是AndroidOS用来显示消息的一种机制,它与Dialog不同,Toast不会获取到焦点,通常显示一段时间之后就会自动消失,下面我们来介绍Toast的几种常用方式: 第一种,默认显示方式,也是最常用的方式: Toast.makeText(MainActivity.this, "这是默认的显示方式", Toast.LE

Android学习笔记二十四之ListView列表视图二

Android学习笔记二十四之ListView列表视图二 前面一篇我们介绍了常用的几种适配器的简单实现和ListView的简单使用,这一篇中,我们介绍一下ListView的优化和一些其它的问题. ListView优化方法一 在ListView中,我们最常用的就是自定义Adapter,在我们自定义Adapter中,需要实现两个比较重要的方法getCount()和getView(),前者是负责计算ListView的总Item数,后者是生成Item,有多少个Item就会调用getView()方法多少次

Android学习笔记(十五)——碎片的生命周期(附源码)

碎片的生命周期 点击下载源码 与活动类似,碎片具有自己的生命周期.理解了碎片的生命周期后,我们可以在碎片被销毁时正确地保存其实例,在碎片被重建时将其还原到前一个状态. 1.使用上一篇的项目Fragments,在Fragment1.java文件中添加如下代码: package net.zenail.Fragments; import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragm

马哥学习笔记二十五——ISCSI协议,架构及其安装配置

ISCSI监听在tcp/3260端口 iSCSI Target:iscsi-target-utils 客户端认正方式: 1.基于IP 2.基于用户,CHAP tgtadm:命令行工具,模式化命令 --mode 常用模式:target,logicalunit,account target --op new.delete.show.update.bind.unbind logicalunit --op new.delete account --op new.delete.bind.unbind --

angular学习笔记(二十五)-$http(3)-转换请求和响应格式

本篇主要讲解$http(config)的config中的tranformRequest项和transformResponse项 1. transformRequest: $http({ transformRequest: function(data){ //对前台发送的data进行处理 return data } }) 这个在测试的时候遇到了很大的问题.只要经过transformRequest函数处理,哪怕是不做任何处理,node后台都会报错,需要尝试使用php 2. transformResp

Android学习笔记二十六.跨进程调用Service(AIDL Service)

跨进程调用Service(AIDL Service) 一.AIDL Service 1.什么是AIDL Service? AIDL,即Android Interface Definition Language.是Android用于定义远程接口,AIDL接口定义语言的语法比较简单,这种接口定义语言并不是真正的编程语言,它只是定义两个进程之间的通信接口.AIDL的语法与Java接口很相似,但存在如下几点差异: (1)AIDL定义接口的源代码必须以.aidl结尾; (2)AIDL接口中用到数据类型,除