Android消息紅點計數(shù)模型庫

最近在寫一個社交APP的時候静暂,在控制消息計數(shù),及界面紅點顯示時總會或多或少有延遲或計數(shù)偏差棚唆,網(wǎng)上大多是對界面繪制的探討,而在處理數(shù)據(jù)處理上相對較少心例,因此宵凌,我琢磨著能寫一個快捷方便,且只需要配置一次止后,之后均自動更新數(shù)字瞎惫,顯示、隱藏的庫译株。于是有了它 —— SuperBadge (全局角標數(shù)據(jù)模型管理庫)

demo

模型思路

通過樹形結(jié)構(gòu)將數(shù)字和紅點進行分層管理瓜喇,只關(guān)聯(lián)父級和子級數(shù)據(jù), 原則上不越級干擾其他控件歉糜,如圖例1所示


圖例1
  • 根節(jié)點 也可理解為頂級節(jié)點乘寒,是所有子級節(jié)點最終的交匯點,其特點為:沒有關(guān)聯(lián)的上級節(jié)點(父節(jié)點)匪补,有關(guān)聯(lián)的下級節(jié)點(節(jié)點A伞辛、節(jié)點B、節(jié)點C)夯缺,不能進行增加數(shù)字和減少數(shù)字操作蚤氏,能進行已讀操作【調(diào)用read()方法】;
  • 節(jié)點A踊兜、節(jié)點B竿滨、節(jié)點C 為普通節(jié)點,其特點為:有關(guān)聯(lián)的上級節(jié)點(根節(jié)點),有關(guān)聯(lián)的下級節(jié)點(節(jié)點1.2.3.4.5.6)姐呐,不能進行增加數(shù)字和減少數(shù)字操作,能進行已讀操作
  • 節(jié)點1.2.3.4.5.6 最下級節(jié)點典蝌,紅點數(shù)字的直接數(shù)據(jù)源曙砂。其特點為:有關(guān)聯(lián)的上級節(jié)點(節(jié)點A、節(jié)點B骏掀、節(jié)點C)鸠澈,沒有關(guān)聯(lián)的下級節(jié)點,能進行增加數(shù)字和減少數(shù)字操作截驮,能進行已讀操作

舉個栗子
主界面有【消息】【好友】【我的】三個模塊笑陈,那么這三個模塊均為獨立的[根節(jié)點],以消息為例】【消息】節(jié)點下面綁定了好友會話A[節(jié)點A]涵妥、好友會話B[節(jié)點B]、好友會話C[節(jié)點C]坡锡,每個好友會話下面分別綁定 語音消息[節(jié)點1.3.5] 蓬网、文本消息[節(jié)點2.4.6],如圖例2所示


圖例2.png

這樣的設(shè)計方式我們能實現(xiàn)那些功能鹉勒?
如果我們要在主界面標記為讀取所有帆锋,那么調(diào)用 【消息】的 read()方法即可,其下所有節(jié)點數(shù)字均會設(shè)置為0(不顯示)禽额;同理锯厢,如果我們要讀取好友會話A,那么調(diào)用好友會話A的 read()脯倒;語音消息和 文本消息數(shù)字均會被設(shè)置為0实辑,而【消息】節(jié)點會減去好友會話A的數(shù)字,通過這種方式藻丢,我們在對任意一個層級做出數(shù)據(jù)更新的時候徙菠,其上下級都會聯(lián)動。

為什么不允許非最下級節(jié)點之外的節(jié)點進行增減操作郁岩?
也可以理解為為什么我只允許在直接關(guān)聯(lián)數(shù)據(jù)的節(jié)點上進行增減操作婿奔,其原因很容易理解,假設(shè)好友會話A發(fā)來一條好友文本消息问慎,如果我們直接對好友會話A節(jié)點進行+1的操作萍摊,因為SuperBadge不干涉業(yè)務(wù)邏輯, 所以我們的下級節(jié)點將無法判斷新+1的消息是語音消息+1還是文本消息+1如叼,從而導(dǎo)致對整個數(shù)據(jù)模型的破壞冰木。同理,我們也不能對【消息】節(jié)點采取添加方法,SuperBadge將無法知道新的會話是來自好友會話A踊沸、B歇终、C其中的哪一個。

同時逼龟,為了保證在配置后能全局自動化评凝,我們希望開發(fā)者在初始化和綁定好控件之后,可以完全忘記數(shù)字的概念腺律,也無需關(guān)心增減的狀態(tài)奕短,而只有讀和未讀的兩種狀態(tài) (但即使如此,為了滿足一些特定需求匀钧,我們依舊提供了增減方法翎碑,但只適用于最下級節(jié)點調(diào)用)

功能分析:自動管理更新全局角標

  1. 首先我們需要【BadgeManger】 角標繪制管理者在相應(yīng)控件上繪制角標,比如右上角畫一個圓之斯,圓里面有相應(yīng)的數(shù)字日杈;
  2. 然后需要一個【SuperBadgeHelper】 角標助手記錄這個控件信息的對象,并加入全局數(shù)據(jù)模型隊列佑刷,在每次刷新界面的時候獲取控件角標信息(如有)并顯示达椰。
  3. 與之相關(guān)聯(lián)的的控件相互綁定,創(chuàng)建樹形數(shù)據(jù)模型项乒。通過【SuperBadgeDater】 角標數(shù)據(jù)管理 - 儲存和獲取數(shù)據(jù)啰劲,在某個控件發(fā)生數(shù)據(jù)變化的時候?qū)εc之相關(guān)聯(lián)的控件做出聯(lián)動。

通過上面的分析檀何,代碼一共由三部分組成

  • BadgeManger 角標繪制管理者 - 用于在View上繪制角標

因為本文重點是討論數(shù)據(jù)模型蝇裤,所以角標繪制代碼借鑒于他人,在此先不多作分析,有興趣可跳轉(zhuǎn)BadgeView查看频鉴。

  • SuperBadgeHelper 角標助手 - 核心類栓辜,處理全局消息計數(shù)模型

  • 私有構(gòu)造方法
    /** 
      * @param context 當前Avtivity 
      * @param view    綁定角標view
      * @param tag     全局的唯一標記 
      * @param num     角標數(shù)字
      * @param show    是否顯示數(shù)字
      * @return SuperBadgeHelper */
    private SuperBadgeHelper(Activity context, View view, String tag, int num, boolean show) {
      if (SuperBadgeDater.getInstance().getBadge(context,tag) != null) {
          throw new IllegalArgumentException(tag + "標記已經(jīng)被其他控件注冊");
      }
      if (context == null) {
          throw new NullPointerException("context not is null ");
      }
      if (num < 0) {
          throw new IllegalArgumentException("初始化角標數(shù)字不能小于0");
      }
      if (tag == null) {
          throw new IllegalArgumentException("tag 不能為空");
      }
      
      this.tag = tag;
      this.view = view;  
      this.num = num;
      this.context = context;
      this.show = show;
      //創(chuàng)建BadgeManger 為控件繪制角標
      badge = new BadgeManger(context);
      badge.setTargetView(view);
      paterAddNum(num);// 添加數(shù)字
    

    }

  • 初始化SuperBadgeHelper
    public static SuperBadgeHelper init(Activity context, View view, String tag) {
      return init(context, view, tag, 0, true);
    }
    
    public static SuperBadgeHelper init(Activity context, View view, String tag, int num) {
      return init(context, view, tag, num, true);
    }
    
    public static SuperBadgeHelper init(Activity context, View view, String tag, boolean show) {
      return init(context, view, tag, 0, show);
    }
    
    /**
     * @param context 當前Avtivity
     * @param view    綁定角標view
     * @param tag     用于綁定的唯一標記
     * @param num     角標數(shù)字
     * @param show    是否顯示數(shù)字
     * @return SuperBadgeHelper
     */
    public static SuperBadgeHelper init(Activity context, View view, String tag, int num, boolean show) {
        //從數(shù)據(jù)模型里查找是否已有標記為 [tag] 的控件
        SuperBadgeHelper superBadge = SuperBadgeDater.getInstance().getBadge(context,tag);
        if (superBadge != null) { //如有,替換view
            superBadge.setView(view);
            superBadge.setContext(context);
            superBadge.setShowBadge(show);
            superBadge.getBadge().setTargetView(view);
            if (superBadge.isShow()) {  
                superBadge.getBadge().setBadgeCount(superBadge.getNum());
            }
            return superBadge;
        } else {//如沒有垛孔,新建SuperBadgeHelper 
            return new SuperBadgeHelper(context, view, tag, num, show);
        }
    }
    
  • 綁定關(guān)聯(lián)控件

綁定關(guān)聯(lián)控件是整個數(shù)據(jù)模型里面最關(guān)鍵的一步藕甩,通過下級控件A調(diào)用 bindView()方法來與其他控件B保持關(guān)系,如果A發(fā)生了變化周荐,那么B也會發(fā)生相應(yīng)的變化狭莱。

1.提供了兩種綁定方法

/**
 * 根據(jù)父級控件根據(jù)全局唯一標簽將他綁定到本級控件
 *
 * @param tag 父級控件的Tag
 */
public void bindView(String tag) {

    for (SuperBadgeHelper pater : paterBadge) {
        if (pater.getTag().equals(tag)) {
            //  throw new IllegalArgumentException("不能重復(fù)添加相同控件");
            return;
        }
    }
    SuperBadgeHelper paterBadgeHelper = SuperBadgeDater.getInstance().getBadge(context,tag);
    if (paterBadgeHelper != null) {
        paterBadge.add(paterBadgeHelper); //添加本級父控件
        paterBadgeHelper.addChild(this);//添加到父級子控件
    } else {
        throw new NullPointerException("沒有找到標記為[" + tag + "]的控件");
    }
}

 //第二種是根據(jù)SuperBadgeHelper(實質(zhì)上還是根據(jù)標簽綁定)

public void bindView(SuperBadgeHelper pater) {   
        bindView(pater.getTag());
}
  • 設(shè)置為已讀
    /**
    * 讀取所有消息,清空數(shù)字為0(隱藏角標)
    */
    SuperBadgeHelper.read()
    
  • 增減數(shù)字方法

我們希望開發(fā)者在初始化和綁定好控件之后概作,可以完全忘記數(shù)字的概念腋妙,也無需關(guān)心增減的狀態(tài),而只有讀和未讀的兩種狀態(tài)讯榕。
骤素!只有最下級節(jié)點可以調(diào)用

  //減少數(shù)字
   SuperBadgeHelper.lessNum(int i)
  //增加數(shù)字
   SuperBadgeHelper.addNum(int i)
  • 其他方法請閱讀源碼

SuperBadgeDater 角標數(shù)據(jù)管理 - 儲存和獲取數(shù)據(jù)

代碼很簡單匙睹,就全部貼上來了,暫時只用Map進行儲存济竹,其他儲存方式正在設(shè)計中

public class SuperBadgeDater implements Serializable {

    private static final SuperBadgeDater Instance = new SuperBadgeDater();

    Map<String, SuperBadgeHelper> map = new HashMap<>();

    private SuperBadgeDater() {

    }
    public static SuperBadgeDater getInstance() {
        return Instance;
    }

    public void addBadge(SuperBadgeHelper superBadge) {
        map.put(superBadge.getTag(), superBadge);
    }
    public SuperBadgeHelper getBadge(String tag) {
        return map.get(tag);
    }
}

使用 SuperBadge


添加依賴

添加在到APP的gradle里

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

添加到項目 gradle的dependency里

dependencies {
    compile 'com.github.chendongde310:SuperBadge:latest.release'
}

最新版本請?zhí)D(zhuǎn)至我的Github 查看

如何使用


  • step1 初始化控件

         /**
           * 
           * @param context Activity
           * @param view 綁定角標view
           * @param tag 用于綁定的唯一標記
           * @param num 角標數(shù)字
           * @param show 是否顯示數(shù)字
           * @return SuperBadgeHelper
           */
      SuperBadgeHelper.init(Activity context, View view, String tag, int num,boolean show)
    
  • step2 綁定上級控件

      /**
        * 根據(jù)父級控件tag綁定父級控件
        * @param tag  父級控件的Tag
        */
        SuperBadgeHelper.bindView(String tag)
        //or
        SuperBadgeHelper.bindView(mSuperBadgeHelper)
    
  • step3 設(shè)置已讀

      /**
      * 讀取所有消息痕檬,清空數(shù)字為0(不顯示)
      */
      SuperBadgeHelper.read()
    
  • other method

       //增加數(shù)字 - 必須為根節(jié)點控件 
       addNum(int i)
       //減少數(shù)字 - 必須為根節(jié)點控件 
       lessNum(int i)
       //是否顯示角標
       setShowBadge(boolean b)
       //設(shè)置角標半徑
       setDipRadius(int dipRadius)
       //設(shè)置角標顏色
       setBadgeColor(int badgeColor)
    

TODO 即將完成
  • 提供自定義繪制方法
  • (已完成)小紅點(不顯示具體數(shù)字,半徑小的紅點提示)
  • read()方法 異步(網(wǎng)絡(luò) 送浊、數(shù)據(jù)庫讀寫)請求失敗后的處理
  • 增加將節(jié)點標記為未讀狀態(tài)功能(+1s)
  • 桌面(APP圖標)角標顯示

采用此消息計數(shù)模型梦谜,配置好后能讓開發(fā)者最大化的不去關(guān)注數(shù)字的更新和界面刷新操作,專注于業(yè)務(wù)邏輯開發(fā)罕袋。此庫可以不必擔心界面和控件創(chuàng)建銷毀所造成的內(nèi)存泄漏等問題改淑,如果此庫對你有幫助碍岔,請花幾秒的時間給我一個star浴讯,您的支持是對我最大鼓勵!

文末提供Demo下載.

我的Githu地址 - http://github.com/chendongde310

如果此庫對你有幫助蔼啦,請花幾秒的時間給我一個star榆纽,您的支持是對我最大鼓勵!如有任何關(guān)于此庫的問題和疑問捏肢,請在下方留言評論或提交issues,感謝閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奈籽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鸵赫,更是在濱河造成了極大的恐慌衣屏,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辩棒,死亡現(xiàn)場離奇詭異狼忱,居然都是意外死亡,警方通過查閱死者的電腦和手機一睁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門钻弄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人者吁,你說我怎么就攤上這事窘俺。” “怎么了复凳?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵瘤泪,是天一觀的道長。 經(jīng)常有香客問我育八,道長均芽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任单鹿,我火速辦了婚禮掀宋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己劲妙,他們只是感情好湃鹊,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著镣奋,像睡著了一般币呵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上侨颈,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天余赢,我揣著相機與錄音,去河邊找鬼哈垢。 笑死妻柒,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的耘分。 我是一名探鬼主播举塔,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼求泰!你這毒婦竟也來了央渣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤渴频,失蹤者是張志新(化名)和其女友劉穎芽丹,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卜朗,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡拔第,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了聊替。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楼肪。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖惹悄,靈堂內(nèi)的尸體忽然破棺而出春叫,到底是詐尸還是另有隱情,我是刑警寧澤泣港,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布暂殖,位于F島的核電站,受9級特大地震影響当纱,放射性物質(zhì)發(fā)生泄漏呛每。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一坡氯、第九天 我趴在偏房一處隱蔽的房頂上張望晨横。 院中可真熱鬧洋腮,春花似錦、人聲如沸手形。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽库糠。三九已至伙狐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瞬欧,已是汗流浹背贷屎。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留艘虎,地道東北人唉侄。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓籍滴,卻偏偏與公主長得像卢鹦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,283評論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理贬墩,服務(wù)發(fā)現(xiàn),斷路器妄呕,智...
    卡卡羅2017閱讀 134,699評論 18 139
  • Day1: 在代碼中通過R.string.hello_world可以獲得該字符串的引用陶舞; 在XML中通過@stri...
    冰凝雪國閱讀 1,410評論 0 5
  • 讓TableView 流暢起來,拒絕卡頓 TableView優(yōu)化10條 避免 cellForRowAtIndexP...
    吳霸格07閱讀 211評論 0 0
  • 生活中很多人去爭取不屬于自己的绪励,總弄得狼狽不堪 忠于初心是好肿孵,可是終不能始終 給自己爭一口氣 不要去輕賤自己!
    你真逗i閱讀 343評論 0 0