Dirección del proyecto
Un cliente de Toutiao de terceros, MVP + RxJava + Retrofit
Arquitectura
MVP
Arquitectura estándar
IBasePresenter
Suelo
Cada capa P tiene una interfaz de actualización y muestra los requisitos de error de la red
public interface IBasePresenter {
void doRefresh();
void doShowNetError();
}
IBaseView
Suelo
Cada capa V tiene una interfaz para mostrar páginas de estado, configuraciones Presenter
y RxJava
darse de baja para evitar pérdidas de memoria.
public interface IBaseView<T> {
void onShowLoading();
void onHideLoading();
void onShowNetError();
void setPresenter(T presenter); // P类型由V层泛型决定
<X> AutoDisposeConverter<X> bindAutoDispose();
}
Análisis de la estructura de la página de noticias
Cree una nueva INewsArticle
interfaz, donde la INewsArticle.View
interfaz es NewsArticleView
implementada INewsArticle.Presenter
e NewsArticlePresenter
implementada por .
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();
}
}
Análisis de páginas de noticias
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
Resumen de arquitectura
// 顶层接口定义一些共有的方法
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();
}
}
La Internet
El marco de red usa Retorfit + OkHttp + RxJava
Cookie
administración
Se utiliza una biblioteca de terceros. Las configuraciones simples son las siguientes: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();
Gestión de caché
OkHttp
Se recomienda utilizar RxCache para el caché , que es realmente fácil de usar.
Lidiando con las RxJava
pérdidas de memoria
El proyecto no se utiliza RxLifecycle
, están utilizando AutoDispose
.
Ejemplos:
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
Cómo se implementa la capabindAutoDispose()
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间的订阅.
}
}
Efecto resaltado
TapTargetView
Esta biblioteca se MainActivity.showTapTarget()
usa y se usa en el método del proyecto .
Establecer propiedades de la aplicación de forma dinámica
SettingUtil
Las herramientas del proyecto pueden establecer el color del tema, el color de la barra de navegación, la pantalla horizontal de video, el tamaño de fuente, etc.
manifest
Activity
Colocación media
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|uiMode"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"/>
Cuando el dispositivo Android se está ejecutando, la configuración del dispositivo puede cambiar, como el cambio de pantalla horizontal y vertical, el teclado, etc., lo que hará que la actividad se reinicie. Antes de destruir, llame a onSaveInstanceState () para guardar algunos datos en la aplicación para su uso cuando se restaure la Actividad. Si desea que el teléfono Si el cambio de configuración no reinicia la Actividad, debe android:configChanges
agregar algunas propiedades a la Actividad actual , de modo que cuando la configuración cambie, la Actividad no se reiniciará pero el onConfigurationChanged()
método de Actividad ser llamado .
navigation
: La barra de navegación ha cambiadofontScale
: La fuente ha cambiadouiMode
: El modo de usuario ha cambiadoorientation
: La orientación de la pantalla ha cambiadoscreenSize
: El tamaño de la pantalla ha cambiadokeyboardHidden
: La usabilidad del teclado ha cambiado