服务 Service -aidl应用

为了让远程Service与多个应用程序的组件(四大组件)进行跨进程通信(IPC),需要使用AIDL

IPC:Inter-Process Communication,即跨进程通信
AIDL:Android Interface Definition Language,即Android接口定义语言;用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。

在多进程通信中,存在两个进程角色(以最简单的为例):服务器端和客户端
以下是两个进程角色的具体使用步骤:
服务器端(Service)
步骤1:新建定义AIDL文件,并声明该服务需要向客户端提供的接口
步骤2:在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法(onCreat、onBind()、blabla)
步骤3:在AndroidMainfest.xml中注册服务 & 声明为远程服务

客户端(Client)
步骤1:拷贝服务端的AIDL文件到目录下
步骤2:使用Stub.asInterface接口获取服务器的Binder,根据需要调用服务提供的接口方法
步骤3:通过Intent指定服务端的服务名称和所在包,绑定远程Service

接下来,我将用一个具体实例来介绍远程Service的使用
一、服务端:
1、新建aidl文件

// IOrderManagerInterface.aidl
package com.htkj.service.aidl;
import com.htkj.service.bean.OrderBean;

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

interface IOrderManagerInterface {
    /**
     * 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);
    List<OrderBean> getAll();
    void add(in OrderBean bean);
}

添加aidl文件后,build工程,在build文件中自动生成代码:
在这里插入图片描述

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.htkj.service.aidl;
// Declare any non-default types here with import statements

public interface IOrderManagerInterface extends android.os.IInterface
{
  /** Default implementation for IOrderManagerInterface. */
  public static class Default implements com.htkj.service.aidl.IOrderManagerInterface
  {
    /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
    @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
    {
    }
    @Override public java.util.List<com.htkj.service.bean.OrderBean> getAll() throws android.os.RemoteException
    {
      return null;
    }
    @Override public void add(com.htkj.service.bean.OrderBean bean) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.htkj.service.aidl.IOrderManagerInterface
  {
    private static final java.lang.String DESCRIPTOR = "com.htkj.service.aidl.IOrderManagerInterface";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.htkj.service.aidl.IOrderManagerInterface interface,
     * generating a proxy if needed.
     */
    public static com.htkj.service.aidl.IOrderManagerInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.htkj.service.aidl.IOrderManagerInterface))) {
        return ((com.htkj.service.aidl.IOrderManagerInterface)iin);
      }
      return new com.htkj.service.aidl.IOrderManagerInterface.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_basicTypes:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          long _arg1;
          _arg1 = data.readLong();
          boolean _arg2;
          _arg2 = (0!=data.readInt());
          float _arg3;
          _arg3 = data.readFloat();
          double _arg4;
          _arg4 = data.readDouble();
          java.lang.String _arg5;
          _arg5 = data.readString();
          this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_getAll:
        {
          data.enforceInterface(descriptor);
          java.util.List<com.htkj.service.bean.OrderBean> _result = this.getAll();
          reply.writeNoException();
          reply.writeTypedList(_result);
          return true;
        }
        case TRANSACTION_add:
        {
          data.enforceInterface(descriptor);
          com.htkj.service.bean.OrderBean _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.htkj.service.bean.OrderBean.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.add(_arg0);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.htkj.service.aidl.IOrderManagerInterface
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      /**
           * Demonstrates some basic types that you can use as parameters
           * and return values in AIDL.
           */
      @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(anInt);
          _data.writeLong(aLong);
          _data.writeInt(((aBoolean)?(1):(0)));
          _data.writeFloat(aFloat);
          _data.writeDouble(aDouble);
          _data.writeString(aString);
          boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public java.util.List<com.htkj.service.bean.OrderBean> getAll() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.util.List<com.htkj.service.bean.OrderBean> _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getAll, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getAll();
          }
          _reply.readException();
          _result = _reply.createTypedArrayList(com.htkj.service.bean.OrderBean.CREATOR);
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void add(com.htkj.service.bean.OrderBean bean) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((bean!=null)) {
            _data.writeInt(1);
            bean.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().add(bean);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.htkj.service.aidl.IOrderManagerInterface sDefaultImpl;
    }
    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getAll = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    public static boolean setDefaultImpl(com.htkj.service.aidl.IOrderManagerInterface impl) {
      if (Stub.Proxy.sDefaultImpl == null && impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.htkj.service.aidl.IOrderManagerInterface getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  /**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.
       */
  public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
  public java.util.List<com.htkj.service.bean.OrderBean> getAll() throws android.os.RemoteException;
  public void add(com.htkj.service.bean.OrderBean bean) throws android.os.RemoteException;
}

上述代码是系统自动生成的,在build目录下,可以到根据IOrderManagerInterface.aidl系统为我们生成了IOrderManagerInterface.java这个类,它继承了IInterface这个接口,同时它自己也还是个接口,所有可以在Binder中传输的接口都需要继承IInterface接口。这个类刚开始看起来逻辑混乱,但是实际上还是很清晰的,通过它我们可以清楚地了解到Binder的工作机制。这个类的结构其实很简单,首先,它声明了两个方法getAll()和add(),显然这就是我们在IOrderManagerInterface.aidl中所生命的方法,同时它还声明 了两个整型的id分别用于标识这两个方法,这个两个id用于标识在transact过程中客户端所请求的到底是哪个方法。接着,它声明了一个内部类Stub,这个Stub就是一个Binder类,当客户端和服务端都位于同一个进程时,方法调用不会走跨进程的transact过程,而当两者位于不同进程时,方法调用需要走transact过程,这个逻辑由Stub的内部代理类Proxy来完成。这么来看,IOrderManagerInterface这个接口的确很简单,但是我们也应该认识到,这个接口的核心实现就是它内部类Stub和Stub的内部代理类Proxy,下面详细介绍针对这两个类的每个方法的含义。

DESCRIPTOR

private static final java.lang.String DESCRIPTOR = "com.htkj.service.aidl.IOrderManagerInterface";
Binder的唯一标识,一般用当前Binder的类名表示,比如本例中“com.htkj.service.aidl.IOrderManagerInterface”。

asInterface(android.os.IBinder obj)
用于讲服务端的BInder对象转成客户端所需要的AIDL接口类型对象,这种转换过程时区分进程的,如果客户端和服务端位于同一个进程,那么此方法返回的就是服务端的Stub对象本身,否则返回的是系统封装后的Stub.proxy对象。

asBinder
此方法用于返回当前Binder对象

onTransact
这个方法运行在服务端中Binder线程池中,当客户端发起跨进程请求时,云端请求会通过系统底层封装后交由此方法来处理。该方法的原型为public Boolean onTransact(int code,android.os.Parcel data,android.os.Parcel reply,int flags)。服务端通过code可以确定客户端所请求的目标方法时什么,接着从data中取出目标方法所需的参数(如果目标方法有参数的话),然后执行目标方法。当目标方法执行完毕后,就向reply中写入返回值(如果目标方法有返回值的话),onTransact方法的执行过程就是这样的。需要注意的是,如果此方法返回false,那么客户端的请求会失败,因此我们可以利用这个特性来做权限验证,毕竟我们也不希望随便一个进程都能远程调用我们的服务。

Proxy#getAll()
这个方法运行在客户端,当客户端远程调用此方法时,它的内部实现是这样的:首先创建该方法所需要的输入型Parcel对象_data、输出型Parcel对象_reply和返回值对象List;然后把该方法的参数信息写入_data中(如果有参数的话);接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起;然后服务端的onTransact方法会被调用,直到RPC过程返回,当前线程继续执行,并从_reply中取出RPC过程的返回结果;最后返回_reply中数据。

Proxy#add()
这个方法运行在客户端,它的执行过程和getall()是一样的,add()没有返回值,所以它不需要从_reply中取出返回值。

通过上面的分析,了解了Binder的工作机制,但是有两点还是需要额外说明一下:首先,当客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远测方法时很耗时的,那么不能在UI线程中发起此远程请求;其次,由于服务端的Binder方法运行在Binder的线程池中,所以Binder方法不管是否耗时都应该采用同步的方式去实现,因为它已经运行在一个线程中了。BInder的工作机制图如下:
在这里插入图片描述
接下来,介绍Binder的两个很重要的方法,linkToDeath和unlinkToDeath。我们知道,Binder运行在服务端进程,如果服务端进程由于某种原因异常终止,这个时候我们到服务端的Binder连接断裂(称之为Binder死亡),会导致我们的远程调用失败。更关键的是,如果我们不知道Binder连接已经断裂,那么客户端的功能就会收到影响。为了解决这个问题,Binder中提供了两个配对的方法linkToDeath 和 unlinkToDeath ,通过linkToDeath我们可以给Binder设置一个死亡代理,当Binder死亡时,我们就会收到通知,这个时候我们就可以重新发起连接清酒从而恢复连接。
首先,声明一个DeathRecipient对象。DeathRecipient是一个接口,其内部只有一个方法bindDeath,我们需要实现这个方法,当Binder死亡的时候,系统就会回调bindDeath方法,然后我们就可以移除之前绑定的binder代理并重新绑定远程服务:
//代码后面补充
其次,在呼呼段绑定远程服务成功后,给binder设置死亡代码:
//代码后面补充。
其中linkToDeath的第二个参数是个标记位,我们直接设为0即可。经过删改你两个步骤,就给我们的Binder设置了死亡代理,当Binder死亡的时候我们就可以收到通知了。另外,通过Binder的方法isBinderAlive也可以判断Binder是否死亡。

2、添加bean数据

package com.htkj.service.bean;

import android.os.Parcel;
import android.os.Parcelable;

public class OrderBean implements Parcelable {
    private String id;
    private String name;
    private int amount;

    public OrderBean(){}

    public OrderBean(String id, String name, int amount) {
        this.id = id;
        this.name = name;
        this.amount = amount;
    }

    public String getId() {
        return this.id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAmount() {
        return this.amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }


    protected OrderBean(Parcel in) {
        id = in.readString();
        name = in.readString();
        amount = in.readInt();
    }

    public static final Creator<OrderBean> CREATOR = new Creator<OrderBean>() {
        @Override
        public OrderBean createFromParcel(Parcel in) {
            return new OrderBean(in);
        }

        @Override
        public OrderBean[] newArray(int size) {
            return new OrderBean[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(id);
        dest.writeString(name);
        dest.writeInt(amount);
    }
}

3、因为bean数据实现Parcelable 接口,需要在bean相关的包名下面添加同名aidl文件。(例如本例中bean名称为OrderBean.java,该类实现Parcelable 接口,该类所在的包名为com.htkj.service.bean,即需要在com.htkj.service.bean包名下添加OrderBean.aidl文件)

// OrderBean.aidl
package com.htkj.service.bean;
parcelable OrderBean;

3、在AndroidManifest.xml中添加以下代码

<service
            android:name=".service.OrderService"
            android:enabled="true">
            <intent-filter>
                <action android:name="com.htkj.lenrning.service.OrderService"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>

        </service>

以上服务端代码结束。
在这里插入图片描述
二、客户端
1、将服务端IOrderManagerInterface.aidl、OrderBean.java、OrderBean.aid三个文件复制到客户端模块,注意包名需要与服务端一样。
2、客户端绑定服务:

package com.htkj.jni.aidlclient;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.htkj.adapter.OrderAdapter;
import com.htkj.service.aidl.IOrderManagerInterface;
import com.htkj.service.bean.OrderBean;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.ListView;

import java.util.List;
import java.util.Random;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private List<OrderBean> orderList;
    private IOrderManagerInterface orderManagerInterface;

    //UI
    private Button search_button;
    private Button add_button;
    private ListView listView;
    private OrderAdapter adapter;

   
    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //客户端与服务连接成功后,自动进入到该方法
            Log.i("MainActivity.conn","@@ onServiceConnected name="+name);
            IOrderManagerInterface manager = IOrderManagerInterface.Stub.asInterface(service);
            orderManagerInterface = manager;
            refreshOrderList();
            try {
                service.linkToDeath(deathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            //当服务异常断开后,自动进入该方法
            Log.i("MainActivity.conn","@@ onServiceDisconnected name="+name);
        }
    };

    IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            if (orderManagerInterface == null) {
                Log.i("MainActivity","@@ binderDied "+(orderManagerInterface==null));
                return;
            }
            orderManagerInterface.asBinder().unlinkToDeath(deathRecipient,0);
            orderManagerInterface = null;
            bindOrderService();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("MainActivity","@@ onCreate");
        setContentView(R.layout.activity_main);
        getLayoutInflater();
        //view
        search_button=findViewById(R.id.search_button);
        add_button=findViewById(R.id.add_button);
        listView=findViewById(R.id.listView);
        //组装recyclerView
        LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        adapter=new OrderAdapter(this);
        listView.setAdapter(adapter);
        //onclick
        search_button.setOnClickListener(this);
        add_button.setOnClickListener(this);
        //bind
        bindOrderService();

    }
    
    //绑定服务
    private void bindOrderService(){
        //服务端服务类完整路径
        Intent intent = new Intent("com.htkj.lenrning.service.OrderService");
        //服务端应用包名
        intent.setPackage("com.htkj.lenrning");
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }
    /**
     * 重新获取数据并刷新列表。
     */
    private void refreshOrderList(){
        try {
            if(orderManagerInterface!=null){
                orderList = orderManagerInterface.getAll();
                int size = orderList.size();
                for(int i = 0; i < size; i ++ ) {
                    Log.d("lili","i = " + i + "id = " + orderList.get(i).getId() + "name =" + orderList.get(i).getName());
                }
            }
            if(orderList!=null){
                adapter.setData(orderList);
                adapter.notifyDataSetChanged();
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onClick(View v) {
        if(v==search_button){
            //刷新订单
            refreshOrderList();
        }else if(v==add_button){
            //增加订单
            try {
                OrderBean orderBean=new OrderBean();
                Random random=new Random();
                orderBean.setAmount(random.nextInt(800)+100);
                orderBean.setId(random.nextInt(100000000)+100000+"");
                orderBean.setName("玩具"+random.nextInt());
                orderManagerInterface.add(orderBean);
                refreshOrderList();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //解绑服务
        unbindService(conn);
    }
}

//adapter
package com.htkj.adapter;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.htkj.jni.aidlclient.R;
import com.htkj.service.bean.OrderBean;

import java.util.List;

public class OrderAdapter extends BaseAdapter {
    private List<OrderBean> orderList;
    private LayoutInflater inflater;

    public OrderAdapter(Context context) {
        inflater = LayoutInflater.from(context);
    }

    public void setData (List<OrderBean> list) {
        this.orderList = list;
        if (this.orderList == null) {
            Log.d("lili","null ....");
        } else {
            Log.d("lili","size =  ...." + this.orderList.size());
        }
    }
    @Override
    public int getCount() {
        if (orderList == null) {
            return 0;
        }else {
            return orderList.size();
        }
    }

    @Override
    public Object getItem(int i) {
        return orderList.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if(convertView == null){
            convertView = inflater.inflate(R.layout.item_adapter,parent,false);
            holder = new ViewHolder();
            holder.tvId = (TextView) convertView.findViewById(R.id.tv_id);
            holder.tvName = (TextView) convertView.findViewById(R.id.tv_name);
            holder.tvAmount = (TextView) convertView.findViewById(R.id.tv_amount);
            convertView.setTag(holder);
        }else{
            holder = (ViewHolder) convertView.getTag();
        }

        holder.tvId.setText(orderList.get(i).getId());
        holder.tvName.setText(orderList.get(i).getName());
        holder.tvAmount.setText(String.valueOf(orderList.get(i).getAmount()));
        return convertView;
    }

    class ViewHolder{
        private TextView tvId;
        private TextView tvName;
        private TextView tvAmount;
    }
}

//main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="5dp"
        android:text="订单管理"
        android:textSize="20dp"/>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp">
        <Button
            android:id="@+id/search_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15dp"
            android:text="刷新订单"/>
        <Button
            android:id="@+id/add_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15dp"
            android:text="添加订单"/>
    </LinearLayout>
    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</LinearLayout>

//item_adapter
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_id"
        android:layout_width="180dp"
        android:layout_height="40dp"
        android:text="id"
        android:textSize="20px"/>

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="180dp"
        android:layout_height="40dp"
        android:text="id"
        android:textSize="20px"
        android:layout_marginLeft="10dp"
        android:layout_marginStart="10dp"/>

    <TextView
        android:id="@+id/tv_amount"
        android:layout_width="180dp"
        android:layout_height="40dp"
        android:text="id"
        android:textSize="20px"
        android:layout_marginLeft="10dp"
        android:layout_marginStart="10dp"/>
</LinearLayout>

3、运行程序,先运行服务端应用,再运行客户端应用。效果图如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 12 中,C++ Service、AIDL 和 HAL 仍然是 Android 系统中重要的组成部分。 1. C++ Service C++ Service 是 Android 系统中的一种基于 Binder 机制实现的服务。它可以在 Android 系统启动时启动,并提供某些系统级别的服务,例如音频服务、电源管理服务等等。 C++ Service 主要的实现语言是 C++,开发者可以使用 C++ 语言来编写自己的 C++ Service。要编写一个 C++ Service,开发者需要实现一个继承自 IInterface 的接口类,并在其中实现自己的服务逻辑。然后,开发者需要通过 ServiceManager 将自己的服务注册到系统中。 2. AIDL AIDL(Android Interface Definition Language)是 Android 系统中的一种 RPC(Remote Procedure Call)框架,它可以用于在不同的进程之间进行通信。开发者可以使用 AIDL 来定义自己的接口,并通过 Binder 机制将接口暴露给客户端。 AIDL 语言是一种类似于 Java 的语言,开发者可以使用 AIDL 来定义自己的接口、数据类型和异常。在使用 AIDL 时,开发者需要编写一个 AIDL 文件,然后通过 AIDL 工具来生成对应的 Java 接口文件和 C++ 接口文件。在编写服务端和客户端时,开发者需要分别实现 Java 接口和 C++ 接口。 3. HAL HAL(Hardware Abstraction Layer)是 Android 系统中的一种硬件抽象层。它可以将硬件接口和实现分离,使得不同厂商可以实现自己的硬件适配层。开发者可以使用 HAL 来访问硬件设备,例如摄像头、传感器等等。 HAL 主要的实现语言是 C++,开发者可以使用 C++ 语言来编写自己的 HAL。要编写一个 HAL,开发者需要实现自己的 HAL 接口,并在其中实现自己的硬件逻辑。然后,开发者需要将自己的 HAL 注册到系统中,使得其他应用程序可以使用它。 以上就是 Android 12 中 C++ Service、AIDL 和 HAL 的一些基本介绍。这些技术都是 Android 系统中非常重要的组成部分,开发者需要深入了解它们的使用方法和原理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值