中山大学智慧健康服务平台应用开发-Broadcast使用

Jonesy

发布日期: 2019-07-17 23:38:40 浏览量: 122
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

一、实验题目

中山大学智慧健康服务平台应用开发

二、实现内容

2.1 Broadcast 使用

2.1.1 实验目的

  • 掌握 Broadcast 编程基础

  • 掌握动态注册 Broadcast 和静态注册 Broadcast

  • 掌握Notification 编程基础

  • 掌握 EventBus 编程基础

2.1.2 实验内容

在之前的基础上,实现静态广播、动态广播两种改变Notification 内容的方法。

要求

在启动应用时,会有通知产生,随机推荐一个食品

点击通知跳转到所推荐食品的详情界面

点击收藏图标,会有对应通知产生,并通过Eventbus在收藏列表更新数据

点击通知返回收藏列表

实现方式要求:启动页面的通知由静态广播产生,点击收藏图标的通知由动态广播产生。

2.1.3 验收内容

  • 静态广播:启动应用是否有随机推荐食品的通知产生。点击通知是否正确跳转到所推荐食品的详情界面

  • 动态广播:点击收藏后是否有提示食品已加入收藏列表的通知产生。同时注意设置launchMode。点击通知是否跳转到收藏列表

  • Eventbus:点击收藏列表图标是否正确添加食品到收藏列表。每点击一次,添加对应的一个食品到收藏列表并产生一条通知

三、实验结果

3.1 实验截图

下图为打开app后,产生一个推荐食品的通知

下图为点击该通知,会跳转至食物详情页面。点击收藏按钮时,产生收藏的通知

下图为点击收藏通知,跳转至收藏列表页面

3.2 实验步骤以及关键代码

3.2.1 利用静态广播实现今日推荐功能

在AndroidManifest.xml注册静态广播接受方

其中StaticReceiver为类名

  1. <receiver android:name=".StaticReceiver">
  2. <intent-filter>
  3. <action android:name="com.example.asus.health.MyStaticFilter" />
  4. </intent-filter>
  5. </receiver>

实现StaticReceiver类,重构onReceive函数

其中要根据intent的action来确定是否接受该广播的内容,来实现功能,而需要实现的包括一个notification的弹出以及点击它跳转到详情页面。

notification部分由builder的设置函数来设置名字,内容,等等,由NotificationManager来发出该notification。

点击后跳转的功能则需要给builder设置一个ContentIntent,这个intent为PeddingIntent,即不会马上跳转,而是需要等待用户的操作。它的构造函数传递了一个普通的intent,而这个intent是携带了所需的数据来生成详情页面。

  1. public void onReceive(Context context, Intent intent) {
  2. if (intent.getAction().equals(STATICACTION)){
  3. Bundle bundle = intent.getExtras();
  4. //TODO:添加Notification部分
  5. Notification.Builder builder = new Notification.Builder(context);
  6. //跳回主页面
  7. Intent intent2 = new Intent(context,Details.class);
  8. Bundle bundle2 = new Bundle();
  9. String s[] = new String [5];
  10. s[0] = ((MyCollection)bundle.getSerializable("collect")).getName();
  11. s[1] = ((MyCollection)bundle.getSerializable("collect")).getMaterial();
  12. s[2] = ((MyCollection)bundle.getSerializable("collect")).getType();
  13. s[3] = ((MyCollection)bundle.getSerializable("collect")).getContent();
  14. s[4] = ((MyCollection)bundle.getSerializable("collect")).getIs_star()?"yes":"no";
  15. bundle2.putStringArray("msg",s);
  16. intent2.putExtras(bundle2);
  17. PendingIntent contentIntent = PendingIntent.getActivity(
  18. context, 0, intent2, PendingIntent.FLAG_UPDATE_CURRENT);
  19. //对Builder进行配置
  20. builder.setContentTitle("今日推荐") //设置通知栏标题:发件人
  21. .setContentText(((MyCollection)bundle.getSerializable("collect")).getName()) //设置通知栏显示内容:短信内容
  22. .setTicker("您有一条新消息") //通知首次出现在通知栏,带上升动画效果的
  23. .setSmallIcon(R.mipmap.empty_star) //设置通知小ICON 空星
  24. .setContentIntent(contentIntent) //传递内容
  25. .setAutoCancel(true); //设置这个标志当用户单击面板就可以让通知将自动取消
  26. //获取状态通知栏管理
  27. NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
  28. //绑定Notification,发送通知请求
  29. Notification notify = builder.build();
  30. manager.notify(0,notify);
  31. }
  32. }

在FoodList主页面onCreat时生成广播

注意action的字符串要与上面的Reciver的相同,不然无法正确接受广播,随机数则是返回一个0到n-1的整数表示随机生成一个推荐食物,然后将所需数据放入intent,通过sendBroadcast函数发送该广播。

  1. //打开应用时,发送一个静态广播
  2. private void boardcastforOpen(int n){
  3. final String STATICACTION = "com.example.asus.health.MyStaticFilter";
  4. Random random = new Random();
  5. int num = random.nextInt(n); //返回一个0到n-1的整数
  6. Intent intentBroadcast = new Intent(STATICACTION); //定义Intent
  7. Log.i("se",getPackageName());
  8. Bundle bundles = new Bundle();
  9. bundles.putSerializable("collect", data2.get(num));
  10. intentBroadcast.putExtras(bundles);
  11. sendBroadcast(intentBroadcast);
  12. }

3.2.2 利用动态广播实现收藏信息提示

实现广播接受器DynamicReceiver类

与静态Receiver的实现过程差不多,一样是实现builder,然后放置peddingIntent,这里就不再重复放代码。唯一的不同点在于,它所要跳回的是收藏夹页面,即FoodList主页面,这里要对intent设置flag,否则无法在foodlist中get到新的intent。

  1. //跳回收藏夹
  2. Intent intent2 = new Intent(context,FoodList.class);
  3. Bundle bundle2 = new Bundle();
  4. bundle2.putString("tag","collect");
  5. intent2.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
  6. intent2.putExtras(bundle2);

对详情页面的收藏事件进行处理

在监听器中设置发送广播的intent,当按下收藏后会发出广播,并传递参数。其中还使用了eventbus来传递收藏的数据。

  1. //处理收藏按钮
  2. final ImageView collect_but = findViewById(R.id.collect);
  3. collect_but.setOnClickListener(new View.OnClickListener(){
  4. @Override
  5. public void onClick(View v){
  6. temp.setIs_collected(true);
  7. Toast.makeText(Details.this, "已收藏",Toast.LENGTH_SHORT).show();
  8. EventBus.getDefault().post(new MessageEvent(temp));
  9. //发送广播
  10. Intent intentBroadcast = new Intent();
  11. intentBroadcast.setAction(DYNAMICACTION);
  12. sendBroadcast(intentBroadcast);
  13. }
  14. });

在FoodList注册动态接收器以及注销动态接收器

注意分别要在onCreate函数以及onDestroy函数中实现注册与注销 。

3.2.3 使用EventBus来实现数据的传输

在这一点上,要改进上一周实验的代码,不再需要点击返回按钮利用setResult以及onActivityResult两个函数来返回信息。而是通过eventbus的订阅发布模式。

在FoodList来注册订阅者,订阅消息。而在Detail来发布信息。其中onMessageEvent函数用于收到发布消息后,来调用之前的接口函数刷新列表。

发布消息就是上面点击收藏按钮后 EventBus.getDefault().post(new MessageEvent(temp));

  1. //注册订阅者(注册收藏列表所在Activity为订阅者)
  2. EventBus.getDefault().register(this);
  3. @Subscribe(threadMode = ThreadMode.MAIN)
  4. public void onMessageEvent(MessageEvent event) {
  5. Log.i("hello","this is eventbus.");
  6. MyCollection mc = event.getCollection();
  7. refreshList(mc,simpleAdapter);
  8. }

3.2.4 从详情跳转回收藏夹

这里由于收藏夹FoodList为经常返回的页面,故这里使用了android:launchMode=”singleInstance”,即不让它重复创建新的活动。

所以再get我的返回intent时是拿不到新的intent的,这里需要重写onNewIntent函数,而且接收新的intent要在onResume中。

这里要求要显示收藏夹页面,所以要将食物列表隐藏起来。

  1. @Override
  2. protected void onNewIntent(Intent intent){
  3. super.onNewIntent(intent);
  4. setIntent(intent);
  5. }
  6. @Override
  7. protected void onResume(){
  8. super.onResume();
  9. //处理跳转
  10. Bundle bundle=this.getIntent().getExtras();
  11. if(bundle != null) {
  12. String str = bundle.getString("tag");
  13. Log.i("resume2",str);
  14. if (str.equals("collect")) {
  15. findViewById(R.id.recyclerView).setVisibility(View.GONE);
  16. findViewById(R.id.listView).setVisibility(View.VISIBLE);//设置Favourite可见
  17. tag_for_foodlist = false;
  18. f_but.setImageResource(R.mipmap.mainpage);
  19. }
  20. }
  21. }

3.3 实验遇到的困难以及解决思路

3.3.1 在安卓8.0版本中无法使用静态接收器,发送广播后,无法成功接收

方法一:解决这个问题,需要给receiver设置component,给予它的包名以及类名。

  1. intent.setComponent(new ComponentName(getPackageName(),getPackageName()+".xxxxReceiver"));

方法二:下载新的虚拟机,使用安卓7.0版本,则可以顺利接收静态广播。

3.3.2 使用EventBus时候,FoodList主页面无法得到post的信息

我按部就班地在Detail页面收藏按钮post,在FoodList订阅消息却毫无反应。首先,我认为是我的接收函数写错了,没有订阅到信息。通过Log.i发现确实没有进入到onMessageEvent函数中,于是对这个问题进行了查阅。网上有推荐使用stickyPost的,怀疑原因出在信息接收发生在创建接收者之前,但显然与函数执行顺序不符,它是先来到了主页面,所以必然创建了receiver。

经过大半个小时的查找发现是,post传的参数错误,并没有生成MessageEvent,而是错误地直接传递了数据包。

  1. //错误
  2. EventBus.getDefault().post(temp);
  3. //正确
  4. EventBus.getDefault().post(new MessageEvent(temp));

3.3.3 从收藏通知返回主页面时候,出现无法拿到intent的情况

由于我是在动态接收方的builder绑定了Peddingintent,当点击通知,应该要返回这个intent到主页面,然而主页面所获取的intent是空值。这一点让我怀疑了很久,问了同学才得知,这是声明了singleInstance的问题。

比如说在一个应用中A activity 跳转至 B activity 在跳转至 C activity 然后C做了一定的操作之后再返回A 界面。这样在A activity的启动模式设置为singleTask后。C界面跳转至A界面时,就会去判断栈内是否有改Activity实例,如果有就直接执行A界面的onNewIntent()方法,我们就可以把逻辑处理放在改生命周期方法中,如果没有就会走Activity的oncrate方法去创建实例。

所以这里需要重写onNewIntent来获取新的intent,而不是直接传递旧intent导致错误。

  1. @Override
  2. protected void onNewIntent(Intent intent){
  3. super.onNewIntent(intent);
  4. setIntent(intent);
  5. }

四、实验思考及感想

这次实验需要在安卓8.0与安卓7.0之间权衡,有些属性方法已经在8.0版本出现了变化,所以当使用错误,出现奇怪的现象时,第一步先检查自己的代码逻辑有否问题,第二步就是要查阅是否存在版本的兼容性问题产生了这些错误。这次作业就是如此,关于广播的实现,个人还是喜欢动态广播,不需要再静态注册在manifest中,代码也更加简便。

对于不同活动之间的传输,使用EventBus比之前的intent更加方便,减轻了耦合性,不用经常记住,哪个intent返回哪里,所以这次我也修改了不少前面实验使用intent的代码。除此之外,充分理解信息传输还需要理解一下活动的存活过程,什么时候调用onCreat,什么时候使用onResume。

上传的附件 cloud_download 实验二-中山大学智慧健康服务平台应用开发.7z ( 206.90kb, 1次下载 )

发送私信

如果这世界上真有奇迹,那只是努力的另一个名字

12
文章数
9
评论数
eject