Android service 和 client的进程通信和消息回调--AIDL

(一)项目介绍
    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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值