关闭

IPC学习之AIDL小试牛刀

标签: aidlipcandroid进程间通信
419人阅读 评论(0) 收藏 举报
分类:

最近在学习IPC进程间通信,在此记录下AIDL的使用,并附上一个Demo:服务端每隔一分钟添加一本书籍,客户端通过进程间通信,获取当前服务端的书籍列表,并且服务端对外开放添加、删除等操作。

效果展示
终于明白鸿洋所说的App效果图尽力的意思了!Android屏幕截图方法可参考:http://www.jianshu.com/p/9a1825e679b7

服务端:

1、新建一个AIDLServer工程,创建一个Parcelable接口类Book

package com.aa.aidlserver;

import android.os.Parcel;
import android.os.Parcelable;

public class Book implements Parcelable {

    public String name;
    public String describe;

    public Book(String name, String describe) {
        this.name = name;
        this.describe = describe;
    }

    protected Book(Parcel in) {
        name = in.readString();
        describe = in.readString();
    }

    //反序列化
    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 int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        //序列化
        parcel.writeString(name);
        parcel.writeString(describe);
    }
}

2、创建两个aidl文件:Book.aidl和IBookManager.aidl

// Book.aidl
package com.aa.aidlserver;
parcelable Book;
// IBookManager.aidl
package com.aa.aidlserver;
import com.aa.aidlserver.Book;

interface IBookManager {
    //获取书本列表
    List<Book> getBookList();
    //添加书本
    void addBook(in Book book);
    //删除书本
    void deleteBook(in Book book);
}

注意:

  1. 其中Book.aidl用来声明Book实现了Parcelable接口
  2. 因为在IBookManager中使用了Book参数,所以无论Book.java是否在同一个包名下,都必须进行一次import

3、创建自定义Service,创建一个IBookManager.Stub对象,即一个Binder对象,重写onBind方法返回这个对象。然后在AndroidManifest中声明此Service,并加入action

package com.aa.aidlserver;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class AIDLService extends Service {

    /**
     * 书本列表
     */
    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();


    private Binder mBinder = new IBookManager.Stub() {

        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            mBookList.add(book);
        }

        @Override
        public void deleteBook(Book book) throws RemoteException {
            mBookList.remove(0);
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if(mBookList.size() == 0) {
            mBookList.add(new Book("他们最幸福", "一个屌丝写的书"));
            mBookList.add(new Book("晓松奇谈", "矮大紧写的书"));
        } else {
            addBook();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 通过定时任务来添加书本信息
     */
    private void addBook() {
        Log.e("TAG", "Adding...");

        int len = mBookList.size() + 1;
        String name = "图书" + len;
        String describe = "这是第" + len + "本书";
        Book book = new Book(name, describe);
        mBookList.add(book);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.aa.aidlserver">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <service
            android:name=".AIDLService"
            android:process=":remote">
            <intent-filter>
                <action android:name="com.aa.aidlserver.AIDLService"/>
            </intent-filter>
        </service>
    </application>

</manifest>

4、在MainActivity中使用AlarmManager每隔一分钟创建(打开)Service

package com.aa.aidlserver;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initAlarmManager();
    }

    /**
     * 初始化定时任务
     */
    private void initAlarmManager() {
        Intent intent = new Intent();
        // 设置Intent的Action 属性
        intent.setAction("com.aa.aidlserver.AIDLService");
        // Android 5.0以上需要设置包名
        intent.setPackage("com.aa.aidlserver");

        //创建一个PendingIntent对象,包含了startService操作
        PendingIntent pi = PendingIntent.getService(this, 0,intent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
        long intervalMillis = 60 * 1000;
        //创建一个系统级定时器,即使熄屏状态也会每隔一分钟启动一次Service添加书本(注:部分定制系统定时器不准)
        am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), intervalMillis, pi);
    }
}

5、在app的build.gradle文件的android节点中添加以下代码,可解决找不到Book类的问题

sourceSets {
    main {
        manifest.srcFile 'src/main/AndroidManifest.xml'
        java.srcDirs = ['src/main/java', 'src/main/aidl']
        resources.srcDirs = ['src/main/java', 'src/main/aidl']
        aidl.srcDirs = ['src/main/aidl']
        res.srcDirs = ['src/main/res']
        assets.srcDirs = ['src/main/assets']
    }
}

至此服务端就开发完毕了,相比之下,客户端的就简单一些。

客户端:

1、新建一个AIDLClient工程,将AIDLServer工程的app\src\main\aidl目录拷贝到AIDLClient工程的app\src\main目录下,不需任何修改(注意这里的包名、文件都与AIDLServer是一致的)

2、服务端每隔一分钟会添加一本书,所以在客户端MainActivity中获取当前服务端书本列表并显示,也可进行添加、删除等操作

package com.aa.aidlclient;

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.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

import com.aa.aidlserver.Book;
import com.aa.aidlserver.IBookManager;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private ListView mListView;
    private ArrayAdapter<String> mAdapter;
    private List<String> mBooks = new ArrayList<>();

    private Button btnLoadmore, btnAdd, btnDetele;

    private IBookManager mIBookManager;
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //Service已连接
            mIBookManager = IBookManager.Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            //Service已断开
            mIBookManager = null;
        }
    };

    private void toast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
        Log.e("AA", "收到Log:" + msg);
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mListView = (ListView) findViewById(R.id.lv_main);
        btnLoadmore = (Button) findViewById(R.id.btn_main_loadmore);
        btnLoadmore.setOnClickListener(this);
        btnAdd = (Button) findViewById(R.id.btn_main_add);
        btnAdd.setOnClickListener(this);
        btnDetele = (Button) findViewById(R.id.btn_main_delete);
        btnDetele.setOnClickListener(this);

        bindAIDLService();
    }

    @Override
    protected void onDestroy() {
        unbindAIDLService();
        super.onDestroy();
    }

    /**
     * 绑定AIDL服务
     */
    private void bindAIDLService() {
        Intent intent = new Intent("com.aa.aidlserver.AIDLService");
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        // Android 5.0以上需要设置包名
        intent.setPackage("com.aa.aidlserver");
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    }

    /**
     * 解绑AIDL服务
     */
    private void unbindAIDLService() {
        if(mIBookManager != null) {
            unbindService(mServiceConnection);
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_main_loadmore:
                //加载更多
                try {
                    List<Book> books = mIBookManager.getBookList();
                    if(books != null && books.size() > 0) {
                        if(mBooks.size() > 0) {
                            mBooks.clear();
                        }

                        //解析数据
                        for(Book book : books) {
                            mBooks.add("Name:" + book.name + " --- Describe:" + book.describe);
                        }
                        //填充数据
                        mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, android.R.id.text1, mBooks);
                        mListView.setAdapter(mAdapter);
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;

            case R.id.btn_main_add:
                //新增图书
                int len = mBooks.size() + 1;
                String name = "图书" + len;
                String describe = "这是第" + len + "本书";
                Book book = new Book(name, describe);
                try {
                    mIBookManager.addBook(book);
                    mBooks.add("Name:" + book.name + " --- Describe:" + book.describe);
                    mAdapter.notifyDataSetChanged();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;

            case R.id.btn_main_delete:
                //删除图书
                if(mBooks.size() > 0) {
                    try {
                        Book book1 = mIBookManager.getBookList().get(0);
                        mIBookManager.deleteBook(book1);
                        mBooks.remove(0);
                        mAdapter.notifyDataSetChanged();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                } else {
                    toast("已经没有书可以删除了");
                }
                break;
        }
    }
}

3、客户端也需要在app的build.gradle文件的android节点中添加以下代码,解决找不到Book类的问题

sourceSets {
    main {
        manifest.srcFile 'src/main/AndroidManifest.xml'
        java.srcDirs = ['src/main/java', 'src/main/aidl']
        resources.srcDirs = ['src/main/java', 'src/main/aidl']
        aidl.srcDirs = ['src/main/aidl']
        res.srcDirs = ['src/main/res']
        assets.srcDirs = ['src/main/assets']
    }
}

其实,AIDL说简单也不简单,难也并不难,还是需要根据实际需求来做的。

CSDN源码下载
Github AIDLServer
Github AIDLClient

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:138658次
    • 积分:2105
    • 等级:
    • 排名:第18780名
    • 原创:68篇
    • 转载:16篇
    • 译文:0篇
    • 评论:66条
    最新评论