项目地址
一款第三方今日头条客户端, MVP + RxJava + Retrofit
架构
标准的MVP
架构
IBasePresenter
层
每个P层都有刷新界面以及显示网络错误需求
public interface IBasePresenter {
void doRefresh();
void doShowNetError();
}
IBaseView
层
每个V层都有展示状态页,设置Presenter
,以及解除RxJava
订阅防止内存泄漏的接口.
public interface IBaseView<T> {
void onShowLoading();
void onHideLoading();
void onShowNetError();
void setPresenter(T presenter); // P类型由V层泛型决定
<X> AutoDisposeConverter<X> bindAutoDispose();
}
对新闻页架构分析
新建INewsArticle
接口,其中INewsArticle.View
接口由NewsArticleView
实现,INewsArticle.Presenter
由NewsArticlePresenter
实现.
public interface INewsArticle {
// INewsArticle.View接口继承自IBaseListView接口,可以看作是对IBaseListView接口方法的补充.
// INewsArticle.View接口中定义了新闻页的行为方法
// IBaseListView<Presenter> 该泛型决定了P层类型,也就是该P层类型必须为INewsArticle.Presenter类型.
interface View extends IBaseListView<Presenter> {
void onLoadData();
void onRefresh();
}
// INewsArticle.Presenter接口继承自IBasePresenter接口,可以看作是对IBaseListView接口方法的扩充
// INewsArticle.Presenter接口中定义了新闻页P层的行为方法
interface Presenter extends IBasePresenter {
void doLoadData(String... category);
void doLoadMoreData();
void doSetAdapter(List<MultiNewsArticleDataBean> dataBeen);
void doShowNoMore();
}
}
对新闻页分析
NewsArticlePresenter
public class NewsArticlePresenter implements INewsArticle.Presenter {
private INewsArticle.View view;// NewsArticleView层引用, 用来更新UI.
public NewsArticlePresenter(INewsArticle.View view) {
this.view = view;
}
}
NewsArticleView
// <INewsArticle.Presenter>: 该泛型是用来确定创建得P层对象的类型.
public class NewsArticleView extends BaseListFragment<INewsArticle.Presenter> implements INewsArticle.View {
// IBaseView接口中定义得setPresenter()方法,在这里实现.
@Override
public void setPresenter(INewsArticle.Presenter presenter) {
if (null == presenter) {
// this.presenter: 在BaseFragment中定义了一个变量presenter,专门用来接收P层对象..
this.presenter = new NewsArticlePresenter(this);
}
}
}
MVP
架构总结
// 顶层接口定义一些共有的方法
interface IBaseP {
}
interface IBaseV<T> {
// 为V层创建P层对象
// 泛型T确定了P层对象的类型
T setPresenter(T t);
}
// 次级接口定义自己特有的方法
interface IMy {
// <MyP>: 确定P层对象的类型为MyP
interface MyV extends IBaseV<MyP> {
void refreshPage();// 更新UI
}
interface MyP extends IBaseP {
void getData();// 获取数据
}
}
// P层的实现
// <T extends IMy.MyV>: 确定P层持有的V层类型
class MyPresenter<T extends IMy.MyV> implements IMy.MyP {
T mView;
public MyPresenter(T mView) {
this.mView = mView;
}
@Override
public void getData() {
System.out.println("获取数据");
mView.refreshPage();// 获取数据之后更新界面
}
}
// 定义BaseActivity,<T>用来确定P层对象的类型.
abstract class BaseActivity<T> implements IBaseV<T> {
T mPresenter;
public BaseActivity() {
// 调用子类实现的setPresenter()方法,创建P层对象,由父类mPresenter变量保存.
mPresenter = setPresenter(mPresenter);
}
}
// V层实现类
// <IMy.MyP>: 确定P层对象类型.
class MyActivity extends BaseActivity<IMy.MyP> implements IMy.MyV {
public MyActivity() {
mPresenter.getData();
}
@Override
public void refreshPage() {
System.out.println("更新界面");
}
// IBaseV.setPresenter()接口方法的具体实现.
@Override
public IMy.MyP setPresenter(IMy.MyP myP) {
// <IMy.MyV>: 用来确认P层中V对象的类型.
return new MyPresenter<IMy.MyV>(this);
}
}
public class MVP {
public static void main(String[] args) {
// 模拟Activity启动之后获取数据然后刷新界面
new MyActivity();
}
}
网络
网络框架使用的是Retorfit+OkHttp+RxJava
Cookie
管理
使用的是一个第三方库PersistentCookieJar
简单的设置如下:
ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(InitApp.AppContext));
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.cache(cache)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
缓存管理
OkHttp
的缓存推荐使用RxCache,这个真的非常好用.
处理RxJava
内存泄漏
项目中没有使用RxLifecycle
,使用的是AutoDispose
.
例子:
RetrofitFactory.getRetrofit().create(IMobileNewsApi.class)
.getNewsComment(groupId, offset)
.subscribeOn(Schedulers.io())
...
.observeOn(AndroidSchedulers.mainThread())
.as(view.bindAutoDispose()) // bindAutoDispose该方法由View层实现.
.subscribe(list -> {
if (null != list && list.size() > 0) {
doSetAdapter(list);
} else {
doShowNoMore();
}
}, throwable -> {
doShowNetError();
ErrorAction.print(throwable);
});
View
层如何实现的bindAutoDispose()
public abstract class BaseFragment<T extends IBasePresenter> extends Fragment implements IBaseView<T> {
/**
* 绑定生命周期
*/
@Override
public <X> AutoDisposeConverter<X> bindAutoDispose() {
return AutoDispose.autoDisposable(AndroidLifecycleScopeProvider
.from(this, Lifecycle.Event.ON_DESTROY)); // 当Activity被销毁时候,接触RxJava间的订阅.
}
}
高亮提示效果
TapTargetView
使用的是这个库,项目中是在MainActivity.showTapTarget()
方法中用到.
动态设置APP属性
项目中SettingUtil
工具类可以设置主题颜色,导航栏上色,视频横屏,字体大小等.
manifest
中Activity
配置
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|uiMode"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"/>
Android 设备运行时候,设备的配置可能发生改变,如横竖屏切换,键盘等,这样会导致Activity重启,销毁前先调用onSaveInstanceState()保存应用中的一些数据,供Activity恢复时候使用.如果想让手机的配置改变不重启Activity的话需要为当前Activity的android:configChanges
添加某些属性,这样当配置改变时不会重启Activity而是会调用Activity的onConfigurationChanged()
方法.
navigation
:导航栏发生了变化fontScale
: 字体发生了变化uiMode
:用户模式发生了变化orientation
:屏幕方向发生了变化screenSize
:屏幕大小发生了变化keyboardHidden
: 键盘可用性发生了变化