AIDL的简单使用,涵盖5.0之后系统及魅族手机调用问题的解决
2017-09-08 15:33
525 查看
最近在整理笔记,因为我很多东西都是放在印象笔记里面,写的也不是特别规范,有时候时间长了,自己回头看都有点懵圈,现在一点点的挪到博客里来,尽量写的规范一点,如果能帮到有需要的朋友,也是件好事。
AIDL,就是安卓跨进程通信的方式,其内部细节及Binder的实现暂时不表,只说怎样使用及一些注意点,还有我自己写demo的时候碰到的问题,比如5.0之后隐式调用Service出错啦,在魅族手机上无法绑定,在下面都会给出解决方式,demo已上传github:传送门。此示例为通过aidl获取服务端的一个List列表,里面存放的是Book这个实体类,服务端运行后,客户端“开启服务”,log日志打印出是否连接成功,然后点击“调用“,log打印出服务端给出的list列表中的实体内容。
来看一下主要的4个文件的书写,首先是aidl包下的两个aidl文件,因为我们使用到了Book类,所以也要建立Book的aidl文件。
Book.aidl
注意parcelable 是一个类型,首字母是小写的。
IBookManager.aidl
需要注意的是该接口使用到了Book文件,但是需要我们手动导入Book类,否则编译会报错的;在接口的定义中, 接口中的参数除了aidl支持的类型,其他类型必须标识其方向:到底是输入还是输出抑或两者兼之,用in,out或者inout来表示,上面的代码我们用in标记,因为它是输入型参数。
Book实体类因为要在进程间传输,需要实现序列化接口Parcelable,写法如下,在构建这些需要序列化的类的时候,有一个小技巧,可以通过studio的自动生成功能来做,不用手写那么麻烦了,首先写成该类的成员变量,然后实现Parcelable接口,类名会报红,alt+/ 修复就自动生成对应的代码了。
客户端的aidl代码直接拷贝服务端的aidl包到客户端moudle下就可以了,由于我们使用到了Book文件,所以需要建立一个与服务端Book代码一致的Book,编译后,构建客户端代码调用文件。
4000
启服务后绑定服务端,点击调用,拿到服务端数据。
注意点:5.0之后不允许隐式开启服务,网上给出的办法是在Inent里面setPackage(服务包名);但是在我的魅族手机上怎么跑都不行,后来发现魅族的系统把这一块给改了,丫的费了我半天劲,最后找到一种方式,可以绑定服务,首先通过setComponent()的方式来指定服务,然后先startService,再bindService这样就能成功的绑定服务端的Service。
服务端Log输出如下:
客户端Log输出:
AIDL,就是安卓跨进程通信的方式,其内部细节及Binder的实现暂时不表,只说怎样使用及一些注意点,还有我自己写demo的时候碰到的问题,比如5.0之后隐式调用Service出错啦,在魅族手机上无法绑定,在下面都会给出解决方式,demo已上传github:传送门。此示例为通过aidl获取服务端的一个List列表,里面存放的是Book这个实体类,服务端运行后,客户端“开启服务”,log日志打印出是否连接成功,然后点击“调用“,log打印出服务端给出的list列表中的实体内容。
一.服务端
1.建立服务端,构建AIDL文件
包名设置为com.crfchina.server,在服务端构建AIDL文件,在服务端可以右键通过studio来生成aidi,因为他的包名不需要修改,其文件结构如下:来看一下主要的4个文件的书写,首先是aidl包下的两个aidl文件,因为我们使用到了Book类,所以也要建立Book的aidl文件。
Book.aidl
package com.crfchina.server; parcelable Book;
注意parcelable 是一个类型,首字母是小写的。
IBookManager.aidl
package com.crfchina.server; import com.crfchina.server.Book; interface IBookManager { List<Book> getBookList(); void addBook(in Book book); }
需要注意的是该接口使用到了Book文件,但是需要我们手动导入Book类,否则编译会报错的;在接口的定义中, 接口中的参数除了aidl支持的类型,其他类型必须标识其方向:到底是输入还是输出抑或两者兼之,用in,out或者inout来表示,上面的代码我们用in标记,因为它是输入型参数。
Book实体类因为要在进程间传输,需要实现序列化接口Parcelable,写法如下,在构建这些需要序列化的类的时候,有一个小技巧,可以通过studio的自动生成功能来做,不用手写那么麻烦了,首先写成该类的成员变量,然后实现Parcelable接口,类名会报红,alt+/ 修复就自动生成对应的代码了。
package com.crfchina.server; import android.os.Parcel; import android.os.Parcelable; public class Book implements Parcelable { private int bookId; private String bookName; public Book(int bookId, String bookName) { this.bookId = bookId; this.bookName = bookName; } protected Book(Parcel in) { bookId = in.readInt(); bookName = in.readString(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(bookId); dest.writeString(bookName); } @Override public int describeContents() { return 0; } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public String toString() { return "Book{" + "bookId=" + bookId + ", bookName='" + bookName + '\'' + '}'; } }
2.构建服务端Service
<service android:name=".MyService" android:enabled="true"> <intent-filter> <action android:name="a.b.c" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service>清单文件中必须配置过滤器,否则外部程序隐式调用该服务会出错。
package com.crfchina.server; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.util.Log; import java.util.ArrayList; import java.util.List; public class MyService extends Service { private static final String TAG = "AIDL"; private List<Book> list = new ArrayList<>(); private Binder mBinder = new IBookManager.Stub() { @Override public List<Book> getBookList() throws RemoteException { synchronized (MyService.class) { return list; } } @Override public void addBook(Book book) throws RemoteException { synchronized (MyService.class) { if (!list.contains(book)) { list.add(book); } } } @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { return super.onTransact(code, data, reply, flags); } }; @Override public IBinder onBind(Intent intent) { Log.i(TAG, "服务绑定"); list = new ArrayList<>(); list.add(new Book(0, "1984")); list.add(new Book(1, "红楼梦")); return mBinder; } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "服务开启"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "服务调用"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "服务关闭"); } }
二.客户端配置
1.客户端目录结构
客户端的aidl代码直接拷贝服务端的aidl包到客户端moudle下就可以了,由于我们使用到了Book文件,所以需要建立一个与服务端Book代码一致的Book,编译后,构建客户端代码调用文件。
2.客户端调用服务
客户端代码如下,在MainActivity中有两个按钮,点击开4000
启服务后绑定服务端,点击调用,拿到服务端数据。
package com.crfchina.client; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import com.crfchina.server.Book; import com.crfchina.server.IBookManager; import java.util.List; public class MainActivity extends AppCompatActivity { private Button btBinder, btGet; private IBookManager manager; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { manager = IBookManager.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { manager = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btBinder = (Button) findViewById(R.id.button2); btGet = (Button) findViewById(R.id.button); initListener(); } private void initListener() { btBinder.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setComponent(new ComponentName("com.crfchina.server", "com.crfchina.server.MyService")); startService(intent); boolean flag = bindService(intent, conn, Context.BIND_AUTO_CREATE); Log.i("AIDL", flag + ""); } }); btGet.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { if (manager != null) { List<Book> books = manager.getBookList(); for (Book book : books) { Log.i("AIDL", book.toString()); } } } catch (RemoteException e) { e.printStackTrace(); } } }); } @Override protected void onDestroy() { super.onDestroy(); unbindService(conn); } }
注意点:5.0之后不允许隐式开启服务,网上给出的办法是在Inent里面setPackage(服务包名);但是在我的魅族手机上怎么跑都不行,后来发现魅族的系统把这一块给改了,丫的费了我半天劲,最后找到一种方式,可以绑定服务,首先通过setComponent()的方式来指定服务,然后先startService,再bindService这样就能成功的绑定服务端的Service。
服务端Log输出如下:
客户端Log输出:
相关文章推荐
- Spring @Async配置4. 基于@Async无返回值调用 使用的方式非常简单,一个标注即可解决所有的问题: 1 @Async //标注使用 2 public void asyncMe
- 使用aidl隐式调用service出现service intent must be explicit 问题的一种解决方法
- 解决android4.4以上手机调用系统相册路径返回错误的问题
- 完美解决部分安卓手机调用系统拍照上传时图片旋转问题
- Android使用webview加载网页,解决上传文件适配3.0、4.0、5.0手机存在的问题。
- Android开发中调用系统相册上传图片到服务器OPPO等部分手机上出现短暂的显示桌面问题的解决方法
- Android 5.0及更高系统使用AIDL的问题
- 可靠简单的 解决Microsoft.Jet.OLEDB.4.0 不能在64位系统下使用的问题
- 关于魅族手机调用系统相册剪裁页面无法载入图片的问题。
- 可靠简单的 解决Microsoft.Jet.OLEDB.4.0 不能在64位系统下使用的问题
- 解决魅族手机上Listview 下拉之后出现HOLD 字样的问题。
- 解决Android使用Svg兼容5.0以下手机导致OOM的问题
- 关于调用系统照相机等,onActivityResult之后Activity被销毁问题解决
- OP:windows 2008 安装之后无线网无法使用问题解决(Windows 2008 Wireless)
- 使用webservice解决多系统登陆问题
- 使用 StateServer 保存 Session 解决 Session过期,登陆过期问题,最简单的方法。
- 如何解决mid使用过程中出现的以下问题(无效的过程调用或参数: 'mid')
- Java写的手机计费系统(作为学习参考的实例:关键是Java类库里面的date和Calendar的使用和相互转换,以及一些日期的实际问题)
- C#.Net里面通过事件调用事件,通过简单了解相信可以帮你解决问题
- 如何解决Mysql "发生系统错误2,找不到指定的文件" 的问题(第一次安装使用)