Android网站客户端学习 消息模块

今天我们以osc(开源中国网)客户端为例学习一下[消息模块](javascript:;)主要使用的动态receiver注册和静态注册。
具体的功能有:

1.获取用户新的动态 并弹出notification显示 如果app在前台还要更新UI显示
2.发送完动弹后的UI通知更新机制
3.当前list内容有更新时候的Toast通知
其实3 并不能算是真正的消息机制,但是这里还是并入这个模块分析

1.新动态的消息机制

osc的获取动态通知的实现比较简单,是轮询.当然,对于osc这样的实时性不是很强应用来说使用http轮询就可以了,不必使用一些xmpp什么的增加成本
在app启动的时候会使用foreachUserNotice()函数来启动轮询

 /**
 * 轮询通知信息
 */
private void foreachUserNotice() {
    final int uid = appContext.getLoginUid();
    final Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                UIHelper.sendBroadCast(Main.this, (Notice) msg.obj);
            }
            foreachUserNotice();// 回调
        }
    };
    new Thread() {
        public void run() {
            Message msg = new Message();
            try {
                sleep(60 * 1000);
                if (uid > 0) {
                    Notice notice = appContext.getUserNotice(uid);
                    msg.what = 1;
                    msg.obj = notice;
                } else {
                    msg.what = 0;
                }
            } catch (AppException e) {
                e.printStackTrace();
                msg.what = -1;
            } catch (Exception e) {
                e.printStackTrace();
                msg.what = -1;
            }
            handler.sendMessage(msg);
        }
    }.start();
}

代码很简单,就是通过递归的方式 , 每隔60秒 想服务器请求一次notice ,网络的数据也是xml的这里就不分析了.

这样有个小问题
Message msg = new Message();
这句话最好用hander.obtaiMessage()或者
Message msg = Message.obtain();
来获取Message 这样可以节约资源浪费
如果有消息更新 就发送广播,这个就是就比较简单了sendBroadCast函数在UIHelper中:

  public static void sendBroadCast(Context context, Notice notice) {
       if (!((AppContext) context.getApplicationContext()).isLogin()
               || notice == null)
           return;
       Intent intent = new Intent("net.oschina.app.action.APPWIDGET_UPDATE");
       intent.putExtra("atmeCount", notice.getAtmeCount());
       intent.putExtra("msgCount", notice.getMsgCount());
       intent.putExtra("reviewCount", notice.getReviewCount());
       intent.putExtra("newFansCount", notice.getNewFansCount());
       context.sendBroadcast(intent);
}

这个receiver是在xml中静态注册的

  <receiver android:name=".ui.BroadCast">
        <intent-filter>
            <action android:name="net.oschina.app.action.APPWIDGET_UPDATE" />
        </intent-filter>
    </receiver>

BroadCast.java这个Receiver的代码就不贴了 主要做两件事:

a更新应用中各个 气泡的消息数量
b弹出notification

在更新了list后 还会调用main中的ClearNotice()成员函数 通知服务器更新未读消息列表,这个不再赘述

2.发送动弹后的消息更新机制

发送动弹后,pub 的activity会发送一个消息给main ,main会有一些几个行为

a发送成功,返回main并更新
b发送失败,dialog提示用户重新发送,如果还是失败,那么提示用户网络错误

其实个人感觉这个行为应该直接由tweetpub来处理而不应该通过消息机制让main来处理,main只需要知道是否发送成功就可以了,但是这里还是分析一下动态注册receiver的使用:
在应用打开的时候调用首先会动态注册一个Receiver

 // 注册广播接收器
    tweetReceiver = new TweetReceiver();
    IntentFilter filter = new IntentFilter();
    filter.addAction("net.oschina.app.action.APP_TWEETPUB");
    registerReceiver(tweetReceiver, filter);

在tweetpub中 发送了动弹之后会执行:
UIHelper.sendBroadCastTweet(TweetPub.this, what, res, tweet);

public static void sendBroadCastTweet(Context context, int what,
        Result res, Tweet tweet) {
    if (res == null && tweet == null)
        return;
    Intent intent = new Intent("net.oschina.app.action.APP_TWEETPUB");
    intent.putExtra("MSG_WHAT", what);
    if (what == 1)
        intent.putExtra("RESULT", res);
    else
        intent.putExtra("TWEET", tweet);
    context.sendBroadcast(intent);
}

ok 这样Main的内部类 TweetReceiver的onReceive函数可以被回调了:

如果成功就自己更新UI 这里请自行看代码
如果失败就会初始化一个thread和一个handler然后重新启动刚刚初始化的那个发送动弹的线程:

if (TweetPub.mContext != null)
   UIHelper.showResendTweetDialog(TweetPub.mContext, thread);
   else        
   UIHelper.showResendTweetDialog(context, thread);

然后在handler中进行发送结果的处理:

final Handler handler = new Handler() {
                public void handleMessage(Message msg) {
                    if (msg.what == 1) {
                        Result res = (Result) msg.obj;
                        UIHelper.ToastMessage(context,res.getErrorMessage(), 1000);
                        if (res.OK()) {
                            // 发送通知广播
                            if (res.getNotice() != null) {
                                UIHelper.sendBroadCast(context,res.getNotice());
                            }
                            // 发完动弹后-刷新最新、我的动弹&最新动态
                            if (curTweetCatalog >= 0 && mCurSel == 2) {
                                loadLvTweetData(curTweetCatalog, 0,lvTweetHandler,UIHelper.LISTVIEW_ACTION_REFRESH);
                            } else if (curActiveCatalog == ActiveList.CATALOG_LASTEST&& mCurSel == 3) {
                                loadLvActiveData(curActiveCatalog, 0,lvActiveHandler,UIHelper.LISTVIEW_ACTION_REFRESH);
                            }
                            if (TweetPub.mContext != null) {
                                // 清除动弹保存的临时编辑内容
                                appContext.removeProperty(AppConfig.TEMP_TWEET,AppConfig.TEMP_TWEET_IMAGE);
                                ((Activity) TweetPub.mContext).finish();
                            }
                        }
                    } else {
                        ((AppException) msg.obj).makeToast(context);
                        if (TweetPub.mContext != null&&TweetPub.mMessage != null)
                            TweetPub.mMessage.setVisibility(View.GONE);
                    }
                }
            };

主要:

发送成功:更新UI
发送失败:progressdialog dismisse掉然后提示用户发送失败.

3.当前list内容有更新时候的Toast通知

这是一个小知识点,其实应该在第一章介绍的.功能如图所示:
![](http://www.zhuitaiyang.com/uploadfile/2013/0722/20130722114108256.png)

这个是在handler中调用handleLvDate()函数的时候触发的,代码:

    NewDataToast.makeText(this, getString(R.string.new_data_toast_message,newdata), appContext.isAppSound()) 

原理是自定义了一个Toast,虽然很简单,但是用户交互很好:

/**
* 新数据Toast提示控件(带音乐播放)
* @author liux (http://my.oschina.net/liux)
* @version 1.0
* @created 2012-8-30
*/
public class NewDataToast extends Toast{
 
private MediaPlayer mPlayer;
private boolean isSound;
 
public NewDataToast(Context context) {
    this(context, false);
}
 
public NewDataToast(Context context, boolean isSound) {
    super(context);
     
    this.isSound = isSound;

    mPlayer = MediaPlayer.create(context, R.raw.newdatatoast);
    mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
        @Override
        public void onCompletion(MediaPlayer mp) {
            mp.release();
        }           
    });

}

@Override
public void show() {
    super.show();
     
    if(isSound){
        mPlayer.start();
    }
}
 
/**
 * 设置是否播放声音
 */
public void setIsSound(boolean isSound) {
    this.isSound = isSound;
}
 
/**
 * 获取控件实例
 * @param context
 * @param text 提示消息
 * @param isSound 是否播放声音
 * @return
 */
public static NewDataToast makeText(Context context, CharSequence text, boolean isSound) {
    NewDataToast result = new NewDataToast(context, isSound);
     
    LayoutInflater inflate = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     
    DisplayMetrics dm = context.getResources().getDisplayMetrics();
     
    View v = inflate.inflate(R.layout.new_data_toast, null);
    v.setMinimumWidth(dm.widthPixels);//设置控件最小宽度为手机屏幕宽度
     
    TextView tv = (TextView)v.findViewById(R.id.new_data_toast_message);
    tv.setText(text);
     
    result.setView(v);
    result.setDuration(600);
    result.setGravity(Gravity.TOP, 0, (int)(dm.density*75));

    return result;
   }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,657评论 18 139
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,715评论 0 9
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,144评论 25 707
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,143评论 30 470
  • 山村的夜,没有城市车水马龙的喧嚣,没有霓虹灯下的浪漫,没有行色匆匆的路人,没有路边摊烧烤味……除了池塘里的蛙声,菜...
    爱妃给朕笑一个阅读 163评论 0 0