zoukankan      html  css  js  c++  java
  • Android总结篇系列:Android Service

    Android总结篇系列:Android Service

     

    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 }
    复制代码
    --------------------------------------------------------------------------------- 
    笔者水平有限,若有错漏,欢迎指正,如果转载以及CV操作,请希注明出处,谢谢!
     
    分类: Android
     
    好文要顶 关注我 收藏该文  
    2
    0
     
    (请您对文章做出评价)
     
    « 上一篇:Android总结篇系列:Android广播机制
    » 下一篇:Android总结篇系列:Android Intent
    posted @ 2014-12-23 21:51 Windstep 阅读(10004) 评论(2) 编辑 收藏

     

     
      
    #1楼 2016-03-01 12:37 骛实豫  
    业界良心好文章
      
    #2楼 2016-03-10 10:27 伟大的臭猪猪  
    你确定service的生命周期受client影响?
    http://www.cnblogs.com/lwbqqyumidi/p/4181185.html
    http://www.cnblogs.com/mengdd/archive/2013/03/24/2979944.html
    http://www.cnblogs.com/macroxu-1982/archive/2012/12/18/2823183.html
  • 相关阅读:
    Web开发者不容错过的20段CSS代码
    常用统计学公式
    手工设置paraview 的几个问题
    响应qt消息应该注意的一点
    找不到QtDir变量的解决办法, 同时不需要经过编译就可以使用qt 库
    paraview的几个问题
    使用paraview 方法
    有志于webgl, three.js编程的朋友进入群52391108,72579998,共同学习提高,本人提供学习相关的资料,webgl,three.js学习,交流的论坛www.webglchina.cn
    qt模型视图结构
    opengl 场景转换过程
  • 原文地址:https://www.cnblogs.com/pengmn/p/5261939.html
Copyright © 2011-2022 走看看