天天看點

(周期計劃-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寫在前面開始自定義的小注解尾聲
個人公衆号

繼續閱讀