Android-service之aidl

相关类关系:

public interface IBinder {...}


public class Binder implements IBinder {...}

//BookManager为自定义的aidl接口
public interface BookManger extends IInterface {
    //Stub为内部类
    public static abstract class Stub extends Binder implements BookManger{...}

}



public interface IInterface
{
    public IBinder asBinder();
}

1、创建.aidl文件,并定义通信接口。(服务端和客户端都必须有此文件,连同包名、类名及内容都必须相同)

1、创建aidl文件:src/main 文件夹下创建一个AIDL文件(Android Studio->File->New->AIDL->AIDL file),创建后Android Studio会自动把这个.aidl文件放到一个aidl的目录下。

Markdown

2、定义接口:

// IRemoteService.aidl
package com.example.administrator.aidldemo;

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

interface IRemoteService {

    int getPid();
    /**
     * 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);
}

建好的效果:

Markdown

3、建好后build ,Android SDK Tool会根据我们的.aidl文件自动生成一个同名的.java文件。
路径为:

AIDLDemo\app\build\generated\source\aidl\debug\com\example\administrator\aidldemo\IRemoteService.java

Markdown

2、服务端:创建一个Service暴露AIDL接口并实现AIDL的接口函数。service要在清单文件中注册。

package com.example.administrator.aidldemo;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.support.annotation.Nullable;

/**
 * 服务端
 * Created by Administrator on 2017/6/2.
 */

public class RemoteService extends Service {

    public RemoteService() {
    }

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

    /*Stub类:Binder的实现类,服务端需要实现这个类来提供服务。*/
    private IRemoteService.Stub binder = new IRemoteService.Stub() {
        @Override
        public int getPid() throws RemoteException {
            return Process.myPid();
        }

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

        }
    };


}

manifest.xml中注册service

        <service
            android:name=".RemoteService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote" />

3、客户端:调用服务端的服务:

package com.example.administrator.aidldemo;

import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

/*客户端*/
public class MainActivity extends AppCompatActivity {

    private final static String TAG = "MainActivity";
    private IRemoteService remoteService;

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


        Intent intent = new Intent(this, RemoteService.class);
        bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE); // 绑定服务
    }

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //获取AIDL的接口实现引用
            /*asInterface函数: 一个静态函数,用来将IBinder转换成对应的Binder的引用。*/
            IRemoteService iRemoteService = IRemoteService.Stub.asInterface(service);

            try {
                Log.i(TAG, "Client pid= " + Process.myPid());//当前进程
                Log.i(TAG, "RemoteService pid= " + iRemoteService.getPid());//服务端进程
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "Service has unexpectedly disconnected");
            remoteService = null;
        }
    };

}

运行效果:

MainActivity: Client pid= 8541
MainActivity: RemoteService pid= 8553

通过IPC传递对象

1:使用Parcelable来序列化对象

注意读音:
parcel:扒~手
parcelable:帕斯~雷柏

package com.example.administrator.aidldemo2;

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

/**
 * Created by Administrator on 2017/6/2.
 */

public class CellPhone implements Parcelable {

    private String phone;
    private String name;

    public CellPhone(String phone, String name) {
        this.phone = phone;
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getName() {
        return name;
    }

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

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.phone);
        dest.writeString(this.name);
    }

    public CellPhone() {
    }

    protected CellPhone(Parcel in) {
        this.phone = in.readString();
        this.name = in.readString();
    }

    public static final Parcelable.Creator<CellPhone> CREATOR = new Parcelable.Creator<CellPhone>() {
        @Override
        public CellPhone createFromParcel(Parcel source) {
            return new CellPhone(source);
        }

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

    @Override
    public String toString() {
        return "CellPhone{" +
                "phone='" + phone + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

2:创建.aidl文件,并定义通信接口。

(服务端和客户端都必须有此文件,连同包名、类名及内容都必须相同)

1、aidl文件名要与上面的序列化类名一致。但是这样的话,好像创建不了aidl文件,它会提示你“Interface name must be unique”,这时,你可以任意起一个名字,这时会生成一个aidl文件。然后对这个aidl文件进行重命名,把它命名成与上面的序列化类名一致 , 然后在这个aidl文件里,对这个类序列化。

CellPhone.aidl


package com.example.administrator.aidldemo2;

parcelable CellPhone;

2、接下来就是在当前aidl包名下,再创建一个Aidl文件,在这个文件中暴露出你想调用的方法。

CellPhoneManager.aidl


package com.example.administrator.aidldemo2;

import com.example.administrator.aidldemo2.CellPhone;

interface CellPhoneManager {

    String call();
    CellPhone getPhone();

}

这里特别要注意“import com.example.administrator.aidldemo2.CellPhone;”导入这个。

如图:
Markdown

3、build,Android SDK Tool会根据我们的.aidl文件自动生成一个同名的.java文件。
路径为:

AIDLDemo2\app\build\generated\source\aidl\debug\com\example\administrator\aidldemo2.CellPhoneManager.java

如图:
Markdown

4、为了避免AIDL 自定义类型CellPhoneManager.java找不到问题,可以添加以下内容到build.gradle中android 目录中的最后。

sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java.srcDirs = ['src/main/java', 'src/main/aidl']
            resources.srcDirs = ['src/main/java', 'src/main/aidl']
            aidl.srcDirs = ['src/main/aidl']
            res.srcDirs = ['src/main/res']
            assets.srcDirs = ['src/main/assets']
        }
    }

如图:

Markdown

3、服务端:创建一个Service暴露AIDL接口并实现AIDL的接口函数。service要在清单文件中注册。

package com.example.administrator.aidldemo2;

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

/**
 * Created by Administrator on 2017/6/2.
 */

public class CellServer extends Service {
    public CellServer() {
    }

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

    CellPhoneManager.Stub binder = new CellPhoneManager.Stub() {
        @Override
        public String call() throws RemoteException {

            return "hello my name is call";
        }

        @Override
        public CellPhone getPhone() throws RemoteException {
            CellPhone cell = new CellPhone();
            cell.setPhone("110-1234567");
            cell.setName("公安局");
            return cell;
        }

        @Override
        public IBinder asBinder() {
            return super.asBinder();
        }

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            return super.onTransact(code, data, reply, flags);
        }
    };
}

注册:

  <service android:name=".CellServer"
            android:enabled="true"
            android:exported="true"
            android:process=":remote">

4、客户端:调用服务端的服务:

客户端要有与服务端相同的aidl文件,只不过包名要注意也要相同,不要弄错,然后还有CellPhone这个类也相同。

package com.example.administrator.aidldemo2;

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.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private Button mBtn;
    private TextView mTv;


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

        initView();
    }

    private void initView() {
        mBtn = (Button) findViewById(R.id.press);
        mTv = (TextView) findViewById(R.id.tv);

        mBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //启动服务
                Intent intent = new Intent(MainActivity.this,CellServer.class);
                //automatically create the service as long
                //* as the binding exists.  Note that while this will create the service,
                bindService(intent,mConnection,BIND_AUTO_CREATE);
            }
        });
    }



    //服务链接
    ServiceConnection mConnection = new ServiceConnection() {
        CellPhoneManager mServer;
        String content;
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("Test","onServiceConnected");
            //初始化aidl
             mServer = CellPhoneManager.Stub.asInterface(service);

            try {
                content = mServer.call()+" 》》》》  ";
                CellPhone cell = mServer.getPhone();
                content += cell.getPhone();
                mTv.setText(content);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mServer = null;
        }
    };





}

布局 :

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.administrator.aidldemo2.MainActivity">

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <Button
        android:id="@+id/press"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="aidl通信对象" />

</android.support.constraint.ConstraintLayout>

效果:

Markdown

参考:

Android面试一天一题(Day 36:AIDL)

Android Studio 中AIDL 的创建与使用详解

使用Android studio创建的AIDL编译时找不到自定义类的解决办法

Android:学习AIDL,这一篇文章就够了(上)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值