小说网 找小说 无限小说 烟雨红尘 幻想小说 酷文学 深夜书屋

Android高级第十讲之AIDL与JNI


博客出自: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() {
		// bindService
		Intent 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>();

	@Override
	public 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;
		}

		@Override
		public void getBookList(List<Book> inBooks, List<Book> outBooks) throws RemoteException {
			// TODO Auto-generated method stub
			Book mBook = new Book();
			mBook.setBookName("IOS应用开发");
			mBook.setBookPrice(45);
			inBooks.add(mBook);
			outBooks.addAll(inBooks);
		}

		@Override
		public List<Book> getBooks() throws RemoteException {
			// TODO Auto-generated method stub
			return 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);
		}
	};

	@Override
	public 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() {
		// bindService
		Intent 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中。

posted on 2013-04-18 23:40  王峰炬  阅读(280)  评论(0编辑  收藏  举报

导航