Android开源中国客户端学习 消息模块 <9>

今天学习一下osc客户端的消息模块主要使用了动态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通知

这是一个小知识点,其实应该在第一章介绍的.功能如图所示:



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

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;
    }
	
}

转载于:https://my.oschina.net/sfshine/blog/145997

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值