重拾Android之路之启动页Splash、广告页

引言

公司业务需求涉及到广告页,趁此机会来学习总结一下。

第一次安装启动的时候,是会出现任何版本都会有的页面,包含有App logoslogan的标准静态页面,然后是介绍新版本特性基本使用方法或者广告软文引导页

在APP的开发过程中,启动页面是绕不开的,广告页面说不定,但是不得不说,这两个界面都是经常要用到的。

那么先看看我们的需求和流程:(当然这也是可以根据实际需求改动的)

  • 展示 logo 页面3秒
  • 服务端可以控制是否播放广告
  • 服务端可以控制播放广告的秒数
  • 服务端可以控制广告的内容(图片)和广告详情页面的链接

这里需要注意的一点是,从服务端请求数据是在展示 3 秒启动页的时候获取的。

启动页

如果我们稍微有留意的话,都会发现,我们自己的应用启动的时候都有一段白屏的状态。但是微信却没有,我们现在要做的是解决这个问题。

首先我们来了解一下,冷启动,热启动。

  • 冷启动:是指进程从无到有的过程。因为要进行页面初始化,所以相对热启动方式,消耗的时间是相对比较多的。

  • 热启动:是指之前的进程还在,在之前进程的基础上创建 Activity 的过程。这里耗时相对少一点。

我们可以通过 Activity 的 theme 来修改这个白屏所显示的界面。根据上面的需求,我们需要显示3秒 logo 的页面。那么,我们干脆将我们的logo设置为背景图就行。

<style name="AppTheme.NoActionBarWithBackGround">
    <item name="windowActionBar">false</item>//取消Actionbar
    <item name="windowNoTitle">true</item>
    <item name="android:windowFullscreen">true</item>//设置全屏
    <item name="android:windowBackground">@drawable/splash</item>//设置背景
</style>

然后让我们的 Activity 使用这个 theme 即可。

<activity
    android:name=".View.iml.AdActivity"
    android:theme="@style/AppTheme.NoActionBarWithBackGround">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

广告页

广告页我尝试过两种方式:

  1. glide 加载
  2. 通过下载文件,然后再加载

如果使用glide加载广告图片,如果网络比较差,会存在广告页面空白的情况,因为使用 glide 无法判断在展示 logo页面的3 秒内是否加载好了广告图片。这给用户的体验是比较差的,也是不太友好的,因为用户在空白界面白白等待了 3 秒。所以后面使用了将广告图片下载到本地的方法。

这里进行数秒,这里是通过增加数字值来控制的,解决了服务端要控制广告时间的问题。之前使用过减少数字值来实现,但是要解决服务端控制广告时间,就没那么容易了。

View

    private int countNum() {//数秒
        timeCount++;
        if (timeCount == 3) {//数秒,超过3秒后如果没有网络,则进入下一个页面
            if (!NetUtils.isConnected(AdActivity.this)) {
                continueCount = false;
                toNextActivity();
            }
            if (!loginCheckBean.isPlayAd()) {//如果服务端不允许播放广告,则直接进入下一个页面
                continueCount = false;
                toNextActivity();
            } else {//如果播放,则进行显示
                ivAdvertising.setVisibility(View.VISIBLE);
                layoutSkip.setVisibility(View.VISIBLE);
            }
        }
        if (timeCount == initTimeCount) {//超过广告显示的最长时间,进入下一个界面
            continueCount = false;
            toNextActivity();
        }
        return timeCount;
    }
    public void toNextActivity() {//根据是否保存有 token 判断去登录界面还是主界面
        L.d("到下一个界面");
        Intent intent = null;
        String token = (String) SPUtils.get(AdActivity.this, "token", "");
        if (TextUtils.isEmpty(token)) {
            intent = new Intent(AdActivity.this, LoginActivity.class);
        } else {
            intent = new Intent(AdActivity.this, MainActivity.class);
            MyApplication.setToken(token);
        }
        startActivity(intent);
        finish();
    }

Presenter

向服务端请求是否要播放广告

    public void getLoginCheck() {//向服务器请求是否要播放广告
        mAdModel.getLoginCheck()
                .subscribeOn(Schedulers.io())                            //发布者在后台线程中运行
                .observeOn(AndroidSchedulers.mainThread())               //订阅者在Android主线程中运行
                .subscribe(new RxSubscribe<LoginCheckBean>() {
                    @Override
                    protected void _onNext(LoginCheckBean loginCheckBean) {
                        getMyView().setLoginCheckBean(loginCheckBean);
                        if (loginCheckBean.isPlayAd()) {//这里需要添加一个是否已经下载的判断,如果已经下载,则不再进行下载
                            getAdMessage();
                        }
                    }

                    @Override
                    protected void _onError(String message) {

                    }

                    @Override
                    public void onCompleted() {

                    }
                });
    }

获取图片地址,详情页面链接,广告的播放时间

    public void getAdMessage() {
        mAdModel.getAdMessage()
                .subscribeOn(Schedulers.io())                            
                .observeOn(AndroidSchedulers.mainThread())               
                .subscribe(new RxSubscribe<AdMessageBean>() {
                    @Override
                    protected void _onNext(AdMessageBean adMessageBean) {
                        getMyView().setAdTime(adMessageBean.getAdTime());
                        getAdPicture(adMessageBean.getAdPictureUrl(), "123.jpg");
                    }

                    @Override
                    protected void _onError(String message) {

                    }

                    @Override
                    public void onCompleted() {

                    }
                });
    }

获取广告图片

   private void getLocalPicture(String localUrl) {
        Bitmap bitmap = BitmapFactory.decodeFile(localUrl);
        getMyView().setAdImg(bitmap);
    }

    public void getAdPicture(final String fileUrl, final String fileName) {//获取要展示的广告图片
        if (SPUtils.get((Context) getMyView(), "adPictureUrl", "").equals(fileUrl)) {//判断是否存在缓存
            L.d("从本地获取图片");
            getLocalPicture((String) SPUtils.get((Context) getMyView(),"adPictureAddress",""));
        } else {
            L.d("从网络中获取图片");
            mAdModel.downLoadFile(fileUrl)
                    .subscribeOn(Schedulers.newThread())                            
                    .observeOn(AndroidSchedulers.mainThread())               
                    .map(new Func1<ResponseBody, Bitmap>() {
                        @Override
                        public Bitmap call(ResponseBody responseBody) {
                            if (responseBody != null) {
                                L.d("收到的responseBody不为空!");
                            }
                            if (writeResponseBodyToDisk(responseBody, fileName, fileUrl)) {
                                Bitmap bitmap = BitmapFactory.decodeFile(((Context) getMyView()).getExternalFilesDir(null) + File.separator + fileName);
                                return bitmap;
                            }
                            return null;
                        }
                    }).subscribe(new RxSubscribe<Bitmap>((Context) getMyView()) {
                @Override
                protected void _onNext(Bitmap bitmap) {
                    getMyView().setAdImg(bitmap);
                }

                @Override
                protected void _onError(String message) {

                }

                @Override
                public void onCompleted() {

                }
            });
        }

    }


    private boolean writeResponseBodyToDisk(ResponseBody body, String fileName, String fileUrl) {//保存图片到本地
        try {
            // todo change the file location/name according to your needs

            File futureStudioIconFile = new File(((Context) getMyView()).getExternalFilesDir(null) + File.separator + fileName);
            L.d("文件的保存地址为:" + ((Context) getMyView()).getExternalFilesDir(null) + File.separator + fileName);
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                byte[] fileReader = new byte[4096];
                long fileSize = body.contentLength();
                long fileSizeDownloaded = 0;
                inputStream = body.byteStream();
                outputStream = new FileOutputStream(futureStudioIconFile);
                while (true) {
                    int read = inputStream.read(fileReader);
                    if (read == -1) {
                        break;
                    }
                    outputStream.write(fileReader, 0, read);
                    fileSizeDownloaded += read;

                    L.d("file download: " + fileSizeDownloaded / fileSize * 100);
                    L.d("file download: " + fileSizeDownloaded + " of " + fileSize);
                }
                outputStream.flush();

                SPUtils.put((Context) getMyView(), "adPictureAddress", ((Context) getMyView()).getExternalFilesDir(null) + File.separator + fileName);//下载好广告图片后,保存好当前广告图片的地址,为判断是否已经下载好图片做准备
                SPUtils.put((Context) getMyView(), "adPictureUrl", fileUrl);
                return true;
            } catch (IOException e) {
                return false;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            }
        } catch (IOException e) {
            return false;
        }
    }

Model

    public Observable<LoginCheckBean> getLoginCheck() {//假装服务器要展示广告
        return Observable.create(new Observable.OnSubscribe<LoginCheckBean>() {
            @Override
            public void call(Subscriber<? super LoginCheckBean> subscriber) {
                subscriber.onNext(new LoginCheckBean(true));
                subscriber.onCompleted();
            }
        });
    }

    public Observable<AdMessageBean> getAdMessage() {
        return Observable.create(new Observable.OnSubscribe<AdMessageBean>() {
            @Override
            public void call(Subscriber<? super AdMessageBean> subscriber) {//假装要展示 3 秒广告,且广告图为如下地址
                subscriber.onNext(new AdMessageBean(3,"http://odjfpxwey.bkt.clouddn.com/2017-3-3-20-141110180-Screenshot_2017-02-23-23-10-26-062_com.tmall.wireless.png","http://www.baidu.com"));
                subscriber.onCompleted();
            }
        });
    }

    public Observable<ResponseBody> downLoadFile(String fileUrl) {
        return retrofitService.downLoadFile(fileUrl);
    }

启动页和广告页的内容暂时是这些

Github地址

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

推荐阅读更多精彩内容

  • 最近在整理做产品以来收集到的各种资料,准备针对app的常见功能模块总结下经验,一来加深学习效果,二来供大家学习交流...
    jason_peng阅读 1,644评论 0 22
  • 老豚曾经说过自己对微商的理解就是:微信上做生意。从某种意义上来说,老豚自己也算是微商,所以,老豚的微信好友基本除了...
    赚女某体阅读 212评论 0 1
  • 两颗小树越长越高 小路越来越窄 一阵风吹过 爱情再也藏不住了~
    雨过晴川阅读 64评论 0 0
  • 不知道为什么考试末尾淘汰让我有一种接受了某种洗礼的感觉,虽然我知道我写的其实并不是很差,被淘汰的那个人不一定是我,...
    MQ是最棒哒阅读 243评论 2 1