2019独角兽企业重金招聘Python工程师标准>>>

(一)项目介绍
Launcher上播放小视屏和独立的视频应用。小视屏是视频应用的裁剪版,只有播放的功能,两者使用相同的底层系统。
系统的初始化会占用比较长的时间,从Launcher上跳转进入app,如果先完全退出结束进程,再重新初始化底层系统,
这样就会耗费不少时间,用户体验会差很多。所以,为了改善这个情况,把底层的部分做成service形式,在Launcher上跳转到其他应用,只是停止了播放,而不结束底层系统。
(二)AIDL
ServiceAidl.aidl 文件定义提供客户端调用的接口
package com.demo.service;
import com.demo.service.Freq;
import  com.demo.service.IServiceCallback;
interface ServiceAidl {
boolean isInited();
void registerCallback(IServiceCallback cb);
void unregisterCallback(IServiceCallback cb);

void playerInit();
int setVideoScale(int full, int x, int y, int width, int height);
void play();
/*自定义类*/
Freq getFreq();
}
aidl里面使用自定义类Freq,需要定义Freq.aidl,然后Freq类需要实现接口Parcelable。Freq(Parcel pl)里面的read的顺序,要和writeToParcel里面write的顺序一直。
public Freq(Parcel pl)
mFreq = pl.readInt(); 
mSymbol = pl.readInt(); 
mQam = pl.readInt(); 
}

@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeInt(this.mFreq);
dest.writeInt(this.mSymbol);
dest.writeInt(this.mQam);
}

//添加一个静态成员,名为CREATOR,该对象实现了Parcelable.Creator接口   
public static final Parcelable.Creator<DvbFreq> CREATOR = new Parcelable.Creator<DvbFreq>(){
@Override
public DvbFreq createFromParcel(Parcel arg0) {
// TODO Auto-generated method stub
return new Freq(arg0);
}
@Override
public DvbFreq[] newArray(int arg0) {
// TODO Auto-generated method stub
return new Freq[arg0];  
}  
};

(三)Service
1、manifest 里面定义
<service
android:name="com.demo.service"
android:enabled="true"
android:exported="true" >
<intent-filter >
<action android:name="com.demo.service.START"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>

2、定义Stub
private final ServiceAidl.Stub mBinder = new ServiceAidl.Stub() {
@Override
public int setVideoScale(int full, int x, int y, int width, int height)
throws RemoteException {
// TODO Auto-generated method stub
return mService.setVideoScale(full, x, y, width, height);
}

@Override
public boolean isInited() throws RemoteException {
// TODO Auto-generated method stub
return  mService.isInited();
}
@Override
public void registerCallback(IServiceCallback cb) throws RemoteException {
// TODO Auto-generated method stub
if (cb != null) mCallbacks.register(cb);
}
@Override
public void unregisterCallback(IDvbServiceCallback cb) throws RemoteException {
// TODO Auto-generated method stub
if (cb != null) mCallbacks.unregister(cb);
}
@Override
public void playerInit() throws RemoteException {
// TODO Auto-generated method stub
mService.playerInit();
}

@Override
public void play() throws RemoteException {
// TODO Auto-generated method stub
mService.play();
}

}
3、重载onBind(Intent intent),客户端bindservice的时候,返回上面定义的mBinder

@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mBinder;
}

(四) Client

1. 导入Service的jar包,或者拷贝service的aidl文件(ServiceAidl.aidl)和aidl里所用到的自定义类文件(Freq.java 和Freq.aidl)
2. 定义Service的aidl接口和connection,
我们调用 startDemoService ()之后,service connected,返回的Binder桩接口取得mServiceAidl接口,这样我们就可以调用Service的aidl文件里面定义的接口了。 注意:我们在startService()的时候,intent的action需要和service 的manifest里面定义的action一致。
private ServiceAidl mService;     // service
private ServiceConnection mConnection;

// 连接service
private void initConnection() {
mConnection = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mService = DvbServiceAidl.Stub.asInterface(service);    
try {
mInitFlag = mService.isInited();
if(mInitFlag) {
mService.playerInit();
mService.registerCallback(mCallback);    // 注册消息回调
mService.setVideoScale(0, 272, 150, 930, 598);    // 设置视频大小和位置
mService.play();     // 播放
}
else {
exitService();  // 初始化失败 退出
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
mService = null;
}
};
}

private void startDemoService() {
Intent intent = new Intent( "com.demo.service.Service.START");
// remote service ,退出activity之后,也不停止service,所以这里bind之后再start
// 具体查看 bindService 、startService以及bindService和startService 同时调用的区别
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);  
startService (intent);
}

3. 因为Service会改变状态,需要去更新ui提示用户状态改变,目前我们已经使用了aidl的方式,所以没办法使用Messenger的方式来发送消息更新,这边使用了回调的方式去更新。
(1)、首先,来看下service端的实现,定义一个RemoteCallbackList和 IServiceCallback的aidl接口由客户端去实现
final static RemoteCallbackList<IServiceCallback> mCallbacks
= new RemoteCallbackList<IServiceCallback>();

package com.feiyue.dvbservice;
oneway interface IServiceCallback {
/*
* handler common message from service
*/
void handlerCommEvent(int msgID, int param);
/*
* handler search message from service
*/
void handlerSearchEvent(int msgID, in List<String> strList);
}

(2)、aidl 定义中有register和unregister两个接口供客户端注册和反注册回调。
void registerCallback(IServiceCallback cb);
void unregisterCallback(IServiceCallback cb);

@Override
public void registerCallback(IDvbServiceCallback cb) throws RemoteException {
// TODO Auto-generated method stub
if (cb != null) mCallbacks.register(cb);
}
@Override
public void unregisterCallback(IDvbServiceCallback cb) throws RemoteException {
// TODO Auto-generated method stub
if (cb != null) mCallbacks.unregister(cb);
}

(3)、service 状态改变,通知client更新ui,这边我们组了一个Message的形式转给客户端
final int N = mCallbacks.beginBroadcast();

for (int i=0; i<N; i++) {
                try {
                    switch(service.status) {
                        case Msg.SHOW__MSG:
                        case Msg.HIDE__MSG:
                            Bundle b = new Bundle();
                            ArrayList<String> strList = new ArrayList<String>();
                            
                            b = msg.getData();
                            strList.add(b.getString("MSGTIP")); // 提示框消息
                        
                            mCallbacks.getBroadcastItem(i).handlerSearchEvent(msg.what, strList); 
                            break;
                        default:
                            break;
                    }
                    
                } catch (RemoteException e) {
                    // The RemoteCallbackList will take care of removing
                    // the dead object for us.
                }
            }

mCallbacks.finishBroadcast();
4. Client端实现
(1)、实现 IServiceCallback的接口, mHandler是客户端实现的消息处理。
private IServiceCallback mCallback = new IServiceCallback.Stub() {
@Override
public void handlerCommEvent(int msgID, int param) throws RemoteException {
// TODO Auto-generated method stub
Message msg = new Message();
msg.what = msgID;
msg.arg1 = param;
mHandler.sendMessage(msg);  
}
@Override
public void handlerSearchEvent(int msgID, List<String> strList) throws RemoteException {
// TODO Auto-generated method stub
Message msg = new Message();
Bundle b = new Bundle();
msg.what = msgID;
switch (msgID) {
case Msg.SHOW_MSG:
case Msg.HIDE_MSG:
b.putString("MSGTIP",strList.get(0));    // ca提示框消息
break;
default:
break;
}
msg.setData(b);
mHandler.sendMessage(msg);
}
};

(2)、在service connected 的时候去注册这个回调,在退出activity反注册callback 和unbindservice
mService.unregisterCallback(mCallback);
if(mConnection != null) {
unbindService(mConnection);
mConnection = null;
}

到此,基本就已经完成了,service和client相互间的通信! 

我的第一次写记录,勉之!

Demo:  https://github.com/yqb178/AidlDemo

转载于:https://my.oschina.net/u/1034996/blog/153362

Android service 和 client的进程通信和消息回调--AIDL相关推荐

  1. Android跨进程通信Binder机制与AIDL实例

    文章目录 进程通信 1.1 进程空间划分 1.2 跨进程通信IPC 1.3 Linux跨进程通信 1.4 Android进程通信 Binder跨进程通信 2.1 Binder简介 2.2 Binder ...

  2. python笔记 7-8 进程池 进程通信 迭代器 消息队列 Queue 协程 和正则表达式

    day7 进程 进程池 进程通信 迭代器 消息队列 Queue 作用 用于多个进程间的通信 操作put放入消息(值) put_nowait() 放入值,不等待 如果队满,则报错 get获取消息(值) ...

  3. 安卓跨进程通信:Messenger、AIDL远程Service 使用

    Messenger 服务端 创建Service: public class MessengerService extends Service {private static final int MSG ...

  4. windows进程通信 -- WM_COPYDATA消息

    WM_COPYDATA消息,在win32中用来进行进程间的数据传输. typedef struct tagCOPYDATASTRUCT { // cds DWORD dwData; DWORD cbD ...

  5. Linux进程通信之消息队列

    目录 1.消息队列的原理: 2.消息队列的接口: (1)创建消息队列 (2)向消息队列发送消息 (3)接收消息 (4)操作消息队列的接口 1.消息队列的原理: 消息队列(messagequeue)以链 ...

  6. Android跨进程通信一 Messenger

    实现客户端与服务端之间的交互 说明:         Messenger是信使的意思,从它的名字就可以了解到它充当着信差的角色.Android通过它实现跨进程通信,主要有客户端信使与服务端信使两种角色 ...

  7. 【朝花夕拾】Android跨进程通信总结篇

    前言 原文:https://www.cnblogs.com/andy-songwei/p/10256379.html 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一. ...

  8. 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10256379.html],谢谢! 只要是面试高级工程师岗位,Android跨进程通信就是最受面 ...

  9. 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇...

    前言 原文:https://www.cnblogs.com/andy-songwei/p/10256379.html 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一. ...

最新文章

  1. 23. 进程并发控制之Semaphore
  2. 大牛书单 | 腾讯技术大咖推荐你五一看这些书
  3. ACM 网址和一些建议
  4. 三菱goto怎么用_GOTO语句使用方法
  5. access中case替代方法
  6. python小测验3_python基础小测试
  7. SQL server 2008 r2 安装出错 Could not open key:
  8. 台达plc接线图实物_台达PLC dvp-14es 外部电路怎么接线
  9. 量化视角下的基金定投策略
  10. python的快捷键是什么意思_Python基础知识—快捷键
  11. mac重置系统_如何在Mac上重置打印系统
  12. 商业智能,数据仓库,ETL,数仓调度工具informatica介绍手账(一)
  13. 解决小程序canvas高清屏模糊问题
  14. 信源编码作业(1)——绘制并分析清浊音频谱图
  15. Linux网络技术学习(一)—— sk_buff数据结构解析
  16. codeforces 1090B切题记录
  17. VSCode . Syncing还原配置
  18. Shell中显示彩色二维码
  19. 0 公式 0 基础学习电磁兼容 — 1. EMC 测试类型简介
  20. 用户登录注册流程图-所有项目论文通用计算机毕业设计

热门文章

  1. oracle创建一个学生,oracle 创建学生选课视图
  2. python方法与重载_python特殊方法和运算符重载(番外--重载)
  3. 安卓学习笔记17:常用控件 - 编辑框
  4. 大数据学习笔记03:安装配置CentOS7虚拟机
  5. python获取手机号码归属地_Python批量获取并保存手机号归属地和运营商的示例
  6. bootstrap文件不能被识别_Spring Boot 配置文件 bootstrap / application 到底有什么区别?...
  7. c语言block内部的实现原理,iOS中block变量捕获原理详析
  8. MFC 常见窗口操作
  9. CentOS7 安装lua环境
  10. 使用nohup以守护进程方式启动程序