天天看点

Android AIDL 的简单使用本文完整项目目标项目结构运行截图实现

Android AIDL 的简单使用

  • 本文完整项目
  • 目标
  • 项目结构
  • 运行截图
  • 实现
    • ----app1
    • ----app2

本文完整项目

链接:

https://download.csdn.net/download/yancr/12739358

链接(老版本):

https://download.csdn.net/download/yancr/11082932

目标

1. A 应用向 B 应用发送两个数字

2. B 应用展示两个数字的和

3. A 应用向B应用获取两个数字的和

项目结构

Android AIDL 的简单使用本文完整项目目标项目结构运行截图实现

运行截图

  1. 应用A初始界面
    Android AIDL 的简单使用本文完整项目目标项目结构运行截图实现
  2. 应用B初始界面
    Android AIDL 的简单使用本文完整项目目标项目结构运行截图实现
  3. 应用B生成随机数并发送
    Android AIDL 的简单使用本文完整项目目标项目结构运行截图实现
  4. 应用A接收到随机数并计算和
    Android AIDL 的简单使用本文完整项目目标项目结构运行截图实现
  5. 应用B获取应用A的计算结果
    Android AIDL 的简单使用本文完整项目目标项目结构运行截图实现

实现

以下未列出的文件,未做特殊修改。代码如果有不规范请不要在意。

没写很多注释,不过应该很容易看懂的。

----app1

文件1,AIDL 接口文件,app2 通过调用 app1 提供的接口与 app1 进行通信。

接口中支持的变量类型只有 int、long、char、boolean、double、String、CharSequence、List Map must be ArrayList HashMap、Parcelable。

若要其他类型需要使用 import 进行声明,如 import com.ycr.aidlserver.Person,而 public class Person implements Parcelable。

// SendTwoNumbersManager.aidl
package com.ycr.app1;

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

interface SendTwoNumbersManager {
    /**
     * 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);
    //app1 gives the interface to app2, with which app2 send two numbers to app1
    void sendTwoNumbers(int a1, int a2);
    //app1 gives the interface to app2, with which app2 is able to get plus result from app1
    int getResult();
}

           

文件2,app1 的主界面,提供一个 TextView 进行数据的展示。

为了 Activity 与 Service 的通信,使用了 LiveData,LiveData 作为 ViewModel 的成员变量存在。

package com.ycr.app1;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private TextView iTV;
    private ServiceToActivityViewModel viewModel;
    private Observer<Integer> newValueObserver;

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

        iTV = findViewById(R.id.iTV);
        iTV.setOnClickListener(this);

        viewModel = ServiceToActivityViewModel.get(getApplication());
        newValueObserver = new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                Log.e("app1", integer + "");
                iTV.setText(String.valueOf(integer));
            }
        };
        viewModel.getNewValue().observe(this, newValueObserver);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        viewModel.getNewValue().removeObserver(newValueObserver);
    }

    @Override
    public void onClick(View v) {
    }
}
           

文件3,app1 提供给 app2 使用的服务,服务中使用匿名类对 AIDL 接口进行了实现。

package com.ycr.app1;

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

public class GetTwoNumbersService extends Service {
    private int result;
    private ServiceToActivityViewModel viewModel;
    private final SendTwoNumbersManager.Stub sendTwoNumbersManager = new SendTwoNumbersManager.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) { }

        @Override
        public void sendTwoNumbers(int a1, int a2) {
            Log.e("app1", "add");
            synchronized (this) {
                result = a1 + a2;
                viewModel.getNewValue().postValue(result);
            }
        }

        @Override
        public int getResult() {
            return result;
        }
    };

    public GetTwoNumbersService() {
    }
    @Override
    public IBinder onBind(Intent intent) {
        if("com.ycr.app1".equals(intent.getAction())) {
            if(viewModel == null) {
                Log.e("app2-app1", getApplication().getPackageName());
                viewModel = ServiceToActivityViewModel.get(getApplication());
            }
            return sendTwoNumbersManager;
        }
        return null;
    }
}

           

文件4,ViewModel,用于存放 LiveData,Activity 中注册 Observer,当Service 使用 set 改变LiveData,则 Activity 中的 Observer 会收到 onChanged 回调。

package com.ycr.app1;

import android.app.Application;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;

public class ServiceToActivityViewModel extends ViewModel {
    private static ServiceToActivityViewModel viewModel = null;
    private MutableLiveData<Integer> newValue;

    public MutableLiveData<Integer> getNewValue() {
        if(newValue == null) {
            newValue = new MutableLiveData<>();
        }
        return newValue;
    }
    synchronized static ServiceToActivityViewModel get(Application application) {
        if(viewModel == null) {
            viewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(application).create(ServiceToActivityViewModel.class);
        }
        return viewModel;
    }
}

           

文件5,Manifest 文件,主要修改了 启动 (bind) 服务的action 和 category。

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <service
            android:name=".GetTwoNumbersService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.ycr.app1" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

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

</manifest>
           

----app2

文件1,app2 的主界面,通过 bind 连接到 app1 的服务,而后 app1 返回的 IBinder 接口 即是 AIDL 接口。app2可以通过这个接口与 app1 进行通信。

package com.ycr.app2;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.ycr.app1.SendTwoNumbersManager;

import java.util.Random;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private TextView iTV;
    private Button getResultBtn;
    private Random random;
    private SendTwoNumbersManager sendMsendTwoNumbersManagernager;
    private boolean isConnect;
    private ServiceConnection serviceConnection;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        random = new Random(System.currentTimeMillis());
        isConnect = false;

        iTV = findViewById(R.id.iTV);
        iTV.setOnClickListener(this);

        getResultBtn = findViewById(R.id.getResultBtn);
        getResultBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if(v.equals(iTV)) {
            if (!isConnect) {
                iTV.setText("Not Connected. Connecting.");
                serviceConnection = new ServiceConnection() {
                    @Override
                    public void onServiceConnected(ComponentName name, IBinder service) {
                        isConnect = true;
                        sendMsendTwoNumbersManagernager = SendTwoNumbersManager.Stub.asInterface(service);
                        iTV.setText("Connected");
                    }

                    @Override
                    public void onServiceDisconnected(ComponentName name) {
                        isConnect = false;
                    }
                };
                Intent intent = new Intent();
                intent.setPackage("com.ycr.app1");
                intent.setAction("com.ycr.app1");
                bindService(intent, serviceConnection, BIND_AUTO_CREATE);
            }
            if (isConnect) {
                int a1 = random.nextInt(20);
                int a2 = random.nextInt(20);
                iTV.setText(a1 + " + " + a2);
                try {
                    sendMsendTwoNumbersManagernager.sendTwoNumbers(a1, a2);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        } else if(v.equals(getResultBtn)) {
            int result = 0;
            if(sendMsendTwoNumbersManagernager != null && isConnect) {
                try {
                    result = sendMsendTwoNumbersManagernager.getResult();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            iTV.setText(String.valueOf(result));
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(isConnect) {
            unbindService(serviceConnection);
        }
    }
}