多页面分享成功回调重复的坑

晚上就要发布新版本了,测试跑来向我反应线上社区存在某个页面分享后,打开该页面之前的几个页面都会收到分享成功回调的问题。看了下项目代码,是个历史遗留问题。告诉他为什么N个版本了都没发现这个问题,偏偏要快上线了要我改???来人,取俺的五十米长刀来!

问题的原因

查阅代码后,得知项目中的分享成功通知是由广播来实现的。在分享成功后,App会发送一个全局广播。而所有的页面都是在初始化时注册广播,在销毁时注销广播。所以,当A页面注册了分享广播,B页面也注册了,此时从A页面跳到B页面,而A页面并没有关闭,那么在B页面分享成功后,自然两个页面都会收到通知。

问题的解决

知道了问题的原因后,解决起来应该就比较容易了。

我第一个想法是,既然是因为广播是在初始化时注册的,导致页面没有关闭时会收到通知,那如果将广播在页面处于前台时在注册,在处于后台时就注销掉,这样问题不就轻松解决了么?

理想很丰满,现实永远是辣么果敢。运行项目后,会发现所有的页面都收不到分享了。调试了一番,原来是分享成功返回App会立即发送广播,而此时页面还没有执行onStart()或者onResume()方法。那自然是收不到通知了。所以,该方案扑街。

转念我再一想,是不是可以在发送成功广播的时候,增加一个区分分享页面的分享源参数。将该类持有的Context的类名赋值给该变量。而该Context必然是某个页面,这样某个注册了广播的页面在接收到广播时,取出该参数和广播中的Context的类名做比较,不就可以区分了么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private String shareSource;

public ShareManager(Activity activity) {
this.mActivity = activity;
shareSource = mActivity.getClass().getName();
}

...

public void sendQuestionBroadCast(String target, int status, String shareSource) {
Intent intent = new Intent(SHARE_QUESTION_RECEIVER);
intent.putExtra(KEY_SHARE_TARGET, target);
intent.putExtra(KEY_SHARE_STATUS, status);
intent.putExtra(KEY_SHARE_SOURCE, shareSource);
context.sendBroadcast(intent);
}

运行项目后,果然还是有问题。A页面和B页面各自持有各自的发送广播类实例,而这样其实比的就是自身,相当于没做。

于是,我立刻想到该变量应该是个静态的,同事在每个页面位于前台时,重新赋值。这样在A页面发送广播时,该值是A,在B页面时该值就成了B,那么在收到广播时,只要比较一下广播中Context的类名和该静态变量值,不就可以区分了么?

再次运行后,竟然还是扑街!!!存在以下两个问题

  1. 只是用页面的名字来区分分享源,确实可以区分不同的页面。但无法区分两个相同的页面。比如A页面跳A页面
  2. A页面和B页面有可能不是同一个进程,这样静态变量就失效了

那么如何解决呢?

第一个问题。既然还要区分同页面,那么只要再名字后再增加一个唯一的ID,这样每个页面的实例都有自己的名字加ID,不就可以区分了。

第二个问题。其实就是个多进程通讯问题,一般而言,有以下几个方法

  1. 使用Bundle
  2. AIDL
  3. Messenger
  4. 文件共享
  5. socket

很显然,这里要找最轻量的一种通信方式。那就是Budle和文件共享。这里Budle不可能,只能是文件共享了。Sp不支持多进程,所以这里,我使用Properties文件。每次分享的时候,只要将分享源存入本地,同时每个页面也保留一份,在收到广播后读取本地文件,再与当前页面保留的数据比对就可以了。

总结

没想到原以为是一个小小的问题,在解决的时候才发现竟然有这么多坑。另外,感觉我这里的处理方式并不是那么优雅,看看日后是否能够优化。