利用 Firebase Remote Config 完成App Tab图标动态替换

这个是我在发版前几天才知道的一个需求。
其实不用 Firebase 也是可以完成的,但肯定要增加我们服务器的工作量的。

毕竟一个创业公司,还是需要注意资源合理利用,于是我还是找到了可靠的 Firebase.

需求

在65eday 的时候,需要把我们 主页 tab 的图标给替换了,包括文字。

脑补京东淘宝等。

接口设计

如果是这样的话,那我为了满足后期的类似需求,肯定是需要下发图片 url 下去,一劳永逸。

于是我让 Firebase配置了一个 json字符串,Android 拿到字符串去解析,然后再去做替换。

{
    "isDefault": false,//是否显示默认的 true显示默认
    "shop": {
        "iconCheckedUrl": "",//选中的图片
        "iconUrl": "",//默认图片
        "name": "ezbuy"//tab 名称
    },
    "surf": {
         "iconCheckedUrl": "http://upload-images.jianshu.io/upload_images/1432234-969054a168834d9d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240",
        "iconUrl": "http://upload-images.jianshu.io/upload_images/1432234-4ffd3e7a31471427.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240",
        "name": "is"
    },
    "prime": {
         "iconCheckedUrl": "http://upload-images.jianshu.io/upload_images/1432234-969054a168834d9d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240",
        "iconUrl": "http://upload-images.jianshu.io/upload_images/1432234-4ffd3e7a31471427.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240",
        "name": ""
    },
    "cart": {
         "iconCheckedUrl": "http://upload-images.jianshu.io/upload_images/1432234-969054a168834d9d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240",
        "iconUrl": "http://upload-images.jianshu.io/upload_images/1432234-4ffd3e7a31471427.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240",
        "name": "the"
    },
    "mine": {
          "iconCheckedUrl": "http://upload-images.jianshu.io/upload_images/1432234-969054a168834d9d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240",
        "iconUrl": "http://upload-images.jianshu.io/upload_images/1432234-4ffd3e7a31471427.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240",
        "name": "best"
    }
}

实现

Firebase 远程配置


配置的 JSON

java bean

Android Studio 可以根据json一键生成。

public class TabIconEntity {
    /**
     * shop : {"iconUrl":"","iconCheckedUrl":"","name":""}
     * surf : {"iconUrl":"","iconCheckedUrl":"","name":""}
     * prime : {"iconUrl":"","iconCheckedUrl":"","name":""}
     * cart : {"iconUrl":"","iconCheckedUrl":"","name":""}
     * mine : {"iconUrl":"","iconCheckedUrl":"","name":""}
     */

    private TabBean shop;
    private TabBean surf;
    private TabBean prime;
    private TabBean cart;
    private TabBean mine;
    private boolean isDefault;

    public static class TabBean {
        /**
         * iconUrl :
         * iconCheckedUrl :
         * name :
         */

        private String iconUrl;
        private String iconCheckedUrl;
        private String name;

        public String getIconUrl() {
            return iconUrl;
        }

        public void setIconUrl(String iconUrl) {
            this.iconUrl = iconUrl;
        }

        public String getIconCheckedUrl() {
            return iconCheckedUrl;
        }

        public void setIconCheckedUrl(String iconCheckedUrl) {
            this.iconCheckedUrl = iconCheckedUrl;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

获取图片替换

首先会在闪屏页获取 Firebase Remote Config 配置(配置的不仅仅是只有这个,还有很多,统一获取回缓存)

  /**
     * 使用到远程配置的参数 在这里更新。
     */
    public void getFirebaseRemoteConfig() {
        final FirebaseRemoteConfig mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
        FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
                .setDeveloperModeEnabled(BuildConfig.DEBUG)
                .build();
        mFirebaseRemoteConfig.setConfigSettings(configSettings);
        mFirebaseRemoteConfig.setDefaults(R.xml.remote_config_defaults);
        long cacheExpiration = 3600; // 1 hour in seconds.
        // If in developer mode cacheExpiration is set to 0 so each fetch will retrieve values from
        // the server.
        if (mFirebaseRemoteConfig.getInfo().getConfigSettings().isDeveloperModeEnabled()) {
            cacheExpiration = 0;
        }
        mFirebaseRemoteConfig.fetch(cacheExpiration)
                .addOnCompleteListener(new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {
                        if (task.isSuccessful()) {
                            mFirebaseRemoteConfig.activateFetched();
                        }
                    }
                });
    }

然后再需要替换 icon 的页面加入以下代码就可以了

    private void checkFirebaseTabIcon() {
        drawables = new Drawable[5][];
        String json = FirebaseRemoteConfig.getInstance().getString("tab_icon_json");
        Gson gson = new Gson();
        TabIconEntity entity = gson.fromJson(json, TabIconEntity.class);
        if (entity != null && !entity.isDefault()) {//
            addFirebaseIcon(entity.getShop(), shopButton, 0);
            addFirebaseIcon(entity.getSurf(), surfButton, 1);
            addFirebaseIcon(entity.getPrime(), primeButton, 2);
            addFirebaseIcon(entity.getCart(), cartButton, 3);
            addFirebaseIcon(entity.getMine(), mineButton, 4);
        }
    }


    private void addFirebaseIcon(final TabIconEntity.TabBean bean, final RadioButton button, final int i) {
        drawables[i] = new Drawable[2];
        RequestQueue mQueue = Volley.newRequestQueue(getActivity());
        ImageRequest request = new ImageRequest(bean.getIconUrl(), new Response.Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap response) {
                drawables[i][0] = new BitmapDrawable((response));
                if (drawables[i][1] != null) {
                    addState(button, bean.getName(), i);
                }
            }
        }, 0, 0, Bitmap.Config.ARGB_8888, null);
        ImageRequest request1 = new ImageRequest(bean.getIconCheckedUrl(), new Response.Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap response) {
                drawables[i][1] = new BitmapDrawable((response));
                if (drawables[i][0] != null) {
                    addState(button, bean.getName(), i);
                }
            }
        }, 0, 0, Bitmap.Config.ARGB_8888, null);
        mQueue.add(request);
        mQueue.add(request1);

    }

    private void addState(RadioButton button, String name, int i) {
        StateListDrawable sd = new StateListDrawable();
        int px = DensityUtils.dp2px(getActivity(), 20);
        if (i == 2) {//Prime 大一倍
            px = px * 2;
        }
        sd.setBounds(0, 0, px, px);
        int checked = android.R.attr.state_checked;
        sd.addState(new int[]{-checked}, drawables[i][0]);
        sd.addState(new int[]{checked}, drawables[i][1]);
        button.setCompoundDrawables(null, sd, null, null);
        if (!TextUtils.isEmpty(name)) {
            button.setText(name);
        }
    }

启动 app 之后检测需要替换

替换后的图片

注意

-图片20dp大小
-宽高 1:1
-prime 是 40dp*40dp
-prime 不要 name

样本图

选中
默认
配置好发布就行
有点丑,不愿意找样本图了
默认显示
测试配置的要比我的好看

注意点

1.拿到 url 然后先去下载图片,转成Drawable
2.利用StateListDrawable 设置selector
3.button.setCompoundDrawables(null, sd, null, null);利用这个 api 设置在RadioButton上面。

然后顺利完成了需求,并且不增加服务器的压力。产品可以随意配置了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,566评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,274评论 25 707
  • 备注: 本教程已由 Attila Hegedüs 更新适配 iOS 10 和 Swift 3,原教程由David...
    _浅墨_阅读 2,790评论 3 9
  • 空出一片寂寞荒芜的心 让我在上面快乐耕耘 用深情浇灌 蔬菜,庄稼,与花 汇作成熟的芳香 风吹不散 累月经年 你没发...
    很宇宙阅读 184评论 2 3
  • JavaScirpt变量提升 两个例子: 控制台显示:undefined 控制台显示:ReferenceError...
    勃王阅读 389评论 0 0