今天学习一下osc客户端的消息模块主要使用了动态receiver注册和静态注册,具体的功能有:
1.获取用户新的动态 并弹出notification显示 如果app在前台还要更新UI显示
2.发送完动弹后的UI通知更新机制
3.当前list内容有更新时候的Toast通知
其实3 并不能算是真正的消息机制,但是这里还是并入这个模块分析
1.新动态的消息机制
osc的获取动态通知的实现比较简单,是轮询.当然,对于osc这样的实时性不是很强应用来说使用http轮询就可以了,不必使用一些xmpp什么的增加成本
在app启动的时候会使用foreachUserNotice()函数来启动轮询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
/**
* 轮询通知信息
*/
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的这里就不分析了.
这样有个小问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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中静态注册的
1 2 3 4 5 |
<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
1 2 3 4 5 |
// 注册广播接收器
tweetReceiver = new TweetReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("net.oschina.app.action.APP_TWEETPUB");
registerReceiver(tweetReceiver, filter);
|
在tweetpub中 发送了动弹之后会执行:
1 |
UIHelper.sendBroadCastTweet(TweetPub.this, what, res, tweet);
|
1 2 3 4 5 6 7 8 9 10 11 12 |
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然后重新启动刚刚初始化的那个发送动弹的线程:
1 2 3 4 |
if (TweetPub.mContext != null)
UIHelper.showResendTweetDialog(TweetPub.mContext, thread);
else
UIHelper.showResendTweetDialog(context, thread);
|
然后在handler中进行发送结果的处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
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通知
这是一个小知识点,其实应该在第一章介绍的.功能如图所示:
这个是在handler中调用handleLvData()函数的时候触发的,代码:
1 2 3 4 5 |
NewDataToast
.makeText(
this,
getString(R.string.new_data_toast_message,
newdata), appContext.isAppSound())
|
原理是自定义了一个Toast,虽然很简单,但是用户交互很好:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
/**
* 新数据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;
}
}
|
声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息
原文作者: sfshine