本文共 8537 字,大约阅读时间需要 28 分钟。
**
**
android service是运行在后台的程序,说白了,就是没有界面,这里我想强调的一点是,运行在后台不等于运行在非主线程,除了IntentService外,普通的service如果你没有开启新的线程,那么默认是运行在主线程中的。 service有两种启动方式,一个是bind,一个是start,两种启动方式,有挺多区别。需要注意的是,bind绑定service的时候,直到最后一个bind到service的程序调用unbind,否则service一直会运行。而对于startservice这种启动方式来说,一旦启动,需要自己stopService或者调用service内部的stopSelf,否则该service是不会关闭的。 还需要注意的是service的声明周期,这个附张图就全明白了。好了,废话不多说了,上个demo吧:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private boolean hasBound; private Button intent_Service; private Button start_Service; private Button bind_Service; private Button messenger_Service; //下面的handler和Messenger使用来进行跨进程通信的 private Handler handler=new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(msg.what==322) { Toast.makeText(getApplicationContext(),"receive message from server",Toast.LENGTH_SHORT).show(); } } }; private Messenger clientMessenger=new Messenger(handler); private Messenger serverMessenger; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { intent_Service= (Button) findViewById(R.id.intent_service); intent_Service.setOnClickListener(this); start_Service= (Button) findViewById(R.id.start_service); start_Service.setOnClickListener(this); bind_Service=(Button)findViewById(R.id.bind_service); bind_Service.setOnClickListener(this); messenger_Service=(Button)findViewById(R.id.messenger_service); messenger_Service.setOnClickListener(this); } @Override public void onClick(View v) { switch(v.getId()) { case R.id.intent_service: //启动IntentService Intent intentService=new Intent(this,IntentTestService.class); startService(intentService); break; case R.id.start_service: //start调用普通Sservice Intent startService=new Intent(this,NormalService.class); startService(startService); break; case R.id.bind_service: //bind调用service Intent bindService=new Intent(this,NormalService.class); if(bindService.resolveActivity(getPackageManager())!=null) bindService(bindService,connection,BIND_AUTO_CREATE); break;//利用Messenger进行跨进程通信 case R.id.messenger_service: if(!hasBound) { Intent intent = new Intent("com.skateboard.serverservice.service.BIND"); intent.setPackage("com.skateboard.serverservice"); bindService(intent, messengerConnection, Context.BIND_AUTO_CREATE); } else { sendMessageToServier(); } break; } } private ServiceConnection messengerConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { hasBound=true; serverMessenger=new Messenger(service); Message message=new Message(); message.what=233; message.replyTo=clientMessenger; try { serverMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { hasBound=false; } }; private ServiceConnection connection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { NormalService.NormalBinder binder= (NormalService.NormalBinder) service; binder.bindMethod(); } @Override public void onServiceDisconnected(ComponentName name) { } }; private void sendMessageToServier() { Message message=new Message(); message.what=233; message.replyTo=clientMessenger; try { serverMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); }}
IntentTestService继承子IntentService,它的功能很简单,就是打印一行话 “intent service start”。比较特别的就是就如如上所说的,这个service是运行在非主线程的。
public class IntentTestService extends IntentService { public IntentTestService() { super("IntentTestService"); } /** * Creates an IntentService. Invoked by your subclass's constructor. * * @param name Used to name the worker thread, important only for debugging. */ public IntentTestService(String name) { super(name); } @Override protected void onHandleIntent(Intent intent) { System.out.println("intent service start"); }}
NormalService可以接受startService()的方式启动同时也可以接受bindService的方式启动,这里主要讲讲bindService的启动方式,当我们bind到一个service的时候,回调用的onBind方法,这时会返回一个IBinder类,这个类个人觉得很想代理模式,通过它来调用service中的方法,在我们bindservice的时候,需要传入一个参数,ServiceConnection,在这个对象里面有两个回调方法,一个是ublic void onServiceConnected(ComponentName name, IBinder service)一个是public void onServiceDisconnected(ComponentName name),在onServiceConnected中的参数service就是我们在onBind方法中返回的IBinder,通过对它的转型,我们就可以调用相应的service中的方法了。所以这里我写了一个内部类NormalBinder,用它来打印“”bind method”并在onBind方法中返回他,这样我在MainActivity中就可以得到这个NormalBinder,并调用它内部的方法。
public class NormalService extends Service { public NormalService() { } @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("service start"); stopSelf(); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. NormalBinder normalBinder=new NormalBinder(); return normalBinder; } @Override public void onDestroy() { super.onDestroy(); System.out.println("stop service"); } public class NormalBinder extends Binder { public void bindMethod() { System.out.println("bind method"); } }}
对于这个流程,我本想画个示意图,但是太懒了,我决定还是文字吧。
跨进程通讯的方式有两种,一种是AIDL,一种就是利用Messenger了,这两种方式的区别就在鱼AIDL是多线程的,而Messenger是单线程的,也就是说利用Messenger的跨进程通信在消息队列中每次只有一个请求。需要注意的是如果你需要服务器回传数据给客户端,你需要在handler的public void handleMessage(Message msg)方法中得到客户端的Messenger,这个messenger就是Messenger clientMessenger=msg.replyTo;这是在客户端在向服务端发送Message的时候传递给message的参数。public class ServerService extends Service { private Handler handler=new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(msg.what==233) { Messenger clientMessenger=msg.replyTo; Message message=new Message(); message.what=322; try { clientMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } } }; private Messenger messenger=new Messenger(handler); public ServerService() { } @Override public void onCreate() { super.onCreate(); System.out.println("service create"); } @Override public IBinder onBind(Intent intent) { System.out.println("bind service"); return messenger.getBinder(); }}
接着MainAcitivyt发起bindService的请求,(这里要注意的是,5.0以后,开启service的Intent必需是显示的Intent,所以你的Intent里必须要包含另一个程序的包名的信息。)在ServiceConnection中的onServiceConnected的方法里,通过返回的IBinder来得到相应的Messenger
private ServiceConnection messengerConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { hasBound=true; serverMessenger=new Messenger(service); Message message=new Message(); message.what=233; message.replyTo=clientMessenger; try { serverMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { hasBound=false; } };
转载地址:http://jbls.baihongyu.com/