android中使用AIDL来启动外部程序的service

本文介绍了如何使用AIDL(Android Interface Define Language)从一个Android应用启动另一个应用的定时器服务。详细步骤包括创建AIDL文件、实现回调方法、在Service中绑定接口以及在不同应用间进行通信。

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

AIDL全称是Android Interface Define Language。即android接口定义语言。使用AIDL可以从一个应用内启动外部应用的服务。下面我们通过具体的例子来看看怎么使用:在AndroidStudio的工程中建立两个module,从一个module中启动另一个的定时器服务。
1. 首先在AndroidStudio中创建一个项目,再在项目中创建另一个module称为timer。
2. 在module名上点击右键选择新建AIDl file 创建好后rebuild一下project。创建AIDL文件
3. 这是AIDL的代码

// ITimerServiceAidlInterface.aidl
package com.chaoyang805.timer;
// Declare any non-default types here with import statements
import com.chaoyang805.timer.ITimerCallback;
interface ITimerServiceAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void startTimer(int value);
    void registerCallback(ITimerCallback callback);
    void unregisterCallback();
}

方法registerCallback依赖于另一个AIDL文件,下面是这个AIDL的代码

// ITimerCallback.aidl
package com.chaoyang805.timer;

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

interface ITimerCallback {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void onUpdate(int value);
}

很明显,这是一个回调方法,定时器更新时将最新的时间传递出去。下面我们来看看怎么在service里实现这个回调。在timer中创建一个定时器的service,在service类中的onBind方法返回这个接口的stub对象。下面是service的代码

package com.chaoyang805.timer;

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

public class TimerService extends Service {


    /**
     * 默认从100开始倒计时
     */
    private int mInitialValue = 100;
    /**
     * 是否在运行
     */
    private boolean isRunning = false;

    /**
     * 倒计时的线程
     */
    private Thread mTimerThread;

    private ITimerCallback mCallback;

    private ITimerServiceAidlInterface.Stub mTimerBinder = new ITimerServiceAidlInterface.Stub() {

        /**
         * 启动线程来开启定时器
         * @param value
         */
        @Override
        public void startTimer(int value) {
            if (!mTimerThread.isAlive()) {
                mInitialValue = value;
                mTimerThread.start();
                isRunning = true;
            }
        }

        /**
         * 注册回调
         * @param callback
         * @throws RemoteException
         */
        @Override
        public void registerCallback(ITimerCallback callback) throws RemoteException {
            mCallback = callback;
        }

        /**
         * 注销回调
         * @throws RemoteException
         */
        @Override
        public void unregisterCallback() throws RemoteException {
            mCallback = null;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return mTimerBinder;
    }

    /**
     * 服务绑定时初始化标志位和线程
     */
    @Override
    public void onCreate() {
        super.onCreate();
        isRunning = true;
        mTimerThread = new Thread(mTimerRunnable);
    }

    /**
     * 服务销毁时停止定时器
     */
    @Override
    public void onDestroy() {
        isRunning = false;
    }

    /**
     *  在runnable里实现定时器功能
     */
    private Runnable mTimerRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (isRunning && mInitialValue > 0) {
                    if (mCallback != null) {
                        mCallback.onUpdate(mInitialValue);
                    }
                    Thread.sleep(1000);
                    mInitialValue--;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    };
}

在service的onBind()方法返回值我们返回了ITimerServiceAidlInterface的对象,并且实现了这个接口的方法,里面的public void registerCallback(ITimerCallback callback)unregisterCallback()就是用来注册和取消回调的,在runnable中通过调用回调方法来将数据传递出去。从上面的过程我们可以看出如果在AIDL中想要实现回调,必须要再定义一个AIDL接口来定义回调的方法,通过在原AIDL文件中添加一个注册和注销回调的方法来实现,需要注意的是,AIDL中用到的对象类必须手动进行导入。
4. 下面我们来看看如何在另一个app中来启动这个广播并添加回调。
第一步要做的就是要将之前定义的两个AIDL文件连同所在的包拷贝到当前module中去,如图
这里写图片描述
两个module的包名和文件名必须一致。
5. 然后rebuild project,来看看MainActivity的代码

package com.chaoyang805.useexternaltimerservice;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.chaoyang805.timer.ITimerCallback;
import com.chaoyang805.timer.ITimerServiceAidlInterface;

public class MainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection {

    /**
     * 远程服务所在包名
     */
    private static final String PKG_NAME = "com.chaoyang805.timer";
    /**
     * 远程服务的类名
     */
    private static final String CLASS_NAME = "com.chaoyang805.timer.TimerService";
    /**
     * 显示倒计时的textview
     */
    private TextView mTvTimer;
    /**
     * 获取起始时间的输入框
     */
    private EditText mEtGetValue;
    /**
     * 是否绑定服务的标志位
     */
    private boolean isServiceBinded = false;
    /**
     * 与远程㐏进行通信的binder对象
     */
    private ITimerServiceAidlInterface mTimerBinder;
    /**
     * 远程服务数据更新时的回调
     */
    private ITimerCallback mCallback;
    /**
     * 更新UI的handler
     */
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            mTvTimer.setText(msg.what + "");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    /**
     * 初始化view
     */
    private void initViews() {
        mEtGetValue = (EditText) findViewById(R.id.et_get_value);
        mTvTimer = (TextView) findViewById(R.id.tv_timer);
        findViewById(R.id.btn_start_external_timer).setOnClickListener(this);
        findViewById(R.id.btn_stop_external_timer).setOnClickListener(this);
    }

    /**
     * 按键的监听事件
     *
     * @param v
     */
    @Override
    public void onClick(View v) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(PKG_NAME, CLASS_NAME));
        switch (v.getId()) {
            case R.id.btn_start_external_timer:
                if (TextUtils.isEmpty(mEtGetValue.getText())) {
                    Toast.makeText(this,"请输入倒计时的时间",Toast.LENGTH_SHORT).show();
                    return;
                }
                //绑定远程服务
                bindService(intent, this, Context.BIND_AUTO_CREATE);
                break;
            case R.id.btn_stop_external_timer:
                //接触绑定服务
                unbindService();
                break;
        }

    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        try {
            //取得binder对象
            mTimerBinder = ITimerServiceAidlInterface.Stub.asInterface(service);
            isServiceBinded = true;
            //实例化回调
            mCallback = new ITimerCallback.Stub() {
                @Override
                public void onUpdate(int value) throws RemoteException {
                    //通过handler来更新UI
                    mHandler.sendEmptyMessage(value);
                }
            };
            //注册回调
            mTimerBinder.registerCallback(mCallback);
            //开启定时器
            startTimer();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    /**
     * 启动远程定时器
     */
    private void startTimer() {
        try {
            int value = Integer.parseInt(mEtGetValue.getText().toString());
            mTimerBinder.startTimer(value);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    /**
     * 服务断开时对标志位进行更改
     *
     * @param name
     */
    @Override
    public void onServiceDisconnected(ComponentName name) {
        isServiceBinded = false;
    }

    /**
     * activity销毁时注销回调并取消绑定服务
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService();
    }

    /**
     * 销毁时注销回调并取消绑定服务
     */
    private void unbindService() {
        if (isServiceBinded) {
            try {
                mTimerBinder.unregisterCallback();
                unbindService(this);
                isServiceBinded = false;
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}

在MainActivity中我们通过声明显示intent Intent intent = new Intent();
intent.setComponent(new ComponentName(PKG_NAME, CLASS_NAME));
实现了绑定外部service,但怎么与其进行通信呢?这就要用到AIDL了。来看一下onServiceConnected的代码

@Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        try {
            //取得binder对象
            mTimerBinder = ITimerServiceAidlInterface.Stub.asInterface(service);
            isServiceBinded = true;
            //实例化回调
            mCallback = new ITimerCallback.Stub() {
                @Override
                public void onUpdate(int value) throws RemoteException {
                    //通过handler来更新UI
                    mHandler.sendEmptyMessage(value);
                }
            };
            //注册回调
            mTimerBinder.registerCallback(mCallback);
            //开启定时器
            startTimer();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

通过mTimerBinder = ITimerServiceAidlInterface.Stub.asInterface(service);来获得ITimerServiceAidlInterface对象,这样我们就可以调用其中的方法来实现回调或是启动定时器。这就和同一app中service通信相差无几了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值