android service 总结篇

深入理解Android的startservice和bindservice

一、首先,让我们确认下什么是service? 
        service就是android系统中的服务,它有这么几个特点:它无法与用户直接进行交互、它必须由用户或者其他程序显式的启动、它的优先级比较高,它比处于前台的应用优先级低,但是比后台的其他应用优先级高,这就决定了当系统因为缺少内存而销毁某些没被利用的资源时,它被销毁的概率很小哦。 
二、那么,什么时候,我们需要使用service呢? 
        我们知道,service是运行在后台的应用,对于用户来说失去了被关注的焦点。这就跟我们打开了音乐播放之后,便想去看看图片,这时候我们还不想音乐停止,这里就会用到service;又例如,我们打开了一个下载链接之后,我们肯定不想瞪着眼睛等他下载完再去做别的事情,对吧?这时候如果我们想手机一边在后台下载,一边可以让我去看看新闻啥的,就要用到service。 
三、service分类: 
       一般我们认为service分为两类,本地service和远程service。 
       本地service顾名思义,那就是和当前应用在同一个进程中的service,彼此之间拥有共同的内存区域,所以对于某些数据的共享特别的方便和简单; 
       远程service:主要牵扯到不同进程间的service访问。因为android的系统安全的原因导致了我们在不同的进程间无法使用一般的方式共享数据。在这里android为我们提供了一个AIDL工具。(android interface description language)android接口描述语言。在后边我们将会对其进行详细的介绍。 
四、service生命周期: 
        和Activity相比,service的生命周期已经简单的不能再简单了,只有onCreate()->onStart()->onDestroy()三个方法。 
       Activity中和service有关的方法: 
       startService(Intent intent):启动一个service 
       stopService(Intent intent) :停止一个service 
        如果我们想使用service中的一些数据或者访问其中的一些方法,那么我们就要通过下面的方法: 
        public boolean bindService(Intent intent, ServiceConnection conn, int flags) ; 
        public void unbindService(ServiceConnection conn); 
        intent是跳转到service的intent,如 Intent intent = new Intent(); intent.setClass(this,MyService.class); 
        conn则是一个代表与service连接状态的类,当我们连接service成功或失败时,会主动触发其内部的onServiceConnectedonServiceDisconnected方法。如果我们想要访问service中的数据,可以在onServiceConnected()方法中进行实现,

 

使用service的步骤: 
        第一步:我们要继承service类,实现自己的service。 
        如果想要访问service中的某些值,我们通常会提供一个继承了Binder的内部类,通过onBund()方法返回给service请求。这里实际上巧妙的利用了内部类能够访问外部类属性的特点。 
第二步:在androidManifest.xml中进行注册,如: 
        <!-- service配置开始 --> 
        <service android:name="MyService"></service> 
        <!-- service配置结束--> 
第三步:在activity中进行启动、绑定、解绑或者停止service。 
        (很多书上说,service与用户是不能交互的,其实这话很不正确,我们完全可以通过activity与service进行交互!我认为,确切的说法应该是service与用户不能进行直接的交互)。

-----------------------------

bindService介绍

一、bindService简介

bindService是绑定Service服务,执行service服务中的逻辑流程。

service通过Context.startService()方法开始,通过Context.stopService()方法停止;也可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自己。只要调用一次stopService()方法便可以停止服务,无论之前它被调用了多少次的启动服务方法。

客户端建立一个与Service的连接,并使用此连接与Service进行通话,通过Context.bindService()方法来绑定服务,Context.unbindService()方法来关闭服务。多个客户端可以绑定同一个服务,如果Service还未被启动,bindService()方法可以启动服务。

上面startService()和bindService()两种模式是完全独立的。你可以绑定一个已经通过startService()方法启动的服务。例如:一个后台播放音乐服务可以通过startService(intend)对象来播放音乐。可能用户在播放过程中要执行一些操作比如获取歌曲的一些信息,此时activity可以通过调用bindServices()方法与Service建立连接。这种情况下,stopServices()方法实际上不会停止服务,直到最后一次绑定关闭。

如果没有程序停止它或者它自己停止,service将一直运行。在这种模式下,service开始于调用Context.startService() ,停止于Context.stopService(). service可以通过调用Android Service 生命周期() 或 Service.stopSelfResult()停止自己。不管调用多少次startService() ,只需要调用一次 stopService() 就可以停止service。

可以通过接口被外部程序调用。外部程序建立到service的连接,通过连接来操作service。建立连接调开始于Context.bindService(), 结束于Context.unbindService(). 多个客户端可以绑定到同一个service,如果service没有启动, bindService() 可以选择启动它。

这2种模式不是完全分离的。你可以可以绑定到一个通过startService()启动的服务。如一个intent想要播放音乐,通过startService() 方法启动后台播放音乐的service。然后,也许用户想要操作播放器或者获取当前正在播放的乐曲的信息,一个activity就会通过bindService()建立一个到此service的连接. 这种情况下 stopService() 在全部的连接关闭后才会真正停止service。

二、bindService启动流程

context.bindService()  ——> onCreate()  ——> onBind()  ——> Service running  ——> onUnbind()  ——> onDestroy()  ——> Service stop

onBind()将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。

所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。

在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。

三、bindService生命周期

像一个activity那样,一个service有些可以用来改变状态的生命周期方法,但是比activity的方法少,service生命周期方法只有三个public

  void onCreate()

  void onStart(Intent intent)

  void onDestroy()

通过实现这三个生命周期方法,你可以监听service的两个嵌套循环的生命周期:

1、整个生命周期

service的整个生命周期是在onCreate()和onDestroy()方法之间。和activity一样,在onCreate()方法里初始化,在onDestroy()方法里释放资源。例如,一个背景音乐播放服务可以在onCreate()方法里播放,在onDestroy()方法里停止。

2、活动的生命周期

service的活动生命周期是在onStart()之后,这个方法会处理通过startServices()方法传递来的Intent对象。音乐service可以通过开打intent对象来找到要播放的音乐,然后开始后台播放。注: service停止时没有相应的回调方法,即没有onStop()方法,只有onDestroy()销毁方法。

onCreate()方法和onDestroy()方法是针对所有的services,无论它们是否启动,通过Context.startService()和Context.bindService()方法都可以访问执行。然而,只有通过startService()方法启动service服务时才会调用onStart()方法。

 

如果一个service允许别人绑定,那么需要实现以下额外的方法:

      IBinder onBind(Intent intent)

      boolean onUnbind(Intent intent)

      void onRebind(Intent intent)

onBind()回调方法会继续传递通过bindService()传递来的intent对象

onUnbind()会处理传递给unbindService()的intent对象。如果service允许绑定,onBind()会返回客户端与服务互相联系的通信句柄(实例)。

如果建立了一个新的客户端与服务的连接,onUnbind()方法可以请求调用onRebind()方法。

记住: 任何服务无论它怎样建立,默认客户端都可以连接,所以任何service都能够接收onBind()和onUnbind()方法

四、bindService和startservice示例

(1)mainactivity

复制代码

public class MainActivity extends Activity {
    Button startServiceButton;// 启动服务按钮
    Button shutDownServiceButton;// 关闭服务按钮
    Button startBindServiceButton;// 启动绑定服务按钮
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        getWidget();
        regiestListener();
    }

    /** 获得组件 */
    public void getWidget() {
        startServiceButton = (Button) findViewById(R.id.startServerButton);
        startBindServiceButton = (Button) findViewById(R.id.startBindServerButton);
        shutDownServiceButton = (Button) findViewById(R.id.sutdownServerButton);
    }

    /** 为按钮添加监听 */
    public void regiestListener() {
        startServiceButton.setOnClickListener(startService);
        shutDownServiceButton.setOnClickListener(shutdownService);
        startBindServiceButton.setOnClickListener(startBinderService);
    }
    
    
    /** 启动服务的事件监听 */
    public Button.OnClickListener startService = new Button.OnClickListener() {
        public void onClick(View view) {
            /** 单击按钮时启动服务 */
            Intent intent = new Intent(MainActivity.this,
                    CountService.class);
            startService(intent);
            
            Log.v("MainStadyServics", "start Service");
        }
    };
    /** 关闭服务 */
    public Button.OnClickListener shutdownService = new Button.OnClickListener() {
        public void onClick(View view) {
            /** 单击按钮时启动服务 */
            Intent intent = new Intent(MainActivity.this,
                    CountService.class);
            /** 退出Activity是,停止服务 */
            stopService(intent);
            Log.v("MainStadyServics", "shutDown serveice");
        }
    };
    /** 打开绑定服务的Activity */
    public Button.OnClickListener startBinderService = new Button.OnClickListener() {
        public void onClick(View view) {
            /** 单击按钮时启动服务 */
            Intent intent = new Intent(MainActivity.this, UseBrider.class);
            startActivity(intent);
            Log.v("MainStadyServics", "start Binder Service");
        }
    };
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

复制代码

(2)service

复制代码

package com.example.testservice;

/**引入包*/
import android.app.Service;// 服务的类
import android.os.IBinder;
import android.os.Binder;
import android.content.Intent;
import android.util.Log;

/** 计数的服务 */
public class CountService extends Service {
    /** 创建参数 */
    boolean threadDisable;
    int count;

    public IBinder onBind(Intent intent) {
        return null;
    }

    public void onCreate() {
        super.onCreate();
        /** 创建一个线程,每秒计数器加一,并在控制台进行Log输出 */
        new Thread(new Runnable() {
            public void run() {
                while (!threadDisable) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {

                    }
                    count++;
                    Log.v("CountService", "Count is" + count);
                }
            }
        }).start();
    }

    public void onDestroy() {
        super.onDestroy();
        /** 服务停止时,终止计数进程 */
        this.threadDisable = true;
    }

    public int getConunt() {
        return count;
    }

//此方法是为了可以在Acitity中获得服务的实例   
class ServiceBinder extends Binder {
        public CountService getService() {
            return CountService.this;
        }
    }
}

复制代码

(3)bindservice(一定要记着这个是要获得,链接的对象)

复制代码

package com.example.testservice;

/**引入包*/
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

/** 通过bindService和unBindSerivce的方式启动和结束服务 */
public class UseBrider extends Activity {
    /** 参数设置 */
    CountService countService;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new UseBriderFace(this));
        
        Intent intent = new Intent(UseBrider.this, CountService.class);
        /** 进入Activity开始服务 */
        bindService(intent, conn, Context.BIND_AUTO_CREATE);

    }

    
    private ServiceConnection conn = new ServiceConnection() {
        /** 获取服务对象时的操作 */
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            countService = ((CountService.ServiceBinder) service).getService();

        }

        /** 无法获取到服务对象时的操作 */
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            countService = null;
        }

    };

    protected void onDestroy() {
        super.onDestroy();
        this.unbindService(conn);
        Log.v("MainStadyServics", "out");
    }
}

复制代码

注意:这个地方有朋友可能会出现onServiceConnected不调用的情况。

这个问题当调用bindService方法后就会回调Activity的onServiceConnected,在这个方法中会向Activity中传递一个IBinder的实例,Acitity需要保存这个实例

在Service中需要创建一个实现IBinder的内部类(这个内部类不一定在Service中实现,但必须在Service中创建它)。

在OnBind()方法中需返回一个IBinder实例,不然onServiceConnected方法不会调用。

不过,我在这里传递null也能够调用,大家根据情况进行判定吧,如果是返回一个ibinder实例的话,示例代码如下:

复制代码

public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        System.out.println("onBind.....");
         IBinder result = null;  
            if ( null == result ) result = new MyBinder() ;
        Toast.makeText(this, "onBind",Toast.LENGTH_LONG);
        return result;
    }

复制代码

 

 

至于startservice和bindservice的使用场景,有网友这么说:

1.通过startservice开启的服务.一旦服务开启, 这个服务和开启他的调用者之间就没有任何的关系了. 
调用者不可以访问 service里面的方法. 调用者如果被系统回收了或者调用了ondestroy方法, service还会继续存在  
2.通过bindService开启的服务,服务开启之后,调用者和服务之间 还存在着联系 , 
一旦调用者挂掉了.service也会跟着挂掉 .

 

示例下载地址:http://pan.baidu.com/share/link?shareid=1614272126&uk=1428765741

还有一个多样化的demo学习地址:http://pan.baidu.com/share/link?shareid=1616100229&uk=1428765741

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Service通常总是称之为“后台服务”,其中“后台”一词是相对于前台而言的,具体是指其本身的运行并不依赖于用户可视的UI界面,因此,从实际业务需求上来理解,Service的适用场景应该具备以下条件:

1.并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的);

2.具有较长时间的运行特性。

1.Service AndroidManifest.xml 声明

一般而言,从Service的启动方式上,可以将Service分为Started Service和Bound Service。无论哪种具体的Service启动类型,都是通过继承Service基类自定义而来。在使用Service时,要想系统能够找到此自定义Service,无论哪种类型,都需要在AndroidManifest.xml中声明,语法格式如下:

复制代码

 1 <service android:enabled=["true" | "false"]
 2     android:exported=["true" | "false"]
 3     android:icon="drawable resource"
 4     android:isolatedProcess=["true" | "false"]
 5     android:label="string resource"
 6     android:name="string"
 7     android:permission="string"
 8     android:process="string" >
 9     . . .
10 </service>

复制代码

其中,android:exported属性上一篇博文中对此已进行详尽描述,android:name对应Service类名,android:permission是权限声明,android:process设置具体的进程名称。需要注意的是Service能否单独使用一个进程与其启动方式有关,本后下面会给出具体说明。其他的属性此处与其他组件基本相同,不再过多描述。

注:如果自定义Service没有在AndroidManifest.xml中声明,当具体使用时,不会像Activity那样直接崩溃报错,对于显式Intent启动的Service,此时也会给出waring信息“IllegalArgumentException: Service not registered”,有时候不容易发现忘了声明而一时定位不到问题。

 

2.Started Service

 Started Service相对比较简单,通过context.startService(Intent serviceIntent)启动Service,context.stopService(Intent serviceIntent)停止此Service。当然,在Service内部,也可以通过stopSelf(...)方式停止其本身。

1)Started Service自定义

下面代码片段显示的是一个最基本的Started Service的自定义方式:

复制代码

 1 public class MyService extends Service {
 2 
 3     public static final String TAG = "MyService";
 4 
 5     @Override
 6     public IBinder onBind(Intent intent) {
 7         return null;
 8     }
 9 
10     @Override
11     public void onCreate() {
12         super.onCreate();
13         Log.w(TAG, "in onCreate");
14     }
15 
16     @Override
17     public int onStartCommand(Intent intent, int flags, int startId) {
18         Log.w(TAG, "in onStartCommand");
19         Log.w(TAG, "MyService:" + this);
20         String name = intent.getStringExtra("name");
21         Log.w(TAG, "name:" + name);
22         return START_STICKY;
23     }
24 
25     @Override
26     public void onDestroy() {
27         super.onDestroy();
28         Log.w(TAG, "in onDestroy");
29     }
30 }

复制代码

其中,onBind(...)函数是Service基类中的唯一抽象方法,子类都必须重写实现,此函数的返回值是针对Bound Service类型的Service才有用的,在Started Service类型中,此函数直接返回 null 即可。onCreate(...)、onStartCommand(...)和onDestroy()都是Started Service相应生命周期阶段的回调函数。

2) Started Service使用

复制代码

 1 public class MainActivity extends Activity {
 2 
 3     public static final String TAG = "MainActivity";
 4 
 5     private Button startServiceBtn;
 6     private Button stopServideBtn;
 7     private Button goBtn;
 8 
 9     private Intent serviceIntent;
10 
11     @Override
12     protected void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         setContentView(R.layout.activity_main);
15 
16         startServiceBtn = (Button) findViewById(R.id.start_service);
17         stopServideBtn = (Button) findViewById(R.id.stop_service);
18         goBtn = (Button) findViewById(R.id.go);
19 
20         startServiceBtn.setOnClickListener(new View.OnClickListener() {
21             @Override
22             public void onClick(View v) {
23                 serviceIntent = new Intent(MainActivity.this, MyService.class);
24                 startService(serviceIntent);
25             }
26         });
27 
28         stopServideBtn.setOnClickListener(new View.OnClickListener() {
29             @Override
30             public void onClick(View v) {
31                 stopService(serviceIntent);
32             }
33         });
34 
35         goBtn.setOnClickListener(new View.OnClickListener() {
36             @Override
37             public void onClick(View v) {
38                 Intent intent = new Intent(MainActivity.this, BActivity.class);
39                 startActivity(intent);
40             }
41         });
42 
43     }
44 
45     @Override
46     protected void onDestroy() {
47         super.onDestroy();
48         Log.w(TAG, "in onDestroy");
49     }
50 }

复制代码

如上代码片段,

当Client调用startService(Intent serviceIntent)后,如果MyService是第一次启动,首先会执行 onCreate()回调,然后再执行onStartCommand(Intent intent, int flags, int startId),当Client再次调用startService(Intent serviceIntent),将只执行onStartCommand(Intent intent, int flags, int startId),因为此时Service已经创建了,无需执行onCreate()回调。无论多少次的startService,只需要一次stopService()即可将此Service终止,执行onDestroy()函数(其实很好理解,因为onDestroy()与onCreate()回调是相对的)。

下面重点关注下onStartCommand(Intent intent, int flags, int startId)方法。

其中参数flags默认情况下是0,对应的常量名为START_STICKY_COMPATIBILITY。startId是一个唯一的整型,用于表示此次Client执行startService(...)的请求请求标识,在多次startService(...)的情况下,呈现0,1,2....递增。另外,此函数具有一个int型的返回值,具体的可选值及含义如下:

START_NOT_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。除非程序中Client明确再次调用startService(...)启动此Service。

START_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand(...)方法,但其中的Intent将是null,pendingintent除外。

START_REDELIVER_INTENT:与START_STICKY唯一不同的是,回调onStartCommand(...)方法时,其中的Intent将是非空,将是最后一次调用startService(...)中的intent。

START_STICKY_COMPATIBILITY:compatibility version of {@link #START_STICKY} that does not guarantee that {@link #onStartCommand} will be called again after being killed。此值一般不会使用,所以注意前面三种情形就好。

以上的描述中,”当Service因为内存不足而被系统kill后“一定要非常注意,因为此函数的返回值设定只是针对此种情况才有意义的,换言之,当认为的kill掉Service进程,此函数返回值无论怎么设定,接下来未来的某个时间内,即使系统内存足够可用,Service也不会重启。

小米手机针对此处做了变更:

另外,需要注意的是,小米手机针对此处做了一定的修改。在“自启动管理”中有一个自启动应用列表,默认情况下,只有少应用(如微信、QQ、YY、360等)默认是可以自启动的,其他应用默认都是禁止的。用户可以手动添加自启动应用,添加后的应用中如果Started Service onStartCommand(...)回调返回值是START_STICKY或START_REDELIVER_INTENT,当用户在小米手机上长按Home键结束App后,接下来未来的某个时间内,当系统内存足够可用时,Service依然可以按照上述规定重启。当然,如果用户在 设置 >> 应用 >> 强制kill掉App进程,此时Service是不会重启的。

注:以上实验结论基于小米2S亲测。

 

3) Started Service生命周期及进程相关

1.onCreate(Client首次startService(..)) >> onStartCommand >> onStartCommand - optional ... >> onDestroy(Client调用stopService(..))

注:onStartCommand(..)可以多次被调用,onDestroy()与onCreate()想匹配,当用户强制kill掉进程时,onDestroy()是不会执行的。

2.对于同一类型的Service,Service实例一次永远只存在一个,而不管Client是否是相同的组件,也不管Client是否处于相同的进程中。

3.Service通过startService(..)启动Service后,此时Service的生命周期与Client本身的什么周期是没有任何关系的,只有Client调用stopService(..)或Service本身调用stopSelf(..)才能停止此Service。当然,当用户强制kill掉Service进程或系统因内存不足也可能kill掉此Service。

4.Client A 通过startService(..)启动Service后,可以在其他Client(如Client B、Client C)通过调用stopService(..)结束此Service。

5.Client调用stopService(..)时,如果当前Service没有启动,也不会出现任何报错或问题,也就是说,stopService(..)无需做当前Service是否有效的判断。

6.startService(Intent serviceIntent),其中的intent既可以是显式Intent,也可以是隐式Intent,当Client与Service同处于一个App时,一般推荐使用显示Intent。当处于不同App时,只能使用隐式Intent。

当Service需要运行在单独的进程中,AndroidManifest.xml声明时需要通过android:process指明此进程名称,当此Service需要对其他App开放时,android:exported属性值需要设置为true(当然,在有intent-filter时默认值就是true)。

复制代码

1 <service
2     android:name=".MyService"
3     android:exported="true"
4     android:process=":MyCorn" >
5     <intent-filter>
6         <action android:name="com.example.androidtest.myservice" />
7     </intent-filter>
8 </service>

复制代码

 

4)Started Service Client与Service通信相关

当Client调用startService(Intent serviceIntent)启动Service时,Client可以将参数通过Intent直接传递给Service。Service执行过程中,如果需要将参数传递给Client,一般可以通过借助于发送广播的方式(此时,Client需要注册此广播)。

 

3.Bound Service

相对于Started Service,Bound Service具有更多的知识点。Bound Service的主要特性在于Service的生命周期是依附于Client的生命周期的,当Client不存在时,Bound Service将执行onDestroy,同时通过Service中的Binder对象可以较为方便进行Client-Service通信。Bound Service一般使用过程如下:

1.自定义Service继承基类Service,并重写onBind(Intent intent)方法,此方法中需要返回具体的Binder对象;

2.Client通过实现ServiceConnection接口来自定义ServiceConnection,并通过bindService (Intent service, ServiceConnection sc, int flags)方法将Service绑定到此Client上;

3.自定义的ServiceConnection中实现onServiceConnected(ComponentName name, IBinder binder)方法,获取Service端Binder实例;

4.通过获取的Binder实例进行Service端其他公共方法的调用,以完成Client-Service通信;

5.当Client在恰当的生命周期(如onDestroy等)时,此时需要解绑之前已经绑定的Service,通过调用函数unbindService(ServiceConnection sc)。

 在Bound Service具体使用过程中,根据onBind(Intent intent)方法放回的Binder对象的定义方式不同,又可以将其分为以下三种方式,且每种方式具有不同的特点和适用场景:

1).Extending the Binder class

 这是Bound Service中最常见的一种使用方式,也是Bound Service中最简单的一种。

局限:Clinet与Service必须同属于同一个进程,不能实现进程间通信(IPC)。否则则会出现类似于“android.os.BinderProxy cannot be cast to xxx”错误。

下面通过代码片段看下具体的使用:

复制代码

 1 public class MyBindService extends Service {
 2 
 3     public static final String TAG = "MyBindService";
 4 
 5     private MyBinder mBinder = new MyBinder();
 6 
 7     public class MyBinder extends Binder {
 8         MyBindService getService() {
 9             return MyBindService.this;
10         }
11     }
12 
13     @Override
14     public void onCreate() {
15         super.onCreate();
16         Log.w(TAG, "in onCreate");
17     }
18 
19     @Override
20     public IBinder onBind(Intent intent) {
21         Log.w(TAG, "in onBind");
22         return mBinder;
23     }
24 
25     @Override
26     public boolean onUnbind(Intent intent) {
27         Log.w(TAG, "in onUnbind");
28         return super.onUnbind(intent);
29     }
30 
31     @Override
32     public void onDestroy() {
33         super.onDestroy();
34         Log.w(TAG, "in onDestroy");
35     }
36 }

复制代码

复制代码

 1 public class BActivity extends Activity {
 2 
 3     public static final String TAG = "BActivity";
 4 
 5     private Button bindServiceBtn;
 6     private Button unbindServiceBtn;
 7 
 8     private Button startIntentService;
 9 
10     private Intent serviceIntent;
11 
12     private ServiceConnection sc = new MyServiceConnection();
13     private MyBinder mBinder;
14     private MyBindService mBindService;
15     private boolean mBound;
16 
17     private class MyServiceConnection implements ServiceConnection {
18 
19         @Override
20         public void onServiceConnected(ComponentName name, IBinder binder) {
21             Log.w(TAG, "in MyServiceConnection onServiceConnected");
22             mBinder = (MyBinder) binder;
23             mBindService = mBinder.getService();
24 
25             mBound = true;
26         }
27 
28         @Override
29         public void onServiceDisconnected(ComponentName name) {
30             // This is called when the connection with the service has been
31             // unexpectedly disconnected -- that is, its process crashed.
32             Log.w(TAG, "in MyServiceConnection onServiceDisconnected");
33             mBound = false;
34         }
35 
36     }
37 
38     @Override
39     protected void onCreate(Bundle savedInstanceState) {
40         super.onCreate(savedInstanceState);
41         setContentView(R.layout.b);
42 
43         bindServiceBtn = (Button) findViewById(R.id.bind_service);
44         unbindServiceBtn = (Button) findViewById(R.id.unbind_service);
45         startIntentService = (Button) findViewById(R.id.start_intentservice);
46 
47         bindServiceBtn.setOnClickListener(new View.OnClickListener() {
48             @Override
49             public void onClick(View v) {
50                 Intent intent = new Intent(BActivity.this, MyBindService.class);
51                 bindService(intent, sc, Context.BIND_AUTO_CREATE);
52             }
53         });
54 
55         unbindServiceBtn.setOnClickListener(new View.OnClickListener() {
56             @Override
57             public void onClick(View v) {
58                 excuteUnbindService();
59             }
60         });
61 
62         startIntentService.setOnClickListener(new View.OnClickListener() {
63             @Override
64             public void onClick(View v) {
65                 Intent intent = new Intent(BActivity.this, MyIntentService.class);
66                 startService(intent);
67             }
68         });
69 
70     }
71 
72     private void excuteUnbindService() {
73         if (mBound) {
74             unbindService(sc);
75             mBound = false;
76         }
77     }
78 
79     @Override
80     protected void onDestroy() {
81         super.onDestroy();
82         Log.w(TAG, "in onDestroy");
83         excuteUnbindService();
84     }
85 }

复制代码

首次点击bindServiceBtn进行bindService(..)时,依次回调顺序如下:

1 MyBindService(13457): in onCreate
2 MyBindService(13457): in onBind
3 BActivity(13457): in MyServiceConnection onServiceConnected

再次点击bindServiceBtn按钮时,发现没有任何输出,说明MyBindService没有进行任何回调。

点击unbindServiceBtn进行unbindService(..)时,回调顺序为:

1 MyBindService(13457): in onUnbind
2 MyBindService(13457): in onDestroy

 注:在四大基本组件中,需要注意的的是BroadcastReceiver不能作为Bound Service的Client,因为BroadcastReceiver的生命周期很短,当执行完onReceive(..)回调时,BroadcastReceiver生命周期完结。而Bound Service又与Client本身的生命周期相关,因此,Android中不允许BroadcastReceiver去bindService(..),当有此类需求时,可以考虑通过startService(..)替代。

 

2)Using a Messenger

Messenger,在此可以理解成”信使“,通过Messenger方式返回Binder对象可以不用考虑Clinet - Service是否属于同一个进程的问题,并且,可以实现Client - Service之间的双向通信。极大方便了此类业务需求的实现。

局限:不支持严格意义上的多线程并发处理,实际上是以队列去处理

下面直接看下具体的使用:

复制代码

 1 public class MyMessengerService extends Service {
 2 
 3     public static final String TAG = "MyMessengerService";
 4 
 5     public static final int MSG_FROM_CLIENT_TO_SERVER = 1;
 6     public static final int MSG_FROM_SERVER_TO_CLIENT = 2;
 7 
 8     private Messenger mClientMessenger;
 9     private Messenger mServerMessenger = new Messenger(new ServerHandler());
10 
11     @Override
12     public IBinder onBind(Intent intent) {
13         Log.w(TAG, "in onBind");
14         return mServerMessenger.getBinder();
15     }
16 
17     class ServerHandler extends Handler {
18         @Override
19         public void handleMessage(Message msg) {
20             Log.w(TAG, "thread name:" + Thread.currentThread().getName());
21             switch (msg.what) {
22             case MSG_FROM_CLIENT_TO_SERVER:
23                 Log.w(TAG, "receive msg from client");
24                 mClientMessenger = msg.replyTo;
25 
26                 // service发送消息给client
27                 Message toClientMsg = Message.obtain(null, MSG_FROM_SERVER_TO_CLIENT);
28                 try {
29                     Log.w(TAG, "server begin send msg to client");
30                     mClientMessenger.send(toClientMsg);
31                 } catch (RemoteException e) {
32                     e.printStackTrace();
33                 }
34                 break;
35             default:
36                 super.handleMessage(msg);
37             }
38         }
39     }
40 
41     @Override
42     public boolean onUnbind(Intent intent) {
43         Log.w(TAG, "in onUnbind");
44         return super.onUnbind(intent);
45     }
46 
47     @Override
48     public void onDestroy() {
49         Log.w(TAG, "in onDestroy");
50         super.onDestroy();
51     }
52 }

复制代码

复制代码

  1 public class CActivity extends Activity {
  2 
  3     public static final String TAG = "CActivity";
  4 
  5     private Button bindServiceBtn;
  6     private Button unbindServiceBtn;
  7     private Button sendMsgToServerBtn;
  8 
  9     private ServiceConnection sc = new MyServiceConnection();
 10     private boolean mBound;
 11 
 12     private Messenger mServerMessenger;
 13 
 14     private Handler mClientHandler = new MyClientHandler();
 15     private Messenger mClientMessenger = new Messenger(mClientHandler);
 16 
 17     private class MyClientHandler extends Handler {
 18         @Override
 19         public void handleMessage(Message msg) {
 20             if (msg.what == MyMessengerService.MSG_FROM_SERVER_TO_CLIENT) {
 21                 Log.w(TAG, "reveive msg from server");
 22             }
 23         }
 24     }
 25 
 26     private class MyServiceConnection implements ServiceConnection {
 27 
 28         @Override
 29         public void onServiceConnected(ComponentName name, IBinder binder) {
 30             Log.w(TAG, "in MyServiceConnection onServiceConnected");
 31             mServerMessenger = new Messenger(binder);
 32 
 33             mBound = true;
 34         }
 35 
 36         @Override
 37         public void onServiceDisconnected(ComponentName name) {
 38             // This is called when the connection with the service has been
 39             // unexpectedly disconnected -- that is, its process crashed.
 40             Log.w(TAG, "in MyServiceConnection onServiceDisconnected");
 41 
 42             mBound = false;
 43         }
 44     }
 45 
 46     @Override
 47     protected void onCreate(Bundle savedInstanceState) {
 48         super.onCreate(savedInstanceState);
 49         setContentView(R.layout.c);
 50 
 51         bindServiceBtn = (Button) findViewById(R.id.bind_service);
 52         unbindServiceBtn = (Button) findViewById(R.id.unbind_service);
 53         sendMsgToServerBtn = (Button) findViewById(R.id.send_msg_to_server);
 54 
 55         bindServiceBtn.setOnClickListener(new View.OnClickListener() {
 56             @Override
 57             public void onClick(View v) {
 58                 Intent intent = new Intent(CActivity.this, MyMessengerService.class);
 59                 bindService(intent, sc, Context.BIND_AUTO_CREATE);
 60             }
 61         });
 62 
 63         unbindServiceBtn.setOnClickListener(new View.OnClickListener() {
 64             @Override
 65             public void onClick(View v) {
 66                 excuteUnbindService();
 67             }
 68         });
 69 
 70         sendMsgToServerBtn.setOnClickListener(new View.OnClickListener() {
 71             @Override
 72             public void onClick(View v) {
 73                 sayHello();
 74             }
 75         });
 76 
 77         new Handler().postDelayed(new Runnable() {
 78             @Override
 79             public void run() {
 80                 Intent intent = new Intent(CActivity.this, MyAlarmBroadcastReceiver.class);
 81                 sendBroadcast(intent);
 82             }
 83         }, 3 * 1000);
 84 
 85     }
 86 
 87     public void sayHello() {
 88         if (!mBound)
 89             return;
 90         // Create and send a message to the service, using a supported 'what' value
 91         Message msg = Message.obtain(null, MyMessengerService.MSG_FROM_CLIENT_TO_SERVER, 0, 0);
 92         // 通过replyTo把client端的Messenger(信使)传递给service
 93         msg.replyTo = mClientMessenger;
 94         try {
 95             mServerMessenger.send(msg);
 96         } catch (RemoteException e) {
 97             e.printStackTrace();
 98         }
 99     }
100 
101     private void excuteUnbindService() {
102         if (mBound) {
103             unbindService(sc);
104             mBound = false;
105         }
106     }
107 
108     @Override
109     protected void onDestroy() {
110         super.onDestroy();
111         Log.w(TAG, "in onDestroy");
112         excuteUnbindService();
113     }
114 }

复制代码

其中,需要注意的几点是:

1.MyMessengerService自定中,通过new Messenger(new ServerHandler())创建Messenger对象,在onBind(..)回调中,通过调用Messenger对象的getBinder()方法,将Binder返回;

2.Client在ServiceConnection的onServiceConnected(..)的回调中,通过new Messenger(binder)获取到Service传递过来的mServerMessenger;

3.接下来,就可以通过mServerMessenger.send(msg)方法向Service发送message,Service中的Messenger构造器中的Handler即可接收到此信息,在handleMessage(..)回调中处理;

4.至此只是完成了从Client发送消息到Service,同样的道理,想实现Service发送消息到Client,可以在客户端定义一个Handler,并得到相应的Messenger,在Clinet发送消息给Service时,通过msg.replyTo = mClientMessenger方式将Client信使传递给Service;

5.Service接收到Client信使后,获取此信使,并通过mClientMessenger.send(toClientMsg)方式将Service消息发送给Client。

至此,完成了Client - Service之间的双向通信流程。

 

3).AIDL(Android Interface Definition Language)

一般情况下,Messenger这种方式都是可以满足需求的,当然,通过自定义AIDL方式相对更加灵活。

这种方式需要自己在项目中自定义xxx.aidl文件,然后系统会自动在gen目录下生成相应的接口类文件,接下来整个的流程与Messenger方式差别不大,网上也有不少实例,在此不再具体给出。

 

注:无论哪种方式的Bound Service,在进行unbind(..)操作时,都需要注意当前Service是否处于已经绑定状态,否则可能会因为当前Service已经解绑后继续执行unbind(..)会导致崩溃。这点与Started Service区别很大(如前文所述:stopService(..)无需做当前Service是否有效的判断)。

 

4.Local Service  VS Remote Service

Local Service:不少人又称之为”本地服务“,是指Client - Service同处于一个进程;

Remote Service:又称之为”远程服务“,一般是指Service处于单独的一个进程中。

其他使用上上文中基本上都有所述。

 

5.Service特性

1.Service本身都是运行在其所在进程的主线程(如果Service与Clinet同属于一个进程,则是运行于UI线程),但Service一般都是需要进行”长期“操作,所以经常写法是在自定义Service中处理”长期“操作时需要新建线程,以免阻塞UI线程或导致ANR;

2.Service一旦创建,需要停止时都需要显示调用相应的方法(Started Service需要调用stopService(..)或Service本身调用stopSelf(..), Bound Service需要调用unbindService(..)),否则对于Started Service将处于一直运行状态,对于Bound Service,当Client生命周期结束时也将因此问题。也就是说,Service执行完毕后,必须人为的去停止它。

 

6.IntentService

IntentService是系统提供给我们的一个已经继承自Service类的特殊类,IntentService特殊性是相对于Service本身的特性而言的:

1.默认直接实现了onBind(..)方法,直接返回null,并定义了抽象方法onHandlerIntent(..),用户自定义子类时,需要实现此方法;

2.onHandlerIntent(..)主要就是用来处于相应的”长期“任务的,并且已经自动在新的线程中,用户无语自定义新线程;

3.当”长期“任务执行完毕后(也就是onHandlerIntent(..)执行完毕后),此IntentService将自动结束,无需人为调用方法使其结束;

4.IntentService处于任务时,也是按照队列的方式一个个去处理,而非真正意义上的多线程并发方式。

下面是一个基本的继承自IntentService的自定义Service:

复制代码

 1 public class MyIntentService extends IntentService {
 2 
 3     public static final String TAG = "MyIntentService";
 4 
 5     public MyIntentService() {
 6         super(TAG);
 7     }
 8 
 9     public MyIntentService(String name) {
10         super(name);
11     }
12 
13     @Override
14     protected void onHandleIntent(Intent intent) {
15         Log.w(TAG, "in onHandleIntent");
16         Log.w(TAG, "thread name:" + Thread.currentThread().getName());
17     }
18 
19 }

复制代码

 

7.前台Service

Android中Service接口中还提供了一个称之为”前台Service“的概念。通过Service.startForeground (int id, Notification notification)方法可以将此Service设置为前台Service。在UI显示上,notification将是一个处于onGoing状态的通知,使得前台Service拥有更高的进程优先级,并且Service可以直接notification通信。

下面是一个简单的前台Service使用实例:

复制代码

 1 public class MyService extends Service {
 2 
 3     public static final String TAG = "MyService";
 4 
 5     @Override
 6     public IBinder onBind(Intent intent) {
 7         return null;
 8     }
 9 
10     @Override
11     public void onCreate() {
12         super.onCreate();
13         Log.w(TAG, "in onCreate");
14     }
15 
16     @Override
17     public int onStartCommand(Intent intent, int flags, int startId) {
18         Log.w(TAG, "in onStartCommand");
19         Log.w(TAG, "MyService:" + this);
20         String name = intent.getStringExtra("name");
21         Log.w(TAG, "name:" + name);
22 
23         
24         Notification notification = new Notification(R.drawable.ic_launcher, "test", System.currentTimeMillis());
25         Intent notificationIntent = new Intent(this, DActivity.class);
26         PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntesnt, 0);
27         notification.setLatestEventInfo(this, "title", "content", pendingIntent);
28         startForeground(1, notification);
29         
30 
31         return START_REDELIVER_INTENT;
32     }
33 
34     @Override
35     public void onDestroy() {
36         super.onDestroy();
37         Log.w(TAG, "in onDestroy");
38     }
39 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值