Project address
A third-party Toutiao client, MVP + RxJava + Retrofit
Architecture
Standard MVP
architecture
IBasePresenter
Floor
Each P layer has a refresh interface and display network error requirements
public interface IBasePresenter {
void doRefresh();
void doShowNetError();
}
IBaseView
Floor
Each V layer has an interface to display status pages, settings Presenter
, and RxJava
unsubscribe to prevent memory leaks.
public interface IBaseView<T> {
void onShowLoading();
void onHideLoading();
void onShowNetError();
void setPresenter(T presenter); // P类型由V层泛型决定
<X> AutoDisposeConverter<X> bindAutoDispose();
}
Analysis of news page structure
Create a new INewsArticle
interface, where the INewsArticle.View
interface is NewsArticleView
implemented INewsArticle.Presenter
by and NewsArticlePresenter
implemented by .
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();
}
}
Analysis of news pages
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
Architecture summary
// 顶层接口定义一些共有的方法
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();
}
}
The internet
The network framework uses Retorfit+OkHttp+RxJava
Cookie
management
A third-party library is used. The simple settings are as follows: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();
Cache management
OkHttp
It is recommended to use RxCache for the cache , which is really easy to use.
Dealing with RxJava
memory leaks
The project is not used RxLifecycle
, are using the AutoDispose
.
Examples:
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
How the layer is implementedbindAutoDispose()
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间的订阅.
}
}
Highlight effect
TapTargetView
This library is MainActivity.showTapTarget()
used, and it is used in the method in the project .
Dynamically set APP properties
SettingUtil
Tools in the project can set theme color, navigation bar color, video horizontal screen, font size, etc.
manifest
Medium Activity
placement
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|uiMode"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"/>
When the Android device is running, the device configuration may change, such as horizontal and vertical screen switching, keyboard, etc., which will cause the Activity to restart. Before destroying, call onSaveInstanceState() to save some data in the application for use when the Activity is restored. If you want the phone If the configuration changes do not restart the Activity, you need to android:configChanges
add some properties to the current Activity , so that when the configuration changes, the Activity will not be restarted but the Activity onConfigurationChanged()
method will be called .
navigation
: The navigation bar has changedfontScale
: The font has changeduiMode
: The user mode has changedorientation
: The screen orientation has changedscreenSize
: The screen size has changedkeyboardHidden
: Keyboard usability has changed