Android高级第十讲之AIDL与JNI

博客出自:刘兆贤的博客_CSDN博客-Java高级,Android旅行,Android基础领域博主,转载注明出处! All Rights Reserved ! 

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

AIDL:Android Interface Defination Language   

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

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

其实它也是RPC机制(Remote Procedure Call Protocol,是一种隐藏调用细节的IPC机制-用于发送消息、共享资源、对象同步),客户端和服务端默认共用一套协议,。

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

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

公共部分:1、序列化的实体类,2、此对象的aidl文件,3、传输接口aidl文件。

 

 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,而不包含其他基本数据类型,即使封装类都不可以。

服务端:

首先依赖上述公共部分

1、首先可以在目标项目中声明一个Service。

2、在Service中实现一个IAIDLServerService.Stub的Binder对象,实现接口。

2、在Service的onBind()方法里返回此Binder对象。

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;
		}
	};
}

客户端:

首先依赖上述公共部分

1、通过隐式调用,启动Service

2、然后实现ServiceConnection对象,从而获得IAIDLServerService句柄

3、最后通过句柄,实现自己的存取业务。

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中。
 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘兆贤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值