android Service概要

本文介绍了Android Service的启动方式,包括startService和bindService,强调了两者的区别和应用场景。此外,还探讨了Service的生命周期及如何进行绑定与解绑。接着,文章引入了AIDL,解释了其在进程间通信中的作用,并给出了一种简单的AIDL使用示例,包括RemoteService和OtherApplication端的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

同前一章BroadcastReceiver一样,在这里不会讲解Service基本用法而只会提一些相对重要的重点

启动Service方式一般是通过方法startService(Intent service)和bindService(Intent service, ServiceConnection conn, int flags)调用从而启动。

在这里就简单介绍这两种方式调用的特点和特性

1.1 Activity第一次通过startService方法启动服务时,服务中的onCreate,onStartCommand方法会被依次调用.即便是调用服务的Activity销毁了,被启动的Service依然在后台运行,除非在Activity销毁之前调用了stopService方法。

1.2 Activity第一次通过bindService方法启动服务时,服务中的onCreate,onBind方法会被依次调用,调用服务的Activity销毁时,被启动的Service也会随之销毁。

1.3针对前两者就能发现他们的差别,有道是不求同时生,但求同时死,正是说的bindService方式启动服务。还有一点,必须在Activity的onStop方法中调用unbindService方法,否则会抛异常has leaked ServiceConnection

1.4通过bindService方法启动服务时,在服务中的onBind方法返回为null时,ServiceConnection 中的onServiceConnected方法则不会调用

1.5服务的绑定与解绑要一一对应,否则会抛异常

1.6通过bindService方式启动的服务,在设置->正在运行的进程中看不到,可以理解为一个隐形的服务

两种调用服务的混合搭配方案

2.1先调用startService方法开启服务,能够保证服务在后台长期运行

2.2调用bindService方法,可以获得中间对象Binder,这样就可以使调用者调用到服务内的方法。

2.3调用unbindService解绑服务,服务并不会销毁

2.4调用stopService销毁服务


说到Service,这里再引申另外一个话题就是aidl(进程间通信),对于android中aidl的定义网上大把的资料,用法也能找到经典的demo,我这里只是用自己的表达方式概述一下。

问:为什么会要有aidl,经典的实例场景是怎样的?

答:像我们所熟知的,微信,支付宝等这些支付软件都带有各自的支付接口,如果第三方应用软件,需要调用他们的接口时,就得通过进程间通信方式打开支付窗口进行扫码支付,等等!

我这里就简单的介绍一下aidi在android studio 开发工具中开发的过程(我这里强调了是在android studio中,而不是eclipse,因为这两种IDE修改的方式不一样,然后随着android studio 3.0发布,发现目前很多android开发人员开始使用android studio)

RemoteService端

先创建aidl文件,这一步跟eclipse的方式完全不同的,在eclipse中我的习惯操作是先定义一个interface的java文件,定义好接口之后再将java的文件的后缀改成aidl,由于aidl的语法跟java语法存在差异,所以改完文件后缀之后还不能直接用,还需要将文件内不能识别的标示给删除,如public,class等(这里针对在eclipse创建aidl多说了几句,有兴趣的可以在网上搜索用eclipse开发aidl的demo)。下面看一下android studio里的创建方式



在aidl文件中添加了对应的接口方法之后,make一下工程,就可以看到开发工具会生成一个对应文件名的java文件



PublicAidlInterface.aidl

// PublicAidlInterface.aidl
package sz.antier.remoteservice;

// Declare any non-default types here with import statements

interface PublicAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    void zhiFu();
}

MyService.java

package sz.antier.remoteservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class MyService extends Service {
    private static final String TAG = "antier";

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Log.e(TAG,"onBind");
        return new MyBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG,"onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG,"onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG,"onDestroy");
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        Log.e(TAG,"onRebind");
    }

    class MyBinder extends PublicAidlInterface.Stub{

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public void zhiFu() throws RemoteException {
            saoma();
        }
    }

    private void saoma(){
        Log.e("antier","支付完成");
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="sz.antier.remoteservice">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="sz.antier.service" />
            </intent-filter>
        </service>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"></action>
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

在RemoteService应用端再多强调两个地方,因为第三方应用程序调用它的服务接口时,一定要配置正确的。

1.RemoteService应用的包名:sz.antier.remoteservice

2.service中的action name: sz.antier.service

备注:这个名字可以随意定,我这里只是一个简单的demo而已


OtherApplication端

先将remoteService中aidl目录拷贝过来


MainActivity.java

package sz.antier.otherapplication;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import sz.antier.remoteservice.PublicAidlInterface;

public class MainActivity extends AppCompatActivity {

    private PublicAidlInterface aidlInterface;
    private Intent remoteIntent;
    private MyServiceConnection connection;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        remoteIntent = new Intent();
        remoteIntent.setPackage("sz.antier.remoteservice");
        remoteIntent.setAction("sz.antier.service");
    }

    public void onClickStartServiceButton(View view){
        this.startService(remoteIntent);
    }

    public void onClickBindServiceButton(View view){
        connection = new MyServiceConnection();
        this.bindService(remoteIntent,connection, BIND_AUTO_CREATE);
    }

    public void onClickPayButton(View view){
        try {
            aidlInterface.zhiFu();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    class MyServiceConnection implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            aidlInterface = PublicAidlInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if(connection!=null) {
            this.unbindService(connection);
        }
    }

}

这在这里又要多啰嗦两句,在创建remoteIntent时,配置了对应的action,package参数(知道前面我为什么要用红色标注的良苦用心了吧),从android6.0之后必须这样配置了,在之前,只需要配置action,其实现在想想看看,package的配置确实是有必要的,要不然,遇到多个应用程序有相同的action时,那就尴尬了。


好了,这就是一个超级简单的进程间通信的demo了,您若觉得有帮助,别忘了6666......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值