Android Service
Android 有四大组件: Activity , Service , BroadcastReceiver , ContentProvider, 这篇主要讲Service
启动Service有两种方式: startService 和 bindService
startService:
Service也有自己的生命周期, startService是会依次调用service的 onCreate(), onStartCommand(),onStart()方法(实际在父类的onStartCommand()方法中主动调用的onStart()),如果Service已经启动了,则只会调用onStartCommand()和onStart().
stopService,停止已经开始的Service,会动用Service的onDestroy();
从log中可以看到,Service是运行与主线程,所以不应做繁重的任务,防止ANR.
bindService:
bindService 需要传三个参数 Intent ,ServiceConnection , flag
Intent 指明需要启动的Service ; ServiceConnection Service连接成功之后的回调; flag bind的方式,一般是1;
bindService 会依次调用Service的onCreate(),onBind()方法, 如果Service已经启动,再次bindService会连接,但不会再调用生命周期的方法
unbindService 会调用Service的onDestroy()。
通过bindService的方式启动Service,可以获取到一个IBinder对象,通过IBinder对象可以调用Service里的方法。
binderService的第二个参数: 通过onServiceConnected()回调 可以获取到IBinder对象。
1 ServiceConnection sc = new ServiceConnection() { 2 @Override 3 public void onServiceDisconnected(ComponentName name) { 4 5 } 6 @Override 7 public void onServiceConnected(ComponentName name, IBinder service) { 8 // TODO Auto-generated method stub 9 10 };
AIDL: android 接口定义语言,通过他可以实现进程间的通信。
要和远端的Service进行交互,可以使用aidl实现进程间的通信:
myService.aidl
1 package com.example.servicelearning.aidl; 2 3 interface myService { 4 void register(); 5 int get(); 6 }
编译之后,会在gen目录对应包名下自动生成一个myService.java的接口,里面有一个内部静态抽象类Stub,实现了myService的接口。
编译之后的myService.java
1 /* 2 * This file is auto-generated. DO NOT MODIFY. 3 * Original file: E:\\vivoCamera\\ServiceLearning\\src\\com\\example\\servicelearning\\aidl\\myService.aidl 4 */ 5 package com.example.servicelearning.aidl; 6 public interface myService extends android.os.IInterface 7 { 8 /** Local-side IPC implementation stub class. */ 9 public static abstract class Stub extends android.os.Binder implements com.example.servicelearning.aidl.myService 10 { 11 private static final java.lang.String DESCRIPTOR = "com.example.servicelearning.aidl.myService"; 12 /** Construct the stub at attach it to the interface. */ 13 public Stub() 14 { 15 this.attachInterface(this, DESCRIPTOR); 16 } 17 /** 18 * Cast an IBinder object into an com.example.servicelearning.aidl.myService interface, 19 * generating a proxy if needed. 20 */ 21 public static com.example.servicelearning.aidl.myService asInterface(android.os.IBinder obj) 22 { 23 if ((obj==null)) { 24 return null; 25 } 26 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 27 if (((iin!=null)&&(iin instanceof com.example.servicelearning.aidl.myService))) { 28 return ((com.example.servicelearning.aidl.myService)iin); 29 } 30 return new com.example.servicelearning.aidl.myService.Stub.Proxy(obj); 31 } 32 @Override public android.os.IBinder asBinder() 33 { 34 return this; 35 } 36 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException 37 { 38 switch (code) 39 { 40 case INTERFACE_TRANSACTION: 41 { 42 reply.writeString(DESCRIPTOR); 43 return true; 44 } 45 case TRANSACTION_register: 46 { 47 data.enforceInterface(DESCRIPTOR); 48 this.register(); 49 reply.writeNoException(); 50 return true; 51 } 52 case TRANSACTION_get: 53 { 54 data.enforceInterface(DESCRIPTOR); 55 int _result = this.get(); 56 reply.writeNoException(); 57 reply.writeInt(_result); 58 return true; 59 } 60 } 61 return super.onTransact(code, data, reply, flags); 62 } 63 private static class Proxy implements com.example.servicelearning.aidl.myService 64 { 65 private android.os.IBinder mRemote; 66 Proxy(android.os.IBinder remote) 67 { 68 mRemote = remote; 69 } 70 @Override public android.os.IBinder asBinder() 71 { 72 return mRemote; 73 } 74 public java.lang.String getInterfaceDescriptor() 75 { 76 return DESCRIPTOR; 77 } 78 @Override public void register() throws android.os.RemoteException 79 { 80 android.os.Parcel _data = android.os.Parcel.obtain(); 81 android.os.Parcel _reply = android.os.Parcel.obtain(); 82 try { 83 _data.writeInterfaceToken(DESCRIPTOR); 84 mRemote.transact(Stub.TRANSACTION_register, _data, _reply, 0); 85 _reply.readException(); 86 } 87 finally { 88 _reply.recycle(); 89 _data.recycle(); 90 } 91 } 92 @Override public int get() throws android.os.RemoteException 93 { 94 android.os.Parcel _data = android.os.Parcel.obtain(); 95 android.os.Parcel _reply = android.os.Parcel.obtain(); 96 int _result; 97 try { 98 _data.writeInterfaceToken(DESCRIPTOR); 99 mRemote.transact(Stub.TRANSACTION_get, _data, _reply, 0); 100 _reply.readException(); 101 _result = _reply.readInt(); 102 } 103 finally { 104 _reply.recycle(); 105 _data.recycle(); 106 } 107 return _result; 108 } 109 } 110 static final int TRANSACTION_register = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 111 static final int TRANSACTION_get = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); 112 } 113 public void register() throws android.os.RemoteException; 114 public int get() throws android.os.RemoteException; 115 }
在自己的Service 实现此类里面的抽象方法。在bindService的时候,onBind()方法可以return此对象,通过此对象实现通信。
BindServiceTest.java (记得在Manifest文件里声明Service)
1 package com.example.servicelearning.service; 2 3 import com.example.servicelearning.aidl.myService; 4 5 import android.app.Service; 6 import android.content.Intent; 7 import android.os.IBinder; 8 import android.os.RemoteException; 9 import android.util.Log; 10 11 public class BindServiceTest extends Service { 12 13 14 private static final String TAG = "BindServiceTestLog.TAG"; 15 16 17 myService.Stub mStub = new myService.Stub() { 18 19 @Override 20 public void register() throws RemoteException { 21 // TODO Auto-generated method stub 22 Log.d(TAG, "register from com.example.servicelearning"); 23 } 24 25 @Override 26 public int get() throws RemoteException { 27 // TODO Auto-generated method stub 28 return 10086; 29 } 30 }; 31 32 @Override 33 public IBinder onBind(Intent intent) { 34 Log.d(TAG, "onBind"); 35 return mStub; 36 } 37 38 }
为了验证通过AIDL实现的进程通信,我们可以再编写一个apk,通过这个apk启动之前那个apk里面的Service,并实现通信。
在这个apk里面我们必须写一个同样的aidl文件,包名必须和之前那个一致。
MainActivity.java (布局文件和Manifest文件都比较简单就不贴出来了)
1 package com.example.servicetesthelp; 2 3 import com.example.servicelearning.aidl.myService; 4 import android.app.Activity; 5 import android.content.ComponentName; 6 import android.content.Context; 7 import android.content.Intent; 8 import android.content.ServiceConnection; 9 import android.os.Bundle; 10 import android.os.IBinder; 11 import android.os.RemoteException; 12 import android.util.Log; 13 import android.view.View; 14 import android.view.View.OnClickListener; 15 import android.widget.Button; 16 17 public class MainActivity extends Activity { 18 19 private static final String TAG = "MainActivityLog.TAG"; 20 Button mButton; 21 @Override 22 protected void onCreate(Bundle savedInstanceState) { 23 super.onCreate(savedInstanceState); 24 setContentView(R.layout.activity_main); 25 mButton = (Button) findViewById(R.id.mButton); 26 mButton.setOnClickListener(new OnClickListener() { 27 28 @Override 29 public void onClick(View v) { 30 // TODO Auto-generated method stub 31 Log.d(TAG, "onClick "); 32 Intent mIntent = new Intent("android.service.bindservicetest"); 33 mIntent.setPackage("com.example.servicelearning"); 34 bindService(mIntent, new ServiceConnection() { 35 36 @Override 37 public void onServiceDisconnected(ComponentName name) { 38 // TODO Auto-generated method stub 39 } 40 41 @Override 42 public void onServiceConnected(ComponentName name, IBinder service) { 43 // TODO Auto-generated method stub 44 Log.d(TAG , "ServiceTestHelp onServiceConnected"); 45 myService binder = myService.Stub.asInterface(service); 46 try { 47 binder.register(); 48 Log.d(TAG," get = " + binder.get()); 49 } catch (RemoteException e) { 50 // TODO Auto-generated catch block 51 e.printStackTrace(); 52 } 53 } 54 }, Context.BIND_AUTO_CREATE); 55 } 56 }); 57 } 58 59 }
点击按钮之后,启动Service,(启动Service时,Intent必须是显性的),onServiceConnected()方法的回调的Ibinder方法,通过myService.Stub.asInterface()方法获取到myService对象,通过此对象可以调用对端Service的方法,具体可以通过Log看到。
1 01-06 08:07:30.385 30401 30401 D MainActivityLog.TAG: onClick
2 01-06 08:07:30.450 30442 30442 D BindServiceTestLog.TAG: onBind 3 01-06 08:07:30.452 30401 30401 D MainActivityLog.TAG: ServiceTestHelp onServiceConnected 4 01-06 08:07:30.453 30442 30462 D BindServiceTestLog.TAG: register from com.example.servicelearning 5 01-06 08:07:30.454 30401 30401 D MainActivityLog.TAG: get = 10086
可以看到是在两个进程里面,也可以正常通信。