Android(三):远程Service基本操作
一、Service简介
Service有local和remote两种类型。
local主要是用于本地的应用程序之间的调用,remote主要用于不同应用之间的重用,这里用到AIDL IPC机制。 关于AIDL IPC机制可以参阅SDK Dev Guide,很简单!当然,你要是想完全理解这种机制可能要花费点时间哟,不过还好,我只是用一下,呵呵!~ ~
二、Service与进程
android各个组件之间默认运行在同一个进程之中,它们有各自所在的进程来管理,它们是主线程的一部分而不是系统开启的线程。
这么说来, 要是 在这些组件中做耗时比较长的操作需要另起线程。
这里需要说明,你可以通过android:process=属性说明应用组建的所属进程。
三、远程Service
先看看文件目录结构吧
在对应的包下面新建一个AIDL文件,这里是IMusicService.aidl文件。那么ADT会自动的为你生成对应的java源文件。不要以为 IMusicService.aidl多难写,其实它就是你暴露给外界的接口,只不过我们把他的后缀写为.aidl而不是.java。
IMusicService.aidl文件:
package ****.blog.myaidl;
interface IMusicService {
void play();
void stop();
void pause();
}
这样,我们就可以在应用程序中使用它啦...
package ****.blog; import java.io.IOException; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import ****.blog.myaidl.IMusicService; public class MusicPlayerService extends Service { //debug private static final String TAG = "Service_06_Remote"; private MediaPlayer mPlayer = null; private IMusicService.Stub binder = new IMusicService.Stub() { @Override public void stop() throws RemoteException { // TODO Auto-generated method stub if(mPlayer != null) { mPlayer.stop(); try { mPlayer.prepare(); } catch (IllegalStateException e) { Log.e(TAG, e.toString()); } catch (IOException e) { Log.e(TAG, e.toString()); } } } @Override public void play() throws RemoteException { // TODO Auto-generated method stub if(mPlayer == null) { mPlayer = MediaPlayer.create(MusicPlayerService.this, R.raw.tiger); } if(! mPlayer.isPlaying()) { mPlayer.start(); } } @Override public void pause() throws RemoteException { // TODO Auto-generated method stub if(mPlayer != null && mPlayer.isPlaying()) { mPlayer.pause(); } } }; @Override public void onCreate() { // TODO Auto-generated method stub //Log.d(TAG, "MusicPlayerService-->onCreate--onBind");//无效 //debug 线程 System.out.println("MusicPlayerService Id-->" + Thread.currentThread().getId()); System.out.println("MusicPlayerService Name-->" + Thread.currentThread().getName()); System.out.println("MusicPlayerService-->onCreate--onBind"); super.onCreate(); } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub try { binder.play(); } catch (RemoteException e) { Log.e(TAG, e.toString()); } //Log.d(TAG, "log MusicPlayerService-->onBind");//无效 System.out.println("MusicPlayerService-->onBind"); return binder; } @Override public boolean onUnbind(Intent intent) { // TODO Auto-generated method stub //Log.d(TAG, "MusicPlayerService-->onUnbind");//无效 System.out.println("MusicPlayerService-->onUnbind"); return super.onUnbind(intent); } @Override public void onDestroy() { // TODO Auto-generated method stub //Log.d(TAG, "MusicPlayerService-->onDestroy");//无效 System.out.println("MusicPlayerService-->onDestroy"); mPlayer.stop(); mPlayer.release(); super.onDestroy(); } }
Activity中我是这样做的:
package ****.blog; 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.os.RemoteException; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import ****.blog.myaidl.IMusicService; public class Service_06_RemoteAct extends Activity implements OnClickListener{ private static final String TAG = "Service_06_RemoteAct"; private static final String SERVICE_ACTION = "****.blog.MusicPlayerService"; private Button btnPlay, btnStop, btnPause, btnExit = null; private IMusicService mIMusicPlayerService = null; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub Log.d(TAG, "onServiceDisconnected()"); mIMusicPlayerService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub Log.d(TAG, "onServiceConnected()"); mIMusicPlayerService = IMusicService.Stub.asInterface(service); } }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //debug 线程 System.out.println("main Id-->" + Thread.currentThread().getId()); System.out.println("main Name-->" + Thread.currentThread().getName()); btnPlay = (Button)findViewById(R.id.button_play); btnStop = (Button)findViewById(R.id.button_stop); btnPause = (Button)findViewById(R.id.button_pause); btnExit = (Button)findViewById(R.id.button_exit); btnPlay.setOnClickListener(this); btnStop.setOnClickListener(this); btnPause.setOnClickListener(this); btnExit.setOnClickListener(this); connection(); } @Override protected void onDestroy() { // TODO Auto-generated method stub Log.d(TAG, "onDestroy-->unbindService"); unbindService(mConnection); super.onDestroy(); } private void connection() { // TODO Auto-generated method stub Log.d(TAG, "bindService"); bindService(new Intent(SERVICE_ACTION), mConnection, Context.BIND_AUTO_CREATE); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()) { case R.id.button_play: try { mIMusicPlayerService.play(); } catch (RemoteException e) { Log.e(TAG, e.toString()); } break; case R.id.button_stop: try { mIMusicPlayerService.stop(); } catch (RemoteException e) { Log.e(TAG, e.toString()); } break; case R.id.button_pause: try { mIMusicPlayerService.pause(); } catch (RemoteException e) { Log.e(TAG, e.toString()); } break; case R.id.button_exit: finish(); break; default: break; } } }
最后,别忘记在manifest.xm文件中声明:
<!--android:process=":remote" 表示该服务在另一个进程之中
这句代码写不写均可以正常运行。
":remote"只是一个标识符,可以任意取名如:"anyName"等
-->
<service android:name=".MusicPlayerService" android:process=":remote">
<intent-filter>
<action android:name="****.blog.MusicPlayerService"/>
</intent-filter>
</service
cmd一下,在命令行中adb shell ps 查看 android 应用程序的 PID 以及进程 ID。