美文网首页Android知识Android技术知识Android开发
Android练手小项目(KTReader)基于mvp架构(三)

Android练手小项目(KTReader)基于mvp架构(三)

作者: yiuhet | 来源:发表于2017-05-30 22:56 被阅读209次

    上路传送眼:

    Android练手小项目(KTReader)基于mvp架构(二)

    下路传送眼:

    Android练手小项目(KTReader)基于mvp架构(四)

    GIthub地址: https://github.com/yiuhet/KTReader

    上篇文章中我们完成了知乎日报内容的fragment。
    而这次我们要做的的就是知乎日报详情页。

    惯例先上效果图:


    效果图

    准备工作

    • 添加依赖

    compile 'com.jude:swipebackhelper:3.1.2' //右滑关闭详情页

    • 工具类
      utils.WebUtil.class(返回html结果的工具类):
    public class WebUtil {
        private WebUtil() {
        }
    
        public static final String BASE_URL = "file:///android_asset/";
        public static final String MIME_TYPE = "text/html";
        public static final String ENCODING = "utf-8";
        public static final String FAIL_URL = "http//:daily.zhihu.com/";
    
        private static final String CSS_LINK_PATTERN = " <link href=\"%s\" type=\"text/css\" rel=\"stylesheet\" />";
        private static final String DIV_IMAGE_PLACE_HOLDER = "class=\"img-place-holder\"";
    
        public static String buildHtmlWithCss(String html, List<String> cssUrls) {
            StringBuilder result = new StringBuilder();
            for (String cssUrl : cssUrls) {
                result.append(String.format(CSS_LINK_PATTERN, cssUrl));
            }
            result.append(html.replace(DIV_IMAGE_PLACE_HOLDER, ""));
            return result.toString();
        }
    }
    

    Model层

    • 模型实体类ZhihuDetail直接使用GsonFormat工具快速生成
      (model.entity.ZhihuDetail)

    • 知乎日报Model接口
      model.ZhihuDetailModel:

    public interface ZhihuDetailModel {
    
        void loadDetail(String id, OnZhihuDetailListener listener);
    }
    
    • 获取日报详情的Model实现
    public class ZhihuDetailModelImp1 implements ZhihuDetailModel {
        // /*获取日报详情的Model实现*/
    
        private ZhihuApi mZhihuApiService; //请求服务
        private ZhihuDetail mZhihuDetail;
    
        public ZhihuDetailModelImp1() {
            mZhihuDetail = new ZhihuDetail();
            mZhihuApiService = RetrofitManager
                    .getInstence()
                    .getRetrofit("http://news-at.zhihu.com/api/4/news/")
                    .create(ZhihuApi.class); //创建请求服务
        }
    
        public ZhihuDetail getDetail() {
            return mZhihuDetail;
        }
    
    
        @Override
        public void loadDetail(String id, final OnZhihuDetailListener listener) {
            if (mZhihuApiService != null) {
                mZhihuApiService.getDetail(id)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Observer<ZhihuDetail>() {
                            @Override
                            public void onSubscribe(@NonNull Disposable d) {
    
                            }
    
                            @Override
                            public void onNext(@NonNull ZhihuDetail zhihuDetail) {
                                mZhihuDetail = zhihuDetail;
                                listener.onLoadZhihuDetailSuccess(zhihuDetail);//加载成功时 回调接口方法。
                            }
    
                            @Override
                            public void onError(@NonNull Throwable e) {
                                listener.onLoadDataError(e.toString());//加载失败时 回调接口方法。
                            }
    
                            @Override
                            public void onComplete() {
    
                            }
                        });
            }
        }
    }
    

    View层

    • 创建回调接口
      view.ZhihuDetailView:
    public interface ZhihuDetailView {
        void onStartGetData();
    
        void onGetDetailSuccess(ZhihuDetail zhihuDetail);
    
        void onGetDetailFailed(String error);
    }
    
    • 创建ZhihuDetailActivity
      详情页包含的新知识点全在ZhihuDetailActivity上,所涵盖的知识有:
      • WebView的使用
      • 右滑关闭activity(也不算知识点,因为使用别人的开源,以后要改写成自己的)
      • CollapsingToolbarLayout 和NestedScrollView的使用

    附上一些资料:
    WebView·开车指南
    看,这个工具栏能伸缩折叠——Android CollapsingToolbarLayout使用
    [Jude95/SwipeBackHelper]

    具体解释全都在代码注释里。
    直接上代码
    ui.activity.ZhihuDetailActivity .class:

    public class ZhihuDetailActivity extends MVPBaseActivity<ZhihuDetailView, ZhihuDetailPresenterImp1> implements ZhihuDetailView {
    
        @BindView(R.id.toolbar)
        Toolbar mToolbar;
        @BindView(R.id.toolbar_layout)
        CollapsingToolbarLayout mToolbarLayout;
        @BindView(R.id.prograss)
        ProgressBar mPrograss;
        @BindView(R.id.wv_zhihu)
        WebView mWvZhihu;
        @BindView(R.id.fab)
        FloatingActionButton mFab;
        @BindView(R.id.iv_title)
        ImageView mIvTitle;
        private String mZhihuId;
    
        @Override
        protected ZhihuDetailPresenterImp1 createPresenter() {
            return new ZhihuDetailPresenterImp1(this);
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            SwipeBackHelper.onCreate(this);
            ButterKnife.bind(this);
            initToolbar();
            initView();
        }
    
        private void initToolbar() {
            setSupportActionBar(mToolbar);
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            getSupportActionBar().setHomeButtonEnabled(true);
        }
    
        private void initView() {
            mZhihuId = getIntent().getStringExtra("ZHIHUID");
            mPresenter.getDetail(mZhihuId);
            mFab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, "已添加进收藏夹(待做功能)", Snackbar.LENGTH_LONG)
                            .setAction("Action", null).show();
                }
            });
            mWvZhihu.setVerticalScrollBarEnabled(true);
            mWvZhihu.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);
    
            WebSettings settings = mWvZhihu.getSettings();
            //设置应用缓存路径,这个路径必须是可以让app写入文件的。该方法应该只被调用一次,重复调用会被无视~
            settings.setAppCachePath(getCacheDir().getAbsolutePath() + "/webViewCache");
            settings.setAppCacheEnabled(true); //启用应用缓存。
            settings.setDatabaseEnabled(true); //启用数据库缓存。
            settings.setDomStorageEnabled(true); //开启DOM缓存
            //用来设置WebView的缓存模式(这里使用的是 只要缓存可用就加载缓存)
            settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
            settings.setJavaScriptEnabled(true); //设置WebView可以运行JavaScript。
            settings.setBuiltInZoomControls(true);//显示或不显示缩放按钮(wap网页不支持)。
            //指定WebView的页面布局显示形式,调用该方法会引起页面重绘
            settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
            mWvZhihu.setWebChromeClient(new WebChromeClient());
    
        }
    
        @Override
        protected int getLayoutRes() {
            return R.layout.activity_zhihu_detail;
        }
    
        @Override
        public void onStartGetData() {
            mPrograss.setVisibility(View.VISIBLE);
        }
    
        @Override
        public void onGetDetailSuccess(ZhihuDetail zhihuDetail) {
            mPrograss.setVisibility(View.GONE);
            mToolbarLayout.setTitle(zhihuDetail.title);
            //在较为特殊的情况下,知乎日报可能将某个主题日报的站外文章推送至知乎日报首页。
            if (zhihuDetail.body == null) {
                mWvZhihu.loadUrl(zhihuDetail.shareUrl);
            } else {
                Glide.with(this).load(zhihuDetail.image).into(mIvTitle);
                String data = WebUtil.buildHtmlWithCss(zhihuDetail.body, zhihuDetail.css);
                mWvZhihu.loadDataWithBaseURL(WebUtil.BASE_URL, data, WebUtil.MIME_TYPE, WebUtil.ENCODING, WebUtil.FAIL_URL);
            }
        }
    
        @Override
        public void onGetDetailFailed(String error) {
            mPrograss.setVisibility(View.GONE);
            toast(error);
        }
    
        @Override
        protected void onPostCreate(@Nullable Bundle savedInstanceState) {
            super.onPostCreate(savedInstanceState);
            SwipeBackHelper.onPostCreate(this);
        }
    
        @Override
        protected void onDestroy() {
            if (mWvZhihu != null) {
                //webview内存泄露
                ((ViewGroup) mWvZhihu.getParent()).removeView(mWvZhihu);
                mWvZhihu.destroy();
                mWvZhihu = null;
            }
            super.onDestroy();
            SwipeBackHelper.onDestroy(this);
        }
    }
    
    

    另附上ZhihuDetailActivity的布局文件:

    activity_zhihu_detail.xml:

    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context="com.example.yiuhet.ktreader.ui.activity.ZhihuDetailActivity">
    
        <android.support.design.widget.AppBarLayout
            android:id="@+id/app_bar"
            android:layout_width="match_parent"
            android:layout_height="@dimen/app_bar_height"
            android:fitsSystemWindows="true"
            android:theme="@style/AppTheme.AppBarOverlay">
    
            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                app:contentScrim="?attr/colorPrimary"
                app:expandedTitleMarginBottom="16dp"
                app:expandedTitleMarginStart="24dp"
                app:expandedTitleTextAppearance="@style/TextAppearance.AppCompat.Title"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">
    
                <ImageView
                    android:id="@+id/iv_title"
                    android:layout_width="match_parent"
                    android:scaleType="centerCrop"
                    app:layout_collapseMode="parallax"
                    app:layout_collapseParallaxMultiplier="0.5"
                    android:fitsSystemWindows="true"
                    android:layout_height="match_parent"/>
                <FrameLayout
                    android:layout_width="match_parent"
                    android:layout_height="48dp"
                    android:layout_gravity="bottom"
                    android:background="@color/title_mask"></FrameLayout>
                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"
                    app:layout_scrollFlags="scroll|enterAlways|snap"
                    app:popupTheme="@style/AppTheme.PopupOverlay" />
    
            </android.support.design.widget.CollapsingToolbarLayout>
        </android.support.design.widget.AppBarLayout>
    
        <include layout="@layout/content_zhihu_detail" />
    
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/fab_margin"
            app:layout_anchor="@id/app_bar"
            app:layout_anchorGravity="bottom|end"
            app:srcCompat="@android:drawable/ic_dialog_email" />
    
    </android.support.design.widget.CoordinatorLayout>
    

    content_zhihu_detail.xml:

    <android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:context="com.example.yiuhet.ktreader.ui.activity.ZhihuDetailActivity"
        tools:showIn="@layout/activity_zhihu_detail">
    
            <WebView
                android:id="@+id/wv_zhihu"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <ProgressBar
                    android:id="@+id/prograss"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:indeterminate="true"
                    android:indeterminateTint="?android:colorAccent"/>
            </WebView>
    </android.support.v4.widget.NestedScrollView>
    

    ZhihuDetailActivity里的fab点击事件预想是添加入收藏栏,等之后写到收藏栏功能时会完成该功能
    ps:从效果图中,可以看出CollapsingToolbarLayout的title显示不全,目前还没找到解决办法(貌似可以写theme解决,回头再实验下),如果有知道的,请告知,谢谢。

    Presenter层

    在ZhihuPresenterImp1类里实现数据和视图的绑定

    • 先写一个回调接口:
      (在Presenter层实现,给Model层回调,更改View层的状态,确保Model层不直接操作View层)
      presenter.OnZhihuDetailListener :
    public interface OnZhihuDetailListener {
    
        void onLoadZhihuDetailSuccess(ZhihuDetail zhihuDetail);
    
        void onLoadDataError(String error);
    }
    
    • 再写一个presenter接口:
      presenter.ZhihuDetailPresenter :
    public interface ZhihuDetailPresenter {
        void getDetail(String id);
    }
    
    • 最后写Prestener实现类:
      presenter.imp1.ZhihuDetailPresenterImp1 .class:
    public class ZhihuDetailPresenterImp1 extends BasePresenter<ZhihuDetailView> implements ZhihuDetailPresenter,OnZhihuDetailListener{
        /*Presenter作为中间层,持有View和Model的引用*/
        private ZhihuDetailView mZhihuDetailView;
        private ZhihuDetailModelImp1 zhihuDetailModelImp1;
        String id;
    
        public ZhihuDetailPresenterImp1(ZhihuDetailView zhihuDetailView) {
            mZhihuDetailView = zhihuDetailView;
            zhihuDetailModelImp1 = new ZhihuDetailModelImp1();
        }
    
    
        @Override
        public void getDetail(String id) {
            mZhihuDetailView.onStartGetData();
            zhihuDetailModelImp1.loadDetail(id, this);
        }
    
    
        @Override
        public void onLoadZhihuDetailSuccess(ZhihuDetail zhihuDetail) {
    
            mZhihuDetailView.onGetDetailSuccess(zhihuDetail);
        }
    
        @Override
        public void onLoadDataError(String error) {
            mZhihuDetailView.onGetDetailFailed(error);
        }
    }
    

    相关文章

      网友评论

        本文标题:Android练手小项目(KTReader)基于mvp架构(三)

        本文链接:https://www.haomeiwen.com/subject/buaoxxtx.html