在TV实际开发中需要使用到监听,来实时更新UI,下面以ATV搜台为例子,搜台时,底层C++发送消息,app中来更新UI。下面具体来分析。

Activity中代码如下:

oncreate中:

     

private OnAtvPlayerEventListener mAtvPlayerEventListener = new AtvPlayerEventListener();
         TvChannelManager.getInstance().registerOnAtvPlayerEventListener(mAtvPlayerEventListener);//进行注册

onpause中:        

       

TvChannelManager.getInstance().unregisterOnAtvPlayerEventListener(mAtvPlayerEventListener);//进行解注册
         mAtvPlayerEventListener = null;
      private class AtvPlayerEventListener implements OnAtvPlayerEventListener {
        @Override
         public boolean onAtvAutoTuningScanInfo(int what, AtvEventScan extra) {
             Message msg = mAtvUiEventHandler.obtainMessage(what, extra);
             mAtvUiEventHandler.sendMessage(msg); //使用handle去更新UI 具体代码不展示了
             return true;
         } }

 

OnAtvPlayerEventListener 代表监听器,实现监听中的方法:onAtvAutoTuningScanInfo

activity中的代码显示需要onAtvAutoTuningScanInfo方法被调用,从而达到刷新UI的目的。

那我们需要在TvChannelManager这个类中进行方法的调用,代码如下:

private ArrayList<OnAtvPlayerEventListener> mAtvListeners = new ArrayList<OnAtvPlayerEventListener>();
    @Deprecated
     public boolean registerOnAtvPlayerEventListener(OnAtvPlayerEventListener listener) {
         Log.d(TAG, "registerOnAtvPlayerEventListener ");
         synchronized (mAtvListeners) {
             mAtvListeners.add(listener);//注册
         }
         return true;
     }    @Deprecated
     public synchronized boolean unregisterOnAtvPlayerEventListener(OnAtvPlayerEventListener listener) {
         synchronized (mAtvListeners) {
             mAtvListeners.remove(listener);//解注册
             Log.d(TAG, "unregisterOnAtvPlayerEventListener  size: " + mAtvListeners.size());
         }
         return true;
     }


代码比较简单,创建一个接口的ArrayList,进行注册与解注册,作用是:任意一个activity中进行注册了此监听,就都能够接收到该监听。

下面来看监听方法被调用的代码:

private class EventHandler extends Handler {
         EventHandler(Looper looper) {
             super(looper);
         }        @Override
         public void handleMessage(Message msg) {        switch (msg.what) {
                case TVPLAYER_ATV_AUTO_TUNING_SCAN_INFO: {
                     synchronized (mAtvListeners) {
                         for (OnAtvPlayerEventListener l : mAtvListeners) {
                             Bundle data = msg.peekData();
                             data.setClassLoader(AtvEventScan.class.getClassLoader());
                             Object msgObj = data.getParcelable("messageObj");
                             l.onAtvAutoTuningScanInfo(msg.what, (AtvEventScan)msgObj);
                         }
                     }
                 }

handle中,只要是ArrayList中的OnAtvPlayerEventListener,都会调用方法onAtvAutoTuningScanInfo

那么继续看这个handle在哪里被调用:

private EventHandler mHandler = null;
        Looper looper;
         if ((looper = Looper.myLooper()) != null) {
             mHandler = new EventHandler(looper);
         } else if ((looper = Looper.getMainLooper()) != null) {
             mHandler = new EventHandler(looper);
         } else {
             mHandler = null;
         }    @Override
     public boolean onEvent(Message msg) throws RemoteException {
         if (mHandler != null) {
             Message msgTmp = mHandler.obtainMessage();
             msgTmp.copyFrom(msg);
             mHandler.sendMessage(msgTmp);
         }
         return true;
     }

在TvChannelManager的构造函数中,进行handle的实例化。如果是主线程中,那么就会有Looper,若是在子线程中则需要获取Looper。

TvChannelManager中重写的onEvent方法调用handler去发消息

那么看一下该类继承会实现了什么:下面可以看见继承了IEventClient.aidl。

public class TvChannelManager extends IEventClient.Stub

aidl中如下:

interface IEventClient {
     boolean onEvent(in Message msg);
 }

那么是不是到此处就完了呢?  还早呢,上面代码只是继承了aidl,并实现了aidl中的方法,那么哪里调用这个onEvent呢?

既然TvChannelManager是继承IEventClient.aidl,那么属于一个binder,而binder大多数时候可以作为方法的参数,猜想一定有方法的使用了TvChannelManager的实例进行参数传递。

TvChannelManager的构造方法中:

 

IBinder b = ServiceManager.getService("tv");
             ITvChannel mService = ITvService.Stub.asInterface(b).getTvChannel();
             mService.addClient(this);

三行简单代码,主要的含义就是IPC跨进程通信,具体不深入了,主要代码就是获取到一个ITvChannel binder(如下),然后调用addClient方法。

public class TvChannelService extends ITvChannel.Stub{
    @Override
     public void addClient(IBinder client) throws RemoteException {
         DeskTvCommonEventListener.getInstance().setClient(client);
     }}

addClient的参数为IBinder,而恰巧TvChannelManager是继承于aidl,自然也是一个binder。

DeskTvCommonEventListener中的代码如下:

public class DeskTvCommonEventListener implements OnEventListener {
    private static DeskTvCommonEventListener mListener = null;
    private static final String TAG = "DeskTvCommonEventListener";
    private RemoteCallbackList<IEventClient> mCallbackList = null;
    private HashMap<IBinder, IEventClient> mMap = null;
    private DeskTvCommonEventListener() {
         mCallbackList = new RemoteCallbackList<IEventClient>() {            @Override
             public void onCallbackDied(IEventClient client) {
                 mMap.remove(client.asBinder());
             }
         };
         mMap = new HashMap<IBinder, IEventClient>();
     }    public static DeskTvCommonEventListener getInstance() {
         if (mListener == null) {
             mListener = new DeskTvCommonEventListener();
         }        return mListener;
     }    public void setClient(IBinder client) {
         if (client != null) {
             IEventClient TvCommonEventClient = IEventClient.Stub.asInterface(client);
             mCallbackList.register(TvCommonEventClient);
             mMap.put(client, TvCommonEventClient);
         }
     }    public void releaseClient(IBinder client) {
         if (client != null) {
             IEventClient tvCommonEventClient = mMap.get(client);
             if (null != tvCommonEventClient) {
                 mCallbackList.unregister(tvCommonEventClient);
             }
             mMap.remove(client);
         }
     }    @Override
     synchronized public boolean onEvent(Message msg) {
         if (mCallbackList == null) {
             return false;
         }        int count = mCallbackList.beginBroadcast();
         while (count > 0) {
             count--;
             try {
                 mCallbackList.getBroadcastItem(count).onEvent(msg);
             } catch (RemoteException e) {
                 e.printStackTrace();
             }
         }
         mCallbackList.finishBroadcast();
         return true;
     }
 }


DeskTvCommonEventListener中的主要的是RemoteCallbackList这个类,这个可以自行百度,或者查看android开发艺术与探索书籍,主要的就是可以删除远程接口的意思。

mCallbackList.getBroadcastItem(count).onEvent(msg);调用onEvent。

那么DeskTvCommonEventListener哪里调用呢?DeskTvCommonEventListener是实现于接口OnEventListener,加上该类也单例模式设计,那么也会有 把DeskTvCommonEventListener作为方法的参数进行传递。

private DeskTvCommonEventListener mTvCommonEventListener = null;
        mTvCommonEventListener = DeskTvCommonEventListener.getInstance();
         TvManager.getInstance().getPlayerManager().setOnEventListener(mTvCommonEventListener);

果不其然,那么我们就找到setOnEventListener该方法。   

private OnEventListener mOnEventListener;
    public void setOnEventListener(OnEventListener listener) {
         mOnEventListener = listener;
     }    private class EventHandler extends Handler {
         private PlayerImpl mMSrv;        public EventHandler(PlayerImpl srv, Looper looper) {
             super(looper);
             mMSrv = srv;
         }        @Override
         public void handleMessage(Message msg) {
             TvOsType.EnumInputSource inputSource = null;            if (mMSrv.mNativeContext == 0) {
                 return;
             }            if (mOnEventListener != null) {
                 final String MESSAGE_OBJ = "messageObj";
                 Bundle bundle = new Bundle();
                 bundle.putParcelable(MESSAGE_OBJ, (Parcelable) msg.obj);
                 switch (msg.what) {
                     case TVPLAYER_DTV_AUTO_TUNING_SCAN_INFO:
                         msg.setData(bundle);
                         break;
                     case TVPLAYER_ATV_MANUAL_TUNING_SCAN_INFO:
                         msg.setData(bundle);
                         break;
                     case TVPLAYER_ATV_AUTO_TUNING_SCAN_INFO:
                         msg.setData(bundle);
                         break;
                     case TVPLAYER_HBBTV_UI_EVENT:
                         msg.setData(bundle);
                         break;
                 }
                 msg.obj = null;
                 mOnEventListener.onEvent(msg);//总算找到调用的地方了!
                 msg.obj = bundle.getParcelable(MESSAGE_OBJ);
             }}

代码就是一个handle中调用了DeskTvCommonEventListener的onEvent方法。

private static void postEventFromNative(Object srv_ref, int what, int arg1, int arg2, Object obj) {
         PlayerImpl srv = (PlayerImpl)((WeakReference) srv_ref).get();
         if (srv == null) {
             return;
         }        if (srv.mEventHandler != null) {
             Message m = srv.mEventHandler.obtainMessage(what, arg1, arg2, obj);
             srv.mEventHandler.sendMessage(m);
         }
         return;
     }

postEventFromNative该方法为静态方法,该类中有很多native方法,所以很显然postEventFromNative会被JNI那边调用。

继续查看JNI代码:

void com_mstar_android_tvapi_impl_PlayerImpl_native_init
 (JNIEnv *env) {
     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");}
void JNIMSrvListener::notifyCB(int32_t event, int32_t ext1, int32_t ext2, const Parcel* pacelObj) {
     ALOGE("notifyCB event = %d\n", event);
     jint msg;
     jobject jobj = NULL;
     JNIEnv *env = NULL;
     if(mJvm == NULL ||  mJvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
         ALOGE("Error! %s(%d) AttachCurrentThread \n", __FUNCTION__, __LINE__);
     }    switch (event) {//只列出一个event,作为示例
         case EV_INPUT_SOURCE_LOCK:
             msg = fields.TVPLAYER_INPUT_SOURCE_LOCK;
             break;
         }
     env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
             msg, ext1, ext2, jobj);
 }

notifyCB中调用了静态方法postEventFromNative。

void JNIMSrvListener::PostEvent_PvrRecordTime(int32_t ext1, int32_t ext2) {//举个例子
     ALOGD("PostEvent_PvrRecordTime");
     notifyCB(EV_PVR_NOTIFY_RECORD_TIME, ext1, ext2, NULL);
 }

PostEvent是主要疑惑点,由于作者也没有找到PostEvent的相关代码,也不好分析,究竟是怎样从C++到JNI中来的!这里面也会涉及到HIDL、binder比较难!也请高手指教下!

C++中都是直接这么使用PostEvent,暂时也没有找到相关PostEvent的源码(如下)。所以如果现在系统代码中有PostEvent找个函数的话,我们就可以参照此流程进行添加自定义的监听事件!

GetMSrvPlayer(eMapiSrcType)->PostEvent(NULL, EV_INPUT_SOURCE_LOCK, E_INPUT_SOURCE_LOCK_EVENT_ON, E_INPUT_SOURCE_LOCK_EVENT_UNDEFINED);