Android笔记系列--Service详解1 基本概念

分类

前台服务是在做了上述工作之后需要调用 startForeground ( android 2.0 及其以后版本 )或 setForeground (android 2.0 以前的版本)使服务成?为 前台服务。
使用 android:process 属性指定运行在别的进程,但注意新进程会重新创建一个Application对象,如果在Application中执行大量的初始化数据要进行判断是否是主进程。
 
解决方案:
public static String getProcessName(Context cxt, int pid) {  
    ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);  
    List<RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();  
    if (runningApps == null) {  
        return null;  
    }  
    for (RunningAppProcessInfo procInfo : runningApps) {  
        if (procInfo.pid == pid) {  
            return procInfo.processName;  
        }  
    }  
    return null;  
}  
在 Application 的 onCreate 中获取进程名称并进行相应的判断,例如?:
String processName = getProcessName(this, android.os.Process.myPid());
if (!TextUtils.isEmpty(processName) 
        && processName.equals(this.getPackageName())) {//判断进程名,保证只有主进程运行
  //主进程初始化逻辑
  ....
}

生命周期

官方给出的两种服务(非绑定 Service 和被绑定 Service)的生命周期图:

1). 被启动的服务的生命周期:如果一个Service被某个Activity 调用 Context.startService 方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行。如果一个Service被startService 方法多次启动,那么onCreate方法只会调用一次,onStart将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用)。该Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务。
 
2). 被绑定的服务的生命周期:如果一个Service被某个Activity 调用 Context.bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStart方法始终不会被调用。当连接建立之后,Service将会一直运行,除非调用Context.unbindService 断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时?候),系统将会自动停止Service,对应onDestroy将被调用。
 
3). 被启动又被绑定的服务的生命周期:如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStart便会调用多少次。调用unbindService将不会停止Service,而必须调用 stopService 或 Service的 stopSelf 来停止服务。
 
4). 当服务被停止时清除服务:当一个Service被终止(1、调用stopService;2、调用stopSelf;3、不再有绑定的连接(没有?被启动))时,onDestroy方法将会被调用,在这里你应当做一些清除工作,如停止在Service中创建并运行的线程。
 
特别注意:
1、你应当知道在调用 bindService 绑定到Service的时候,你就应?当保证在某处调用 unbindService 解除绑定(尽管 Activity 被 finish 的时候?绑定会自动解除,并且Service会自动停止);
 
2、你应当注意 使用 startService 启动服务之后,一定要使用 stopService停止服务,不管你是否使用bindService; 
 
3、同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止;
 
4、当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的?生命周期与上述相同。
 
5、在 sdk 2.0 及其以后的版本中,对应的 onStart 已经改为了 onStartCommand,不过之前的 onStart 仍然有效。这意味着,如果你开发的应用程序用的 sdk 为 2.0 及其以后的版本,那么你应当使用 onStartCommand 而不是 onStart。

几个需要注意的地方
1)   如果 Service 自己没有生成新的线程,那它也是运行在应用的主线程里的,因此 Service 本身并不能提高应用的响应速度和其他的性能,而是说通过这个后台服务生成新的线程来处理比较耗时的操作如大数据的读取等来提高响应, Service 自己并不能保证这一点。 Service 相当于提供了一个这些费时操作的平台,由它在后台创建新线程完成这些任务,以及视各种情况管理这些线程,包括销毁。
 
2)   stopService 和 unbindService 都可以把 Service 停掉,但是如果希望明确立刻停掉 Service ,则使用 stopService 更安全,因为 unbindService 实质上是将与 Service 的连接数减一,当减为 0 的时候才会销毁该服务实例, stopService 的效果相当于将连接数立即减为 0 ,从而关闭该服务,所以在选择关闭方式上要视不同情况而定。


启动方式


Service 的启动方式有两种,下面来分析一下这两种的区别:
(1)通过 startService 启动
这种方式启动的服务跟启动它的Activity是没有交互的,即?使启动它的Activity被destory了,该服务还可以继续运行。那什么时候销毁呢调用stopServive或该服务所在进程被销毁了,这个服务才可能销毁。
 
(2)通过 bindService 启动
这种方式启动的服务跟启动它的Activity是可以交互的,依靠的是Binder进程间通讯机制,启动它的Activity可以通过binder对?象调用Service的一些方法,这个并不是直接调用Service内部的?方法,只是先得到一个映射,再通过映射找Service内部的方法。因为这种方式启动的Service跟启动它的Activity 进行了绑定,所以它会受到Activity的生命周期的影响,在Activity销毁的时候,绑定的Service也会销毁。注意Activity 销毁的时候记得解除绑定,不然会报错。
错误信息如下:
E/ActivityThread: Activity com.example.servertest.MainActivity has leaked ServiceConnection com.example.servertest.MainActivity$1@b0ff6638 that was originally bound here

可以看出MainActivity可以正常的回调onDestroy方法,MyService也能回调onDestroy方法,但是会报错。

注意:
(1)无论使用那种方式启动的Service,Service 都会执行一次完整的逻辑,它不能被stopService调用强制停止当前进行的操作。
(2)Service 跟线程没有什么必然的联系,不要混淆。
(3)Service 默认是跟Activity在同一个进程里(主线程),所以?在Service里执行耗时的操作需要另开新线程,避免ANR。
 
在什么情况下使用 startService 或 bindService 或 同时使用startService 和 bindService?
如果你只是想要启动一个后台服务长期进行某项任务那么使用 startService 便可以了。如果你想要与正在运行的 Service 取得联系,那么有两种方法,一种是使用 broadcast ,另外是使用 bindService ,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且 BroadcastReceiver 本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择使用 bindService(这个时候你便同时在使用 startService 和 bindService 了,这在 Activity 中更新 Service 的某些运行状态是相当有用的)。另外如果你的服务只是公开一个远程接口,供连接上的客服端(android 的 Service 是C/S架构)远程调用执行方法。这个时候你可以不让服务一开始就运行,而只用 bindService ,这样在第一次 bindService 的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是Remote Service,那么该效果会越明显(当然在 Service 创建的时候会花去一定时间,你应当注意到这点)。

销毁

在Service的基本用法这一部分,我们介绍了销毁Service最简单的一种情况,点击Start Service按钮启动Service,再点击Stop Service按钮停止Service,这样MyService就被销毁了,可以看到打印日志如下所示:

    
那么如果我们是点击的Bind Service按钮呢?由于在绑定Service的时候指定的标志位是BIND_AUTO_CREATE,说明点击Bind Service按钮的时候Service也会被创建,这时应该怎么销毁Service呢?其实也很简单,点击一下Unbind Service按钮,将Activity和Service的关联解除就可以了。
 
先点击一下Bind Service按钮,再点击一下Unbind Service按钮,打印日志如下所示:


以上这两种销毁的方式都很好理解。那么如果我们既点击了Start Service按钮,又点击了Bind Service按钮会怎么样呢?这个时候你会发现,不管你是单独点击Stop Service按钮还是Unbind Service按钮,Service都不会被销毁,必要将两个按钮都点击一下,Service才会被销毁。也就是说,点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。
 
我们应该始终记得在Service的onDestroy()方法里去清理掉那些不再使用的资源,防止在Service被销毁后还会有一些不再使用的对象仍占用着内存。


创建并绑定本地Service

Service 组件也是可执行程序,也有自己的生命周期。它与 Activity 的区别在于:Service 一直在后台运行而没有用户界面。

在 AndroidManifest.xml 里 Service 元素的常见选项
android:name  -------------  服务类名
android:label  --------------  服务的名字,如果此项不设置,那么默?认显示的服务名则为类名 
android:icon  --------------  服务的图标 
android:permission  -------  申明此服务的权限,这意味着只有提供?了该权限的应用才能控制或连接此服务 
android:process  ----------  表示该服务是否运行在另外一个进程,如?果设置了此项,那么将会在包名后面加上这段字符串?表示另一进程的名字
android:enabled  ----------  如果此项设置为 true,那么 Service 将会默认被?系统启动,不设置默认此项为 false
android:exported  ---------  表示该服务是否能够被其他应用程序所?控制或连接,不设置默认此项为 false 

开发 Service 的步骤
1.    定义一个继承 Service 的子?类。
类似于 Activity,Service 中也定义了系列生?命周期方法如下:
IBinder onBind(Intent intent) :这是 Service 子类必须实现的方法。该方法返回一个 IBinder 对象,应用程序可通过该对象与 Service 组件通信。
void onCreate() :该 Service 被首次创建后回调该方法。
void onDestroy() :该 Service 被关闭之前将回调该方法。
void onStartCommand(Intent intent, int flags, int startId) :每次客户端调用 startService(Intent) 方法启动该 Service 时都会回调该方法。该方法的早期版本:
void onStart(Intent intent, int startId)
boolean onUnbind(Intent intent) :当该 Service 上绑定的所有客户端都断开连接时回调该方法。
2.    在 AndroidManifest.xml 文件中配置该 Service。
使用的配置元素是 <service.../>,与配置 Activity 相似,也可为<service.../> 元素配置 <intent-filter.../> 子元素,用于说明该 Service 可被哪些 Intent 启动。示例——
    <service android:name=".FirstService">
      <intent-filter>
        <!-- 为该Service组件的intent-filter配置action -->
        <action android:name="org.crazyit.service.FIRST_SERVICE" />
      </intent-filter>
    </service>
 
Service 与 Activity 都是从 Context 派生出来,因此都可调用 Context 里定义的 getResources()、getContentResolver() 等方法。
 
如果 Service 和访问者之间需要进行方法调用或数据交换,则应该使用 bindService() 和 unbindService() 方法启动、关闭 Service。
方法签名:
bindService(Intent service, ServiceConnection conn, int flags)
该方法的三个参数解释如下:?
service :通过 Intent 指定要启动的 Service。
conn :该对象用于监听访问者与 Service 的连接情况,并?相应回调如下方法——
?nbsp;   onServiceConnected(ComponentName name, IBinder service) :连接成功时回调该方法。IBinder参数对?象可实现程序与被绑定 Service 之间的通信。实际开发时?通常会采用继承 Binder(IBinder 的实现类)的方式实现自己?的 IBinder 对象。
?nbsp;   onServiceDisconnected(ComponentName name) :当 Service 所在的宿主进程由于异常中止而导?致连接断开时回调该方法。
注:当调?用者主动通过 unBindService() 方?法断开连接时该方?法不会被调用。
 flags :指定绑定时是否自动创建 Service ——
?nbsp;   0 :不自动创建。
?nbsp;   BIND_AUTO_CREATE :自动创建。
 
注:多次调用 bindService() 方法并不会执行重复绑定,因而 onBind() 方法只会被回调一次。

例子:
创建一个Service 是比较简单的,我们需要继承Service这个类,重写里面的一些方法完成我们需要的逻辑。
 
下面是一个例子:
public class MyService extends Service {  
    public static final String TAG = "MyService";  
    private MyBinder mBinder = new MyBinder();  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        Log.d(TAG, "onCreate() executed");  
        Log.d(TAG, "MyService thread id is " + Thread.currentThread().getId());  
    }  
  
    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        // 销毁一些不再使用的资源  
        Log.d(TAG, "onDestroy() executed");  
    }  
  
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        Log.d(TAG, "onStartCommand() executed");  
        //因为当前服务跟Activity是在同一个进程里,耗时操作应?该另起线程处理,避免ANR  
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                Log.d(TAG, "startDownload() executed");  
                Log.d(TAG, "Download thread id is " + Thread.currentThread().getId());  
                // 执行具体的下载任务  
            }  
        }).start();  
  
        return super.onStartCommand(intent, flags, startId);  
    }  
  
    @Override  
    public IBinder onBind(Intent intent) {  
        return mBinder;  
    }  
  
    class MyBinder extends Binder {  
  
        public void startDownload() {  
            new Thread(new Runnable() {  
                @Override  
                public void run() {  
                    Log.d(TAG, "startDownload() executed");  
                    Log.d(TAG, "Download thread id is " + Thread.currentThread().getId());  
                    // 执行具体的下载任务  
                }  
            }).start();  
        }  
  
    }  
}   

 Service里面创建了一个Binder子类对象,该对象有个startDownload方法,将作为onBind 方法返回对象。onBind 方法只有使用bindService开启服务的时候才会被调用,它返回的IBinder对象用于跟Service通讯用的。
(1) 使用startService开启服务
Intent intent = new Intent(MainActivity.this,MyService.class);  
startService(intent);  
(2) 使用bindService 开启服务
Intent intent = new Intent(MainActivity.this,MyService.class);  
bindService(intent,serviceConnection,BIND_AUTO_CREATE);  
bindService方法里面的参数serviceConnection是一个实现 ServiceConnection接口的对象,我们可以这样创建它:
serviceConnection = new ServiceConnection() {  
            @Override  
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {  
                // 简单服务  
                myBinder = (MyService.MyBinder) iBinder;  
                myBinder.startDownload();  
            }  
  
            @Override  
            public void onServiceDisconnected(ComponentName componentName) {  
  
            }  
 };  
 
当Service绑定之后会回调 onServiceConnected 方法,传入的参数有一个IBinder 对?象,我们就是通过这个对象跟Service通讯。这里的例子代?码就是调用了服务的startDownload方法。

IntentService使用

IntentService 是 Service 的子类,扩展了额外的功能。
 
Service 本身存在的两个问题:
Service 不会专门启动一条单独的进程,而是跟它?所在的应用位于同一个进程中。
Service 也不是专门一条新的线程,因此不应在 Service 中直接处理耗时的任务。
 
IntentService 弥补了 Service 的不足:它将使用队列来管理请求 Intent。对于异步的 startService() 请求,IntentService 会依次处理队列中的Intent。由于 IntentService 使用新的 worker 线程处理 Intent 请求,因此不会阻塞主线程。
归纳 IntentService 的特征:
IntentService 会创建单独的 worker 线程来处理所有的 Intent 请求。
IntentService 会创建单独的 worker 线程来处理 onHandleIntent() 方法实现的代码,因此开发者无须处理多线程问题。
当所有请求处理完成后,IntentService 会自动停止,因此开发者无须调用 stopSelf()。
为 Service 的 onBind() 方法提供了默认实现(返回 null)。
为 Service 的 onStartCommand() 方法提供了默认实现,该实现将请求 Intent 添加到队列中。
扩展 IntentService 无须重写 onBind()、onStartCommand() 方法,只要重写 onHandleIntent() 方法即可。
 
使用IntentService需要实现的两个方法: 
?nbsp;   构造函数 
     IntentService的构造函数一定是参数为空的构造函?数,然后再在其中调用super(“name”)这种形式的构造函数?。因为Service的实例化是系统来完成的,而且系统是用参数为空的构造函数来实例化Service的
?nbsp;   实现虚函数onHandleIntent
        在里面根据Intent的不同进行不同的事务处理。  

示例
MyIntentService.java
public class MyIntentService extends IntentService{
  public MyIntentService(){
    super("MyIntentService");
  }
 
  // IntentService会使用单独的线?程来执行该方法的?代码
  @Override
  protected void onHandleIntent(Intent intent){
    // 该方法内可以执?行任何耗时任务,?比如下载文件等,?此处只是让线程暂?停20秒
    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("---耗时任务执?行完成---");
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Android开发教程及笔记-完整版.pdf》是一本关于Android开发的教程和笔记的完整版电子书。这本电子书主要介绍了Android开发所需的各种知识和技术,对于想要学习Android开发的人来说是一本非常有价值的资料。 这本电子书包含了Android开发的基础知识,如Android系统的介绍、Android开发环境的搭建以及常用开发工具的使用方法。同时,它也详细介绍了Android应用程序的开发流程,包括界面设计、布局管理、事件处理、数据库操作等方面的内容,使读者能够全面掌握Android应用程序的开发技巧。 此外,这本电子书还介绍了一些高级的Android开发技术,如网络编程、多媒体处理、传感器应用等方面的知识。通过学习这些高级技术,读者可以进一步提升自己的Android开发水平,设计出更加优秀和复杂的Android应用程序。 除了知识点的介绍之外,这本电子书还提供了大量的实例和代码,让读者能够通过实践来巩固所学知识。同时,它还给出了一些常见问题的解决方法和开发经验的分享,帮助读者更好地理解和应用所学的知识。 总之,《Android开发教程及笔记-完整版.pdf》是一本非常实用的Android开发学习资料,其全面而详细的内容将帮助读者系统地学习和掌握Android开发的技能,为实际项目的开发提供了很好的指导。无论是初学者还是有一定经验的开发者,都可以从中受益匪浅。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星点点-

请我喝杯咖啡呗

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值