Lectura del código fuente del proyecto Toutiao

Dirección del proyecto
Un cliente de Toutiao de terceros, MVP + RxJava + Retrofit

Arquitectura

MVPArquitectura estándar

IBasePresenterSuelo

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();
}
IBaseViewSuelo

Cada capa V tiene una interfaz para mostrar páginas de estado, configuraciones Presentery RxJavadarse 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 INewsArticleinterfaz, donde la INewsArticle.Viewinterfaz es NewsArticleViewimplementada INewsArticle.Presentere NewsArticlePresenterimplementada 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
  1. NewsArticlePresenter
public class NewsArticlePresenter implements INewsArticle.Presenter {
    
    
    private INewsArticle.View view;// NewsArticleView层引用, 用来更新UI.
    public NewsArticlePresenter(INewsArticle.View view) {
    
    
            this.view = view;
    }
}
  1. 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);
        }
    }
}
MVPResumen 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

Cookieadministració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é

OkHttpSe recomienda utilizar RxCache para el caché , que es realmente fácil de usar.

Lidiando con las RxJavapé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);
         });

ViewCó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

TapTargetViewEsta biblioteca se MainActivity.showTapTarget()usa y se usa en el método del proyecto .

Establecer propiedades de la aplicación de forma dinámica

SettingUtilLas 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.

manifestActivityColocació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:configChangesagregar 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 cambiado
  • fontScale: La fuente ha cambiado
  • uiMode: El modo de usuario ha cambiado
  • orientation: La orientación de la pantalla ha cambiado
  • screenSize: El tamaño de la pantalla ha cambiado
  • keyboardHidden: La usabilidad del teclado ha cambiado

Supongo que te gusta

Origin blog.csdn.net/MoLiao2046/article/details/106957752
Recomendado
Clasificación