zoukankan      html  css  js  c++  java
  • OSChinaclient源代码学习(3)--轮询机制的实现

    主要以OSChina Androidclient源代码中Notice的轮询机制进行解读。

    一、基础知识

    1. 一般IM(即使通讯)的实现有两种方式:推送和轮询,推送就是server主动向client发送消息,用特定的协议比方XMPP、MQTT。

      还有一种是轮询,实时性并不高。并且比較耗电。这样的有分为两种情况:一段时间发起一次查询和死循环进行查询。
      參考: http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0401/1609.html

    2. 远端Service调用:
      a.服务端:
      0.自己定义接口 (AIDL定义接口文件),然后自己主动生成相应的java类。
      1.继承Stub类。复写接口中定义的方法
      2.将1中的类对象作为Service中onBind方法的返回值,也就是将来信息交流的使者。
      b.client
      3.在Activity或其它工具类中。创建ServiceConnection 对象。在onServiceConnected回调方法中,将第二个參数转化赋值给本地变量,通过这个变量进行与远端服务交互(通信)。

    以上总结非常简陋,后面我会结合OSChina的Android源代码具体为大家解读。

    參考:http://blog.csdn.net/guolin_blog/article/details/9797169

    二、源代码解析

    1 绑定了服务

    首先在MainActivity中绑定了服务(开启了服务)

    MainActivity初始化init()中

    NoticeUtils.bindToService(this);

    当中bindToService实现

    public staticboolean bindToService(Context context,
               ServiceConnection callback) {
    //直接开启本地NoticeService服务,(注:startService方式并不能进行进行通信)
           context.startService(new Intent(context, NoticeService.class));
    //绑定远程NoticeService 服务,
    //csp:为什么同一个服务用两种不同的方式开启?
    //answer: 可能是先开启本地服务,然后把绑定本地服务当做远程服务来处理,目的可能是为了创造不同的进程。提高效率?
           ServiceBinder sb = new ServiceBinder(callback);
           sConnectionMap.put(context, sb);
    
           return context.bindService(
                    (newIntent()).setClass(context, NoticeService.class), sb, 0);
        }
    
    //最后。总之开启了服务NoticeService

    2 採用Service+AlarmManager+Thread方式轮询

    在NoticeService中的onCreate方法中用AlarmManager的方式,每隔2分钟运行一次(轮询)请求。看是否有新的消息通知(这样的方式适合通信实时性不高的情况,比方论坛的回复,你并不须要立刻知道别人的回复,晚个1-2分钟是能够接受的。

    mAlarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
           startRequestAlarm();
    private voidstartRequestAlarm() {
           cancelRequestAlarm();
           // 从1秒后開始,每隔2分钟运行getOperationIntent()
           mAlarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,
                    System.currentTimeMillis()+ 1000, INTERVAL,
                    getOperationIntent());
        }

    当中getOperationIntent()实现例如以下:

      /**
        * OSC採用轮询方式实现消息推送<br>
        * 每次被调用都去运行一次{@link #AlarmReceiver}onReceive()方法
        *
        * @return
        */
        privatePendingIntent getOperationIntent() {
           Intent intent = new Intent(this, AlarmReceiver.class);
           PendingIntent operation = PendingIntent.getBroadcast(this,0, intent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
           return operation;
    }

    在AlarmReceiver类中调用NoticeUtils.requestNotice方法例如以下
    该方法首先推断远端Service的onBind返回来的sService对象是否为空。假设连接上了。不为空,则调用该sService对象的方法requestNotice(),否则发送广播,请求訪问server更新Notice

     publicstatic void requestNotice(Context context) {
           if (sService != null) {
               try {
                    TLog.log("requestNotice...");
                    //这里的sService。在以下进行具体的解读
                    sService.requestNotice();
               } catch (RemoteException e) {
                    e.printStackTrace();
               }
           } else {
               context.sendBroadcast(new Intent(
                        NoticeService.INTENT_ACTION_REQUEST));
               TLog.log("requestNotice,service is null");
    

    最后就是requestNotice的实现了:

        publicstatic void getNotices(AsyncHttpResponseHandler handler) {
           RequestParams params = new RequestParams();
           params.put("uid", AppContext.getInstance().getLoginUid());
           ApiHttpClient.get("action/api/user_notice", params, handler);
        }

    3 具体解读requestNotice中的sService

    还是先上源代码,以下是调用远程Service的步骤:
    (0)用AIDL自己定义一 个接口文件INoticeService.aidl

     package net.oschina.app.service;
    interface INoticeService
    { 
       void scheduleNotice();
       void requestNotice();
       void clearNotice(int uid,int type);
    } 

    然后点击保存之后,gen文件夹下就会生成一个相应的Java文件:INoticeService.java

    这里写图片描写叙述

    然后。我们打开看一下里面的代码:

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: E:\oschina-android-app-v2.2.1\android-app\osc-android-app\src\net\oschina\app\service\INoticeService.aidl
     */
    package net.oschina.app.service;
    public interface INoticeService extends android.os.IInterface
    {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements net.oschina.app.service.INoticeService
    {
    ...//Stub类的内容较长。我在此省略
    }
    public void scheduleNotice() throws android.os.RemoteException;
    public void requestNotice() throws android.os.RemoteException;
    public void clearNotice(int uid, int type) throws android.os.RemoteException;
    }
    

    ADT自带工具aidl.exe生成的代码的看点在于,生成了一个Stub类。该类1.继承了Binder(Binder是IBinder接口的一个实现类)因此将来能够作为Service的onBind方法的返回值,2.实现了自己定义的接口(INoticeService.aidl),将来能够复写或调用。

    (1)定义一个Stub的子类:ServiceStub,复写自己定义接口中的三个方法。

     private static class ServiceStub extends INoticeService.Stub {
            WeakReference<NoticeService> mService;
    
            ServiceStub(NoticeService service) {
                mService = new WeakReference<NoticeService>(service);
            }
    
            @Override
            public void clearNotice(int uid, int type) throws RemoteException {
                mService.get().clearNotice(uid, type);
            }
    
            @Override
            public void scheduleNotice() throws RemoteException {
                mService.get().startRequestAlarm();
            }
    
            @Override
            public void requestNotice() throws RemoteException {
                mService.get().requestNotice();
            }
        }

    (2)在NoticeService中将(1)的对象作为onBind方法的返回值返回。

    
       private final IBinder mBinder = new ServiceStub(this);
    
       @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
    

    (3)创建ServiceConnection 对象
    源代码在NoticeUtils中定义了一个ServiceBinder 类实现ServiceConnection 接口,复写了两个回调函数(当连接远端服务成功和连接远端服务失败)

    
     private static class ServiceBinder implements ServiceConnection {
            ServiceConnection mCallback;
    
            ServiceBinder(ServiceConnection callback) {
                mCallback = callback;
            }
    
            @Override
            public void onServiceConnected(ComponentName className,
                    android.os.IBinder service) {
                //第二个參数service:获取远程Service的onBind方法返回的对象的代理
                //以下一句是将代理转换为对象
                sService = INoticeService.Stub.asInterface(service);
                if (mCallback != null) {
                    mCallback.onServiceConnected(className, service);
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName className) {
                if (mCallback != null) {
                    mCallback.onServiceDisconnected(className);
                }
                sService = null;
            }
        }

    上面的代码告诉我们。假设连接远端服务(NoticeService)成功,则能够通过远端onBind方法返回的对象(即onServiceConnected方法的第二个參数)来进行通信,这里值得一说的是远端服务返回来的仅仅是对象的代理,这一点差别于绑定本地服务,所以要进行转换。转化的方法就是这一句: sService = INoticeService.Stub.asInterface(service)。
    至此,我们已经彻底知道了sService的由来。

    三、总结

    1. 通过阅读这一部分的源代码,我大致理清了client通过轮询的方式实现IM的同步的过程。
    2. 远端Service的用法。

      这里补充几点:
      a. MainAcitivy中开一个Service。实际上是在同一个线程中。所以不要将耗时操作直接写在Service的onCreate方法里。而应该另外开启一个线程去操作 。
      能够參考:http://blog.csdn.net/guolin_blog/article/details/11952435
      b. 所谓绑定“远端服务”(有的书上叫远程服务)。本质就是IPC(inter process communication)跨进程通信,Android提供了AIDL Service,底层是又Binder机制实现。注意:这里说的“远端”不是C/S中的Server,而是充当提供服务的Service,它能够用来共享,全部訪问远端Service的。都被统称为Client。
      所以,说白了。这里扮演C/S的,能够是两个不同的进程,能够是两个不同的应用程序,当中一个应用程序共享了自己的一个Service组件。充当还有一个应用程序的远端Service。还有一个应用程序则充当Client的角色,能够进行訪问远端Service

    最后,欢迎拍砖。。。

    作者:项昂之
    时间:2015.7.20
    转载注明出处:http://blog.csdn.net/csp277?viewmode=list

  • 相关阅读:
    Django框架---- 自定义分页组件
    Django框架----Form组件补充
    ARM体系的异常中断
    ARM处理机模式--内部寄存器
    产品概述
    简单应用程序的设计 -重复前缀
    简单应用程序的设计字符串处理
    基本输入输出系统BIOS---显示输出
    基本输入输出系统BIOS---键盘输入
    中断
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/7190365.html
Copyright © 2011-2022 走看看