深入剖析Android四大组件(二)——Service服务之启动与绑定(二)

简介: 深入剖析Android四大组件(二)——Service服务之启动与绑定(二)

4.创建一个被绑定的服务


被绑定的服务是允许应用程序组件通过调用bindService()绑定的服务,目的在于创建一个长期的连接。


当我们想要这个服务与其他应用程序中的Activity交互时,创建一个被绑定的服务将是一个不错的选择。


想要创建一个被绑定的服务,则必须实现onBind()方法去返回与服务通信的接口对象(IBinder)。其他应用程序组件可以调用bindService()去检索服务提供的接口并且开始在服务中调用这些方法。服务只为绑定它的应用程序组件服务而活,因此,当没有组件绑定到这个服务的时候,系统会销毁它(在系统通过onStartCommand()来启动服务时,我们不需要停止一个绑定服务)


为创建一个被绑定的服务,必须要做的第一件事情是定义接口,该接口指定客户如何与该服务通信。服务和客户端之间的接口必须是一个IBinder的实现,它是服务从onBind()回调方法中返回的。一旦这个客户端收到IBinder,它能通过该接口与服务交互。


多个客户端能立刻绑定这个服务。当客户端完成与服务交互的时候,它调用unBindService()去解绑。一旦没有客户绑定到这个服务上,系统就会销毁该服务。


实现一个被绑定的服务有很多方法,它比实现被启动的服务更为复杂。


①基本介绍


被绑定的服务是Service类的一个实现,该类允许其他应用程序绑定到服务上并与之交互,为给服务提供绑定,我们必须实现onBind()回调方法。该方法返回一个IBinder对象,该对象定义了客户端可以用来与服务交互的编程接口。


客户端可以通过调用bindService()方法绑定到这个服务。当这样做的时候它必须提供ServiceConnection实现,该实现将监视与服务的连接。没有值的bindService()方法会立即返回,但当Android系统创建客户端与服务之间的连接时,我们会调用ServiceConnection中的onServiceConnected()方法来传递IBinder,而客户端可用IBinder来与服务通信。


多个客户端可立即连接到服务上,但是只有首个客户端被绑定的时候,系统才会调用服务的onBind()方法去检索IBinder。之后,系统交付相同的IBinder到绑定的任何额外客户端上,不用再次调用onBind()方法。


当最后的客户端从这个服务中解除绑定的时候,系统会销毁服务(除非该服务也是通过startService()方法启动的)。


当我们实现被绑定服务的时候,最重要的部分是定义onBind()回调方法返回的接口。定义服务的IBinder接口有几种方法,接下来将会介绍这些方法。


②LYJBoundService实例


前面我们讲述了被绑定服务的特性以及生命周期,现在来看一个完整的实例,通过这个实例,我们将深入理解如何定义AIDL并使用它来实现服务,具体步骤如下所示。


Ⅰ使用上面的LYJService项目,在”liyuanjing.example.com.lyjService“下添加IRemoteService.aidl文件以定义远程接口,相关代码如下所示:

package liyuanjing.example.com.lyjservice;
interface IRemoteService {
    int getPid();
}


当完成这个步骤时,我们的项目工程将会发生变化,Android工具将为我们编译出iRemoteService.java库。


Ⅱ创建一个名叫“LYJBoundService”的服务类,它继承自Service类。


这里我们需要完成以下两件事。


㈠实现Ⅰ中定义的接口。


㈡实现必要的服务生命周期回调函数,最重要的是需要实现onBind()接口


修改后的服务代码如下所示:


public class LYJBoundService extends Service {
    public LYJBoundService() {
    }
    //实现IRmeoteService中的getPid()接口
    IRemoteService.Stub mRemoteBinder=new IRemoteService.Stub(){
        @Override
        public int getPid() throws RemoteException {
            return android.os.Process.myPid();
        }
    };
    @Override
    public IBinder onBind(Intent intent) {
        //将mRemoteBinder通过此接口返回
        return mRemoteBinder;
    }
}

Ⅲ将LYJBoundService配置到AndroidManifest.xml文件中,并增加一个<service>节点,代码如下:

<service
    android:name=".LYJBoundService"
    android:enabled="true"
    android:exported="true" >
    <intent-filter>
        <action android:name="liyuanjing.example.com.boundservice.remote"/>
    </intent-filter>
</service>

Ⅳ修改默认的Activity使存在3个按钮,它们分别是“Bind Service”,"UnBind Service"和“Kill Service”,其中,只有当成功绑定到服务的时候,“UnBindService”按钮才变为用。修改后的代码如下所示:


布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:id="@+id/bind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Bind Service" />
    <Button
        android:id="@+id/unBind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="UnBind Service" />
    <Button
        android:id="@+id/kill"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Kill Service" />
</LinearLayout>

MainActivity:

public class MainActivity extends Activity implements View.OnClickListener{
    private final static String SERVICE_ACTION="liyuanjing.example.com.boundservice.remote";
    private static final String TAG="MainActivity";
    private Button bind;
    private Button unBind;
    private Button kill;
    private IRemoteService mIRemoteService;
    private ServiceConnection mServiceConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mIRemoteService=IRemoteService.Stub.asInterface(service);
            unBind.setEnabled(true);
            kill.setEnabled(true);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mIRemoteService=null;
            unBind.setEnabled(false);
            kill.setEnabled(false);
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final Intent intent=new Intent(SERVICE_ACTION);
        this.bind=(Button)findViewById(R.id.bind);
        this.unBind=(Button)findViewById(R.id.unBind);
        this.kill=(Button)findViewById(R.id.kill);
        this.bind.setOnClickListener(this);
        this.unBind.setOnClickListener(this);
        this.kill.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        int id=v.getId();
        switch (id){
            case R.id.bind:
                Intent intent=new Intent(SERVICE_ACTION);
                bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
                break;
            case R.id.unBind:
                if(mIRemoteService!=null){
                    try{
                        int pid=mIRemoteService.getPid();
                        Log.e(TAG,"Service_Pid = "+pid);
                        unbindService(mServiceConnection);
                    }catch(RemoteException e){
                        e.printStackTrace();
                    }
                }
                break;
            case R.id.kill:
                if(mIRemoteService!=null){
                    try{
                        int pid=mIRemoteService.getPid();
                        Log.e(TAG,"Service_Pid = "+pid);
                    }catch(RemoteException e){
                        e.printStackTrace();
                    }
                }
                break;
        }
    }
}

Ⅴ运行应用程序,先点击Bind Service,在点击unBind Service,最后点击Kill Service得到如下日志:

74.png

项目目录结构如下图:

75.png

相关文章
|
20天前
|
Java API 调度
Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播
Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播
41 0
|
21天前
|
Android开发
Android 11 添加Service服务SELinux问题
Android 11 添加Service服务SELinux问题
43 1
|
4天前
|
Java 开发工具 Android开发
如何在Eclipse中查看Android源码或者第三方组件包源码(转)
如何在Eclipse中查看Android源码或者第三方组件包源码(转)
13 4
|
21天前
|
Android开发
Android Service Call /dev/xxx SELinux
Android Service Call /dev/xxx SELinux
16 1
|
3天前
|
Android开发 数据库管理
Android如何在Activity和Service之间传递数据
Android如何在Activity和Service之间传递数据
10 3
|
7天前
|
Android开发
Android Service的两种使用方法
Android Service的两种使用方法
15 2
|
13天前
|
安全 网络安全 Android开发
云端防御策略:融合云服务与网络安全的未来构建高效的Android应用:从内存优化到电池寿命
【4月更文挑战第30天】 随着企业加速向云计算环境转移,数据和服务的云端托管成为常态。本文探讨了在动态且复杂的云服务场景下,如何构建和实施有效的网络安全措施来保障信息资产的安全。我们将分析云计算中存在的安全挑战,并展示通过多层次、多维度的安全框架来提升整体防护能力的方法。重点关注包括数据加密、身份认证、访问控制以及威胁检测与响应等关键技术的实践应用,旨在为读者提供一种结合最新技术进展的网络安全策略视角。 【4月更文挑战第30天】 在竞争激烈的移动市场中,Android应用的性能和资源管理已成为区分优秀与平庸的关键因素。本文深入探讨了提升Android应用效率的多个方面,包括内存优化策略、电池
|
22天前
|
设计模式 前端开发 数据库
构建高效Android应用:使用Jetpack架构组件实现MVVM模式
【4月更文挑战第21天】 在移动开发领域,构建一个既健壮又易于维护的Android应用是每个开发者的目标。随着项目复杂度的增加,传统的MVP或MVC架构往往难以应对快速变化的市场需求和复杂的业务逻辑。本文将探讨如何利用Android Jetpack中的架构组件来实施MVVM(Model-View-ViewModel)设计模式,旨在提供一个更加模块化、可测试且易于管理的代码结构。通过具体案例分析,我们将展示如何使用LiveData, ViewModel, 和Repository来实现界面与业务逻辑的分离,以及如何利用Room数据库进行持久化存储。最终,你将获得一个响应迅速、可扩展且符合现代软件工
25 0
|
10天前
|
存储 安全 Android开发
安卓应用开发:构建一个高效的用户登录系统
【5月更文挑战第3天】在移动应用开发中,用户登录系统的设计与实现是至关重要的一环。对于安卓平台而言,一个高效、安全且用户体验友好的登录系统能够显著提升应用的用户留存率和市场竞争力。本文将探讨在安卓平台上实现用户登录系统的最佳实践,包括对最新身份验证技术的应用、安全性考量以及性能优化策略。
|
13天前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比