Android练手小项目(KTReader)基于mvp架构(三)
16lz
2021-01-24
上路传送眼:
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 = " "; private static final String DIV_IMAGE_PLACE_HOLDER = "class=\"img-place-holder\""; public static String buildHtmlWithCss(String html, List 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() { @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 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:
content_zhihu_detail.xml:
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 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库中不能使用switch-case语句访问资源ID
- Android开发 Handler+ExecutorService(线程池)+MessageQueue模式
- Android传感器的运用之ACCELEROMETER
- 什么是aidl?Android(安卓)AIDL详解
- 漫谈Android数据缓存、数据序列化和Intent传递复杂数据
- android camera API1调用camera HAL3流程学习总结
- Android学习笔记--Binder
- Android关机流程解析---从reboot说起
- Android和IOS获取crash信息