(周期计划-5)从公司代码看Notification

2018年技术周期计划:周期计划-5(2018/1/29-2018/2/4)

写在前面

今天在做一个关于Notification业务的时候,突然想到了自己以前看公司代码时候遇到的一个问题:本来很简单的问题为什么要写的很复杂?
加之自己正要写Notification,所以又回过头来好好的看了一番公司的代码。才感觉前辈们的代码的确是有它们存在的价值和意义。

开始

在正式开始之前,我们先思考一下我们写Notification的套路:无论我们是自定义Notification还是用系统的布局。只要涉及到点击事件,我们就要包装一个PendingIntent。OK,那么问题来了。

如果我们业务简单,我们可能这么写:

Intent intent=new Intent(this,MainActivity.class);
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

在添加setContentIntent的时候把这个PendingIntent传进去。这样当然没有什么毛病。


不过,我们思考一个问题:

如果这个Intent,我们需要传递参数该怎么办?我们当然可能顺其自然的在intent对象中,开始putExtra,setAction之类的,这样也没有什么毛病。

此时,我们再思考一个问题:

如果这个MainActivity是别人(比如是我的Leader,W哥)维护的,W哥为了更方便的协同开发,他在他的MainActivity中暴露一个用于启动当前Activity的接口,比如是这样的:

    public static void start(@NonNull Context context,String action) {
        Intent intent = new Intent(context, HomeActivity.class);
        intent.putExtra(EXTRA_NAV_ACTION_KEY, action);
        if (!(context instanceof Activity)) {
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        context.startActivity(intent);
    }

按照W哥的想法,一切需要启动MainActivity的外部context只需要调用这个静态的start,传入对应的action即可,至于怎么启动外部不需要管。

OK,那么我们的问题来了:

回想一下我们刚才生成PendingIntent的过程....既然要生成PendingIntent,就需要我们自己实例化一个Intent,但是W哥的做法显然是封装了Intent,外部没办法获取。那么怎么办?难道让我的顶头上司去改代码?

公司的做法是这样的:自己获取一个用于Broadcast的Intent,然后对应写一个BroadcastReceiver,在这个接受者中,再去调用MainActivity中的start()。

让我们来看代码


public class NotificationReceiver extends BroadcastReceiver{
    // @NotificationClickAction / @NotificationFromType这个注解是自定义的,
    //非常简单,但又非常有效的一个自定义注解。一会儿会针对这个注解进行简单的展开
    publicstatic PendingIntent createClickIntent(@NonNull Context context, @NotificationClickAction String action, @NotificationFromType int fromType, int requestCode) {
        Intent contentIntent = null;
        switch (action) {
            //随意编写了一个ACTION
            case NOTIFICATION_ACTION_CLICK_1:
                contentIntent = new Intent(action);
                break;
        }
        if (contentIntent != null) {
            contentIntent.setComponent(new ComponentName(context, NotificationReceiver.class));
            contentIntent.setPackage(context.getPackageName());
            //传递的额外参数,这里是业务需要
            contentIntent.putExtra(NOTIFICATION_FROM_TYPE_EXTRA_KEY, fromType);
            return PendingIntent.getBroadcast(context, requestCode, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        }
        throw new IllegalArgumentException("createDeleteIntent UnSupport actionType");
    }
    //省略部分代码

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        //省略部分代码
        switch (action) {
            //在这里接受我们的Broadcast的ACTION,以此来调用MainActivity暴露的方法
            case NOTIFICATION_ACTION_CLICK_1: {
                MainActivituy.start(context, action);
                break;
            }
            default://no support action
                return;
        }
        //省略部分代码
    }
}

看完代码,我猜大概大家已经能清楚的看出思路,我们外部需要PendingIntent的时候,调用NotificationReceiver中的createClickIntent()方法传入对应一个ACTION,然后在onRecive()中接收这个ACTION,做自己的逻辑即可。


自定义的小注解

上述的代码中,出现了@NotificationClickAction这个注解。其实它的声明很简单,就是这样的:

    //我们可以看到这个注解类型是String,有俩个默认变量(它的作用请继续往下看)
    @StringDef(value = {NOTIFICATION_ACTION_CLICK_1, NOTIFICATION_ACTION_2})
    @Retention(RetentionPolicy.SOURCE)
    public @interface NotificationClickAction {
    }

    public static final String NOTIFICATION_ACTION_CLICK_1 =  "我就是一个常量1";
    public static final String NOTIFICATION_ACTION_CLICK_2 = "我就是一个常量2";

通过上边的代码,我们可以看出一个问题,那就是我们声明了俩个常量NOTIFICATION_ACTION_CLICK_1 以及NOTIFICATION_ACTION_CLICK_2,并且它俩是注解NotificationClickAction 的初始值。

这样有什么用呢?

还记得我们在createClickIntent()方法里出入的参数么?

@NotificationClickAction String action

用此注解标注的参数,有一个作用就是:如果我们传递了一个这个注解没有包含的变量,比如NOTIFICATION_ACTION_CLICK_3,那么编辑器便会提示你这是错误的。这样的好处便是告诉我们此处需要传什么值。

那么我们再回归到W哥的那个关于MainActivity的start封装,他的start中也包含了对应注解参数,那么我完全可以只需要按照注解的标注传参,即可。极大的提高了协同开发的效率。


尾声

个人认为这是一篇注重代码质量和团队合作规范的一篇博客,重点不是为了去记录知识点,而是为了让后来的伙伴们看到我写的代码,由衷的说一句:这代码看起来真舒服。

本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅…
https://github.com/zhiaixinyang/PersonalCollect

2018年7月2号,我正式开始了自己的Android工作,为了能够让自己能够好好完成工作,并且能够快速得到技术提升。所以打算以公众号的方式去敦促自己学习,我会把自己日常的学习笔记发布到公众号上,如果可以,共同进步!~


(周期计划-5)从公司代码看Notification
个人公众号
上一篇:网上转载的针对国内安全公司的评价


下一篇:2009年六大网络安全威胁:SQL注入攻击位列榜首