android 之 AIDL
AIDL (android interface defintion language) 定义跨进程调用数据,也就是说不同进程之间的数据共享。
- AIDL 定义接口的源代码必须以.aidl结尾。
- AIDL 接口中用到的数据类型,除了基本类型、String List Map CharSequence 之外,其他类型都需要导包。
先看一下项目结构图:
接下来我们需要定义一个Book实体,属于自定义类型。
Book.java
package com.hkrt.action; import android.os.Parcel; import android.os.Parcelable; public class Book implements Parcelable { private String author; private String bookName; private int bookPrice; public Book() { } public Book(Parcel parcel) { author = parcel.readString(); 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 String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeString(author); 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]; } }; }注:对象在跨进程访问,类必须实现 Parcelable。原文是这样说的。
Interface for classes whose instances can be written to and restored from a
Parcel
.
Classes implementing the Parcelable interface must also have a static field called CREATOR
, which is an object implementing the Parcelable.Creator
interface.然后定义一个Book.aidl 文件
parcelable Book;
接下来定义把对外提供的服务定义aidl(IaidlServerService.aidl)。
package com.hkrt.action; import com.hkrt.action.Book; import java.util.List; interface IAIDLServerService { String sayHello(); Book getBook(); List<Book> getBooks(); }当保存这个文件时,就会在gen/<package>/生成对应的java文件。如图上所示。
然后。编写本地实现,实现这三个接口,并初始化数据。
package com.hkrt.action; import java.util.ArrayList; import java.util.List; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import com.hkrt.action.IAIDLServerService.Stub; public class AidlServerService extends Service{ @Override public IBinder onBind(Intent intent) { return mBinder; } /*** 在AIDL文件中定义的接口实现 */ private IAIDLServerService.Stub mBinder = new Stub() { @Override public String sayHello() throws RemoteException { return "Hello"; } @Override public Book getBook() throws RemoteException { Book mBook = new Book(); mBook.setAuthor("机器人"); mBook.setBookName("Android应用开发"); mBook.setBookPrice(50); return mBook; } @Override public List<Book> getBooks() throws RemoteException { List<Book> books = new ArrayList<Book>(); Book book1 = new Book(); book1.setAuthor("机器人Tom"); book1.setBookName("Android adil person one"); book1.setBookPrice(501); books.add(book1); Book book2 = new Book(); book2.setAuthor("机器人Jom"); book2.setBookName("Android adil person two"); book2.setBookPrice(502); books.add(book2); Book book3 = new Book(); book3.setAuthor("机器人Jom3"); book3.setBookName("Android adil person three"); book3.setBookPrice(502); books.add(book3); return books; } }; }
需要把这个service 注册到AndroidManifest.xml下。
<service android:name="AidlServerService" android:process=":remote"> <intent-filter> <action android:name="com.hkrt.action.IAIDLServerService"></action> </intent-filter> </service>
这样第一个应用就写完了,只是提供一些数据,可又被另一个进程访问。
接下来我们需要新建另外一个程序,访问第一个程序对外提供的数据。
先看一下结构图:
具中图:
是从第一个图中拷出来的。自动就会在gen下对应的java文件。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/textview" android:layout_width="200dp" android:layout_height="20dp" android:text="@string/hello" /> <Button android:id="@+id/button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="调用AIDL服务" /> <ExpandableListView android:id="@+id/ExpandableListView01" android:layout_width="fill_parent" android:layout_height="fill_parent"> </ExpandableListView> </LinearLayout>效果图:
接下来,我们需要把第一个程序对外程序提供的内容展出来。
我把第一个程序对处提供的集合用树结构展示出来。
TreeViewAdapter.java 是为树结构准备的。
package com.hkrt; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.BaseExpandableListAdapter; import android.widget.TextView; public class TreeViewAdapter extends BaseExpandableListAdapter { public static final int ItemHeight = 48;// 每项的高度 public static final int PaddingLeft = 36;// 每项的高度 private int myPaddingLeft = 0;// 如果是由SuperTreeView调用,则作为子项需要往右移 static public class TreeNode { Object parent; List<Object> childs = new ArrayList<Object>(); } List<TreeNode> treeNodes = new ArrayList<TreeNode>(); Context parentContext; public TreeViewAdapter(Context view, int myPaddingLeft) { parentContext = view; this.myPaddingLeft = myPaddingLeft; } public List<TreeNode> GetTreeNode() { return treeNodes; } public void UpdateTreeNode(List<TreeNode> nodes) { treeNodes = nodes; } public void RemoveAll() { treeNodes.clear(); } public Object getChild(int groupPosition, int childPosition) { return treeNodes.get(groupPosition).childs.get(childPosition); } public int getChildrenCount(int groupPosition) { return treeNodes.get(groupPosition).childs.size(); } static public TextView getTextView(Context context) { AbsListView.LayoutParams lp = new AbsListView.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ItemHeight); TextView textView = new TextView(context); textView.setLayoutParams(lp); textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); return textView; } public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { TextView textView = getTextView(this.parentContext); textView.setText(getChild(groupPosition, childPosition).toString()); textView.setPadding(myPaddingLeft + PaddingLeft, 0, 0, 0); return textView; } public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { TextView textView = getTextView(this.parentContext); textView.setText(getGroup(groupPosition).toString()); textView.setPadding(myPaddingLeft + (PaddingLeft >> 1), 0, 0, 0); return textView; } public long getChildId(int groupPosition, int childPosition) { return childPosition; } public Object getGroup(int groupPosition) { return treeNodes.get(groupPosition).parent; } public int getGroupCount() { return treeNodes.size(); } public long getGroupId(int groupPosition) { return groupPosition; } public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } public boolean hasStableIds() { return true; } }
最后主要的展示 AidlClientDemoActivity.java 代码
package com.hkrt; 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.Button; import android.widget.ExpandableListView; import android.widget.TextView; import android.widget.Toast; import android.widget.ExpandableListView.OnChildClickListener; import com.hkrt.action.Book; import com.hkrt.action.IAIDLServerService; public class AidlClientDemoActivity extends Activity { private TextView mTextView; private Button mButton; ExpandableListView expandableList; TreeViewAdapter adapter; public String[] groups ; public String[][] child; 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); //aidl通信 try { String mText = "Say hello: " + mIaidlServerService.sayHello() + "\n"; mText += "作者: " + mIaidlServerService.getBook().getAuthor()+"\n"; mText += "书名: " + mIaidlServerService.getBook().getBookName()+"\n"; mText += "价格: " + mIaidlServerService.getBook().getBookPrice(); List<Book> books = mIaidlServerService.getBooks(); groups = new String[books.size()]; for(int i=0;i<books.size();i++){ groups[i]=books.get(i).getBookName(); } child =new String[groups.length][3]; for(int j=0;j<groups.length;j++){ Book book = books.get(j); child[j][0] = "作者: " +book.getAuthor(); child[j][1] = "书名: "+book.getBookName(); child[j][2] = "价格: "+book.getBookPrice() + ""; } mTextView.setText(mText); List<TreeViewAdapter.TreeNode> treeNode = adapter.GetTreeNode(); for(int i=0;i<groups.length;i++) { TreeViewAdapter.TreeNode node=new TreeViewAdapter.TreeNode(); node.parent=groups[i]; for(int ii=0;ii<child[i].length;ii++) { node.childs.add(child[i][ii]); } treeNode.add(node); } adapter.UpdateTreeNode(treeNode); expandableList.setAdapter(adapter); expandableList.setOnChildClickListener(new OnChildClickListener(){ @Override public boolean onChildClick(ExpandableListView arg0, View arg1, int parent, int children, long arg4) { String str="parent id:"+String.valueOf(parent)+",children id:"+String.valueOf(children); Toast.makeText(AidlClientDemoActivity.this, str, 300).show(); return false; } }); } catch (RemoteException e) { e.printStackTrace(); } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //初始化控件 mTextView = (TextView)findViewById(R.id.textview); mButton = (Button)findViewById(R.id.button); expandableList=(ExpandableListView) this.findViewById(R.id.ExpandableListView01); //增加事件响应 mButton.setOnClickListener(new OnClickListener(){ public void onClick(View v) { Intent service = new Intent("com.hkrt.action.IAIDLServerService"); bindService(service, mConnection,BIND_AUTO_CREATE); adapter=new TreeViewAdapter(AidlClientDemoActivity.this,TreeViewAdapter.PaddingLeft>>1); adapter.RemoveAll(); adapter.notifyDataSetChanged(); } }); } }
效果图:
如果。需要传递参数,服务器端的IaidlServerService.aidl
可以定义成 String sayMe(in String str);
in 表示传入参数。
在aidl 中写注释 /**注释*/