Android高级第十讲之AIDL与JNI

来源:互联网 发布:国道知证量化 编辑:程序博客网 时间:2024/04/30 23:46


博客出自:http://blog.csdn.net/liuxian13183,转载注明出处! All Rights Reserved ! 


什么是AIDL,它有什么作用?

AIDL:Android Interface Defination Language   

它是一种Android内部进程通信的描述语言,用它来定义通信接口。

AIDL是安卓的一个伟大设计,它保证不同项目之间资源、数据可以共享,减少冗余开发。

其实它也是RPC机制,客户端和服务端默认共用一套协议,Remote Procedure Call Protocol。

资源共享可以在项目的project.properties文件里写android.library.reference.1=../“项目名”

AIDL的简单实现(一方做服务端,一方做客户端):


目标项目:

1、首先可以在目标项目中声明一个Service A和一个.aidl结尾的接口文件B

2、在Service中实现一个IMyService.Stub实体类 C,其中C实现调用文件中的IInterface实现接口D

2、在Service的onBind()方法里返回B的实现

这样目标项目工作就完成了。

客户端:

1、首先实现一个序列化实体,一般用parcelable

2、然后完善D,写入一个抽象类,声明DESCRIPTOR变量为目标项目的B路径

3、在Activity中先绑定A,再获取A中所持久化的数据。


例:

创建一个ServiceConnection连接,从后台获得

private IAIDLServerService mIaidlServerService = null;private ServiceConnection mConnection = new ServiceConnection() {public void onServiceDisconnected(ComponentName name) {mIaidlServerService = null;}public void onServiceConnected(ComponentName name, IBinder service) {mIaidlServerService = IAIDLServerService.Stub.asInterface(service);}};
private void bindService() {// bindServiceIntent service = new Intent("com.chapter8.aidl.IAIDLServerService");service.setPackage("com.blog.aidlserver");bindService(service, mConnection, BIND_AUTO_CREATE);}
private Book mBook;private void getTransferSingleData() {if (mIaidlServerService == null) {return;}// aidl通信try {String mText = "Say hello: " + mIaidlServerService.sayHello() + "\n";mBook = mIaidlServerService.getBook();mText += "书名: " + mBook.getBookName() + "\n";mText += "价格: " + mBook.getBookPrice();mTextView.setText(mText);} catch (RemoteException e) {e.printStackTrace();}}


公共部分

Book:

package com.blog.aidl;import android.os.Parcel;import android.os.Parcelable;public class Book implements Parcelable {private String bookName;private int bookPrice;public Book(){}public Book(Parcel parcel){bookName = parcel.readString();bookPrice = parcel.readInt();}public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public int getBookPrice() {return bookPrice;}public void setBookPrice(int bookPrice) {this.bookPrice = bookPrice;}public int describeContents() {return 0;}public void writeToParcel(Parcel parcel, int flags) {parcel.writeString(bookName);parcel.writeInt(bookPrice);}public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>() {public Book createFromParcel(Parcel source) {return new Book(source);}public Book[] newArray(int size) {return new Book[size];}};}
Book.aidl

parcelable Book;
IAIDLServerService.aidl

package com.blog.aidl;import com.blog.aidl.Book;  interface IAIDLServerService {String sayHello();Book getBook();List<Book> getBooks();void getBookList(in List<Book> inBooks,out List<Book> outBooks);}

这里多解释一下,进程间通信的实体类都要实现parcelable接口,aidl里面也有一些格式规范

主要是in和out关键字,in代表传入的参数,out代表输出的参数

当然看到这里,也清楚传入传出的参数类型,只能为实体类和容器类包含String,而不包含其他基本数据类型,即使封装类都不可以

服务端:

AidlServerService:

package com.blog.aidlserver;import java.util.ArrayList;import java.util.List;import java.util.Random;import com.blog.aidl.Book;import com.blog.aidl.IAIDLServerService.Stub;import com.blog.aidl.IAIDLServerService;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;public class AidlServerService extends Service {private List<Book> mList = new ArrayList<Book>();@Overridepublic IBinder onBind(Intent intent) {return mBinder;}/** * 在AIDL文件中定义的接口实现。 */private IAIDLServerService.Stub mBinder = new Stub() {public String sayHello() throws RemoteException {return "Hello";}public Book getBook() throws RemoteException {Book mBook = new Book();mBook.setBookName("Android应用开发");Random random = new Random();mBook.setBookPrice(50 + random.nextInt(50));mList.add(mBook);return mBook;}@Overridepublic void getBookList(List<Book> inBooks, List<Book> outBooks) throws RemoteException {// TODO Auto-generated method stubBook mBook = new Book();mBook.setBookName("IOS应用开发");mBook.setBookPrice(45);inBooks.add(mBook);outBooks.addAll(inBooks);}@Overridepublic List<Book> getBooks() throws RemoteException {// TODO Auto-generated method stubreturn mList;}};}
客户端:
package com.blog.aidlclient;import java.util.ArrayList;import java.util.List;import android.app.Activity;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.view.View.OnClickListener;import android.widget.TextView;import com.blog.aidl.Book;import com.blog.aidl.IAIDLServerService;public class AidlClientActivity extends Activity {private TextView mTextView;private IAIDLServerService mIaidlServerService = null;private ServiceConnection mConnection = new ServiceConnection() {public void onServiceDisconnected(ComponentName name) {mIaidlServerService = null;}public void onServiceConnected(ComponentName name, IBinder service) {mIaidlServerService = IAIDLServerService.Stub.asInterface(service);}};@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);// 初始化控件mTextView = (TextView) findViewById(R.id.textview);bindService();findViewById(R.id.button1).setOnClickListener(new OnClickListener() {public void onClick(View v) {getTransferSingleData();}});findViewById(R.id.button2).setOnClickListener(new OnClickListener() {public void onClick(View v) {getTransferMultiData();}});findViewById(R.id.button3).setOnClickListener(new OnClickListener() {public void onClick(View v) {getTransferTempData();}});}private void bindService() {// bindServiceIntent service = new Intent("com.chapter8.aidl.IAIDLServerService");service.setPackage("com.blog.aidlserver");bindService(service, mConnection, BIND_AUTO_CREATE);}private Book mBook;private void getTransferSingleData() {if (mIaidlServerService == null) {return;}// aidl通信try {String mText = "Say hello: " + mIaidlServerService.sayHello() + "\n";mBook = mIaidlServerService.getBook();mText += "书名: " + mBook.getBookName() + "\n";mText += "价格: " + mBook.getBookPrice();mTextView.setText(mText);} catch (RemoteException e) {e.printStackTrace();}}private void getTransferMultiData() {if (mIaidlServerService == null) {return;}// aidl通信try {String mText = "Say hello: " + mIaidlServerService.sayHello() + "\n";List<Book> inBooks = new ArrayList<Book>();if (mBook == null) {mBook = mIaidlServerService.getBook();}inBooks.add(mBook);List<Book> outBooks = new ArrayList<Book>();mIaidlServerService.getBookList(inBooks, outBooks);for (Book book : outBooks) {mText += "书名: " + book.getBookName() + "\n";mText += "价格: " + book.getBookPrice() + "\n";}mTextView.setText(mText);} catch (RemoteException e) {e.printStackTrace();}}private void getTransferTempData() {if (mIaidlServerService == null) {return;}// aidl通信try {String mText = "Say hello: " + mIaidlServerService.sayHello() + "\n";List<Book> books = mIaidlServerService.getBooks();for (Book book : books) {mText += "书名: " + book.getBookName() + "\n";mText += "价格: " + book.getBookPrice() + "\n";}mTextView.setText(mText);} catch (RemoteException e) {e.printStackTrace();}}}
按钮1:


按钮2:


按钮1再按钮2


要求客户端与服务端公用模块一样,最好写成依赖包的形式

源码

注:直接启动服务端(只为Service自启动)再调用客户端就可以试验了!

关于JNI,主要用在java调用c或c调用java语言,应用场景分为3类

1、涉及到核心知识库,c的加密性会更好

2、c已经实现逻辑,且比较复杂

3、调用驱动,一般java做不到

如何区分Java类中哪些是调用c语言的方法呢?看到有native加为前缀的方法即是。当然这之前需要先把so库加载进来,否则会报错;例:

    static {        System.loadLibrary("webp");    }
private native final void init();//初始化类的方法

对应在c中的方法为(是一种编译规范,可改变)

static void android_content_AssetManager_init(JNIEnv* env,jobject clazz)

规范指,产生的c函数中,前者是JNIEnv对象指虚拟机运行环境,后者是调用函数的对象,指AssetManager;java方法在c中表现为包名+类包+方法名。

关于数据访问,java不可以直接访问c,c默认对java是私有的,可以使用get/set方法来达到访问目的。


有时c也会要访问java,因为一般情况下两者不会使用回调函数,不同于aidl,c语言返回值支持void、object和基本数据类型的封装类,调用分3步

1、获得Java对象的类

cls=env->GetObjectClass(object)

2、获得Java函数id

jmethodId mid= env ->GetMethodId(cls,"method_name","[Ljava/lang/String;)V")

3、调用函数

env->CallXXXMethod(jobject,mid,ret)

如果要获得数据,将上面的method改成field即可,比较奇怪的一个问题是这样,c库里主要进行逻辑运算,而结果的保存,如对象的声明,通常要保存在java中。

原创粉丝点击