Android服务Service(二)
来源:互联网 发布:花溪区4g网络基站建设 编辑:程序博客网 时间:2024/05/21 10:24
1)前言
本文是接着上篇没有介绍完的Android服务Service写的,主要是想对Bound式服务做一个总结,从学Android到现在,我很少用到Bound式服务,倒是Started式服务用得不少(可能太菜),借着这个机会,结合官方文档案例对Bound式服务做一个全面的了解。
2)基本用法
一个绑定服务,就是一个实现了类Service,并允许其它应用程序与其绑定及与之交互的的组件。提供一个绑定服务,你必须实现onBind()方法,这个方法返回一个IBinder对象,这个对象就是定义用来客户端与服务交互的接口。
客户端通过bindService()方法绑定服务。另外,客户端还必须提供一个ServiceConnection的实现对象,用以监控与服务Service间的连接情况。bindService()无返回值,但系统在客户端与服务端连接之间,会调用在ServiceConnect对象中的onServiceConnected()方法,并传递一个客户端与服务端可以交互的IBinder接口。
多个客户端同时连接Service时,系统只在第一个客户端连接时调用你的onBind()方法并返回一个IBinder对象,系统在其他客户端进行连接时返回相同的IBinder对象,而不再去调用onBind().
当最后一个客户端调用与服务解除绑定时,系统将销毁服务,除非这个服务启动时,也调用了startService()方法.
创建绑定服务,必须提供IBinder接口,有三种方式定义这个接口:
- 1) 实现Binder类
如果这个service只是为当前应用服务,并且运行在相同的进程里,创建的接口必须继承Binder类,并且在onBind()方法中返回。客户可以通过它得到Binder对象,通过这个对象可以直接访问共有函数。
当service仅仅为自己的应用服务,这是首选技术。
- 2) 使用Messenger
如果需要接口在不同的进程间使用,可以用Messenger 为service类创建接口。用这种方式, service对处理不同的Message 对象定义了一个Handler. 这个Handler是Messenger的基础,可以与客户分享IBinder,允许客户用message发送命令到service上。补充点,客户端可以自定义Messenger,因此service可以发送消息回来。
这是在进程间通信最简单的方式。因为Messenger队列所有的请求发生在一个线程上,因此不需要考虑service的线程安全。
- 3) 使用AIDL
AIDL (Android Interface Definition Language) 可以把对象分解成系统能够识别的单元,已达到在进程间通信的能力。在前面的技术中,使用的messenger,实际上是以AIDL作为基础的结构。如上所述,Messenger在一个线程中创建了所有客户请求的一个队列。如果你想service能够同时处理多个请求,那么就可以直接用AIDL. 在这种案例中,service 必须要有处理多线程的能力,并且是线程安全的。
要想直接使用AIDL,必须创建定义程序的接口文件,后缀是.aidl。Android SDK工具可以通过这个文件生成一个实现了这个接口和处理IPC的抽象类,自定义的service需要继承自这个抽象类。
这种方式暂且不讨论
下面分别看下具体三种使用方法
3)实现Binder类
1、 在你的服务类中,创建一个满足下面条件的Binder实现类:
包含一个public方法,以便客户端可以调用
在一个public方法中返回当前服务实例给客户端使用
2、 在onBind()方法中,返回Binder对象实例
3、 在客户端,从onServiceConnected()回调方法接收Binder对象,并调用绑定服务中提供的方法。
下面来看下代码
//服务端public class BoundTest extends Service { private static final String TAG = "chen"; private IBinder iBinder = new LocalBinder(); private Random mGenerator = new Random(); public class LocalBinder extends Binder{ public BoundTest getService(){ return BoundTest.this; } } public int getRandomNumber() { return mGenerator.nextInt(100); } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate"); } @Override public IBinder onBind(Intent intent) { Log.i(TAG, "onBind"); return iBinder; } @Override public boolean onUnbind(Intent intent) { Log.i(TAG, "onUnbind"); return super.onUnbind(intent); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestory"); }}
我们可以看见在服务端LocalBinder是一个内部类,其继承了Binder,里面有个公共方法,返回该服务的实例。并且有一个getRandomNumber()测试方法,供客户端调用。
//客户端public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private Button btn_bound; private Button btn_unbound; private Button btn_getrandom; private BoundTest mService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_bound = (Button) findViewById(R.id.btn_bound); btn_unbound = (Button) findViewById(R.id.btn_unbound); btn_getrandom = (Button) findViewById(R.id.btn_getrandom); btn_bound.setOnClickListener(this); btn_unbound.setOnClickListener(this); btn_getrandom.setOnClickListener(this); } @Override public void onClick(View view) { Intent intent = null; switch (view.getId()){ case R.id.btn_bound: intent = new Intent(MainActivity.this, BoundTest.class); //绑定服务 bindService(intent, mConnection, Context.BIND_AUTO_CREATE); break; case R.id.btn_unbound: intent = new Intent(MainActivity.this, BoundTest.class); //解绑服务 unbindService(mConnection); break; case R.id.btn_getrandom: int number = mService.getRandomNumber(); btn_getrandom.setText("获取随机数"+number); break; } } private ServiceConnection mConnection = new ServiceConnection() { //绑定成功回调 @Override public void onServiceConnected(ComponentName className, IBinder service) { BoundTest.LocalBinder binder = (BoundTest.LocalBinder) service; mService = binder.getService(); //获取Binder对外提供的接口 } //绑定失败回调 @Override public void onServiceDisconnected(ComponentName arg0) { } };}//布局:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.chen.demo.MainActivity"> <Button android:id="@+id/btn_bound" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="绑定" /> <Button android:layout_marginTop="20dp" android:id="@+id/btn_unbound" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="解绑" /> <Button android:layout_marginTop="20dp" android:id="@+id/btn_getrandom" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="获取随机数" /></LinearLayout>
我们在客户端通过bindService()绑定服务,通过unbindService()解绑服务,其中bindService()需要三个参数意思分别是:
第一个变量是通过Intent指定要绑定的service.
第二个参数是 ServiceConnection 对象.
第三个参数是设置绑定的选项。通常是BIND_AUTO_CREATE,当service不在运行时,会自动创建。其他值有BIND_DEBUG_UNBIND 和BIND_NOT_FOREGROUND, 或者是0(没有任何意义).
而unbindService(),需要一个参数ServiceConnection
我们看下运行结果:
结果是最后一个Button的Text后面的数字
4)使用Messenger
如果service需要与远程的进程通讯,可以用Messenger为service提供一个接口。这种技术可以处理进程间的通讯。
下面是使用messenger的简介:
1)service 要实现Handler,它可以收到每一个client调用的回调。
2)Handler用于创建Messenger对象。 (which is a reference to the Handler).
3)Messenger创建一个IBinder,client调用onBind()时,IBinder要返回给client的
4)Clients 通过IBinder实例化Messenger(that references the service’s Handler),Messenger为了client发送Message对象到service。
5)service 通过Handler收到每一个Message, 在 handleMessage() 方法明确的处理.
利用这种方式,service中没有方法可一个被Client调用。client通过传递消息(messages)到service的Handler中。
我们简单看下服务端代码
//服务端public class MessengerService extends Service { private static final String TAG = "chen"; public static final int MSG_SAY_HELLO = 1; public class IncomingHandler extends Handler{ @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } final Messenger mMessenger = new Messenger(new IncomingHandler()); @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate"); } @Override public IBinder onBind(Intent intent) { Log.i(TAG, "onBind"); return mMessenger.getBinder(); } @Override public boolean onUnbind(Intent intent) { Log.i(TAG, "onUnbind"); return super.onUnbind(intent); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestory"); }}
注意:Handler 的handleMessage()方法收到Message,并且根据Message的what变量 确定需要做什么。
Client的需要实现的是,基于返回的IBinder创建Messenger对象,并且通过send()发送Message给service的Handler。
//客户端public class MessengerActivity extends AppCompatActivity implements View.OnClickListener{ private Button btn_bound; private Button btn_unbound; private Button btn_getrandom; Messenger mService = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_messenger); btn_bound = (Button) findViewById(R.id.btn_bound); btn_unbound = (Button) findViewById(R.id.btn_unbound); btn_getrandom = (Button) findViewById(R.id.btn_getrandom); btn_bound.setOnClickListener(this); btn_unbound.setOnClickListener(this); btn_getrandom.setOnClickListener(this); } @Override public void onClick(View view) { Intent intent = null; switch (view.getId()){ case R.id.btn_bound: intent = new Intent(MessengerActivity.this, MessengerService.class); //绑定服务 bindService(intent, mConnection, Context.BIND_AUTO_CREATE); break; case R.id.btn_unbound: //解绑服务 unbindService(mConnection); break; case R.id.btn_getrandom: Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } break; } } @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); } private ServiceConnection mConnection = new ServiceConnection() { //绑定成功回调 @Override public void onServiceConnected(ComponentName className, IBinder service) { mService = new Messenger(service); } //绑定失败回调 @Override public void onServiceDisconnected(ComponentName arg0) { } };}
注意: 这个例子没有体现service是如何响应client。如果想service响应client,需要在client里面创建一个Messenger。当client收到onServiceConnected()回调,就会发送Message到service,send()方法的Message变量replyTo包括客户端的Messenger,从而实现双向通讯。
看下运行结果:
这个Toast是服务端打印的结果。
5)生命周期管理
当service没有被任何的client绑定,android系统会杀死它(除非中途被其他的组件调用了onStartCommand())。按照这种原理, 绑定service是不需要管理它的生命周期的-android系统会根据绑定原则自动管理service。
然而,如果选择onStartCommand()方法实现,就必须明确的停止service,因为服务当前状态被认为是started。在这种案例下,service一直运行直到调用stopSelf()或者其他的组件调用stopService()方法,不管他绑定任何clients.这里的意思是说:当一个绑定service通过onStartCommand()启动,需要stopSelf()和stopService()方法来停止它,即使是中间绑定其他的客户端。
补充点,如果service已经启动并且接受了client的绑定,那么当系统调用onUnbind()方法时,如果想client下次绑定service的时候调用onRebind(),可以选择返回true,(而不是重新调用onBind()). onRebind() 返回 void, 但是client在onServiceConnected()还是接受IBinder. 下面的图阐明了上面的逻辑。
6)最后
服务基本内容也就这么多,还有一个AIDL没有介绍,下次准备结合Android Studio详细介绍下
7) Ref
1 )Android 官方文档
2 )http://blog.163.com/cazwxy_12/blog/static/898763720122106483898/
3 )http://blog.csdn.net/luhuajcdd/article/details/8756541
- Android Service 服务(二)
- Android服务Service(二)
- Android Service服务(二)
- Android Service服务(二)AIDL
- Android中Service服务详解(二)
- Android Service(服务)详解·(二)Service基本用法
- Android service(二)绑定服务
- Android Service(服务)
- Android服务(Service)
- Android 服务(Service)
- Android Service 服务(二)—— BroadcastReceiver
- Android Service 服务(二)—— BroadcastReceiver
- Android Service 服务(二)—— BroadcastReceiver
- (转)Android Service 服务(二)—— BroadcastReceiver
- android Service 服务(二)—— BroadcastReceiver
- Android Service 服务(二)—— BroadcastReceiver
- Android Service 服务(二)—— BroadcastReceiver
- Android Service 服务(二)—— BroadcastReceiver
- Android Studio插件整理
- freemarker
- 编写函数实现str函数
- WebView与JavaScript交互
- [转-收藏]CreateFileMapping用法
- Android服务Service(二)
- BAT怎么初始化样式
- 小型电商网站架构
- WinForm线程 - Thread
- 51nod 1420 数袋鼠好有趣【贪心】
- 【常用技能】为自己的U盘设置自定义图标
- JavaScript HTML DOM 对象(下)
- python3实现网络爬虫(5)--模拟浏览器抓取网页
- 关于代码重构Refactoring