深入剖析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

相关文章
|
1月前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
2月前
|
存储 Android开发 开发者
深入理解安卓应用开发的核心组件
【10月更文挑战第8天】探索Android应用开发的精髓,本文带你了解安卓核心组件的奥秘,包括Activity、Service、BroadcastReceiver和ContentProvider。我们将通过代码示例,揭示这些组件如何协同工作,构建出功能强大且响应迅速的应用程序。无论你是初学者还是资深开发者,这篇文章都将为你提供新的视角和深度知识。
|
2月前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
101 0
|
21天前
|
XML 搜索推荐 前端开发
安卓开发中的自定义视图:打造个性化UI组件
在安卓应用开发中,自定义视图是一种强大的工具,它允许开发者创造独一无二的用户界面元素,从而提升应用的外观和用户体验。本文将通过一个简单的自定义视图示例,引导你了解如何在安卓项目中实现自定义组件,并探讨其背后的技术原理。我们将从基础的View类讲起,逐步深入到绘图、事件处理以及性能优化等方面。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
2月前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
34 1
|
2月前
|
XML 前端开发 Java
安卓应用开发中的自定义View组件
【10月更文挑战第5天】自定义View是安卓应用开发的一块基石,它为开发者提供了无限的可能。通过掌握其原理和实现方法,可以创造出既美观又实用的用户界面。本文将引导你了解自定义View的创建过程,包括绘制技巧、事件处理以及性能优化等关键步骤。
|
2月前
|
测试技术 数据库 Android开发
深入解析Android架构组件——Jetpack的使用与实践
本文旨在探讨谷歌推出的Android架构组件——Jetpack,在现代Android开发中的应用。Jetpack作为一系列库和工具的集合,旨在帮助开发者更轻松地编写出健壮、可维护且性能优异的应用。通过详细解析各个组件如Lifecycle、ViewModel、LiveData等,我们将了解其原理和使用场景,并结合实例展示如何在实际项目中应用这些组件,提升开发效率和应用质量。
53 6
|
3月前
|
安全 API 开发工具
Android平台RTMP推送|轻量级RTSP服务如何实现麦克风|扬声器声音采集切换
Android平台扬声器播放声音的采集,在无纸化同屏等场景下,意义很大,早期低版本的Android设备,是没法直接采集扬声器audio的(从Android 10开始支持),所以,如果需要采集扬声器audio,需要先做系统版本判断,添加相应的权限。
|
3月前
|
编解码 开发工具 Android开发
Android平台实现屏幕录制(屏幕投影)|音频播放采集|麦克风采集并推送RTMP或轻量级RTSP服务
Android平台屏幕采集、音频播放声音采集、麦克风采集编码打包推送到RTMP和轻量级RTSP服务的相关技术实现,做成高稳定低延迟的同屏系统,还需要有配套好的RTMP、RTSP直播播放器
|
20天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
41 19