EasyGank源码分析:从项目启动到网络请求的完整执行流程
【免费下载链接】EasyGank💊 The project build framework based on the Rx series and MVP pattern.项目地址: https://gitcode.com/gh_mirrors/ea/EasyGank
EasyGank是一个基于Rx系列和MVP模式构建的Android项目框架,通过本文你将了解其从应用启动到网络请求的完整执行流程,掌握MVP架构在实际项目中的应用方式。
项目整体架构概览
EasyGank采用经典的MVP(Model-View-Presenter)架构模式,代码结构清晰,主要分为以下几个核心模块:
- 视图层(View):位于
app/src/main/java/com/camnter/easygank/views/目录,包含所有Activity和Fragment - ** presenter层**:位于
app/src/main/java/com/camnter/easygank/presenter/目录,处理业务逻辑 - 模型层(Model):位于
app/src/main/java/com/camnter/easygank/model/目录,负责数据获取和处理 - 数据层:位于
app/src/main/java/com/camnter/easygank/data/目录,管理网络请求和本地缓存
应用启动流程解析
1. Application初始化
应用的入口点是EasyApplication类,它继承自Application并在AndroidManifest.xml中注册。其主要职责包括:
public class EasyApplication extends Application { private static EasyApplication ourInstance = new EasyApplication(); public boolean log = true; public Gson gson; @Override public void onCreate() { super.onCreate(); ourInstance = this; Logger.init(); // 初始化日志工具 this.initGson(); // 初始化Gson解析器 this.initReservoir(); // 初始化本地缓存 } private void initGson() { this.gson = new GsonBuilder().setDateFormat(GankApi.GANK_DATA_FORMAT).create(); } private void initReservoir() { try { Reservoir.init(this, CACHE_DATA_MAX_SIZE, this.gson); } catch (Exception e) { e.printStackTrace(); } } }EasyApplication使用单例模式,通过getInstance()方法提供全局访问点,同时初始化了Gson和Reservoir(本地缓存库),为整个应用提供基础服务。
2. 主界面启动
应用启动后,会进入MainActivity,它继承自BaseDrawerLayoutActivity,实现了MainView接口:
public class MainActivity extends BaseDrawerLayoutActivity implements MainView, MainAdapter.OnClickListener { @Override protected void initData() { this.presenter = new MainPresenter(); // 创建Presenter实例 this.presenter.attachView(this); // 绑定View this.gankType = GankType.daily; this.mainAdapter = new MainAdapter(this, this.gankType); this.mainRv.setAdapter(this.mainAdapter); this.refreshData(this.gankType); // 刷新数据 } }在initData()方法中,MainActivity创建了MainPresenter实例并与其绑定,然后初始化适配器并开始刷新数据,完成了MVP模式中View与Presenter的关联。
MVP架构核心交互流程
1. View与Presenter的绑定
MainActivity通过以下代码与MainPresenter建立联系:
this.presenter = new MainPresenter(); this.presenter.attachView(this);MainPresenter继承自BasePresenter,后者实现了Presenter接口,提供了MVP模式的基础方法:
public class BasePresenter<V extends MvpView> implements Presenter<V> { protected V mMvpView; protected DataManager mDataManager; protected CompositeSubscription mCompositeSubscription; @Override public void attachView(V mvpView) { this.mMvpView = mvpView; this.mDataManager = DataManager.getInstance(); this.mCompositeSubscription = new CompositeSubscription(); } @Override public void detachView() { this.mMvpView = null; if (this.mCompositeSubscription != null) { this.mCompositeSubscription.unsubscribe(); } } }2. 数据请求流程
当用户需要获取数据时,MainActivity会调用Presenter的相应方法:
private void refreshData(int gankType) { this.presenter.setPage(1); new Handler().post(() -> MainActivity.this.refresh(true)); switch (gankType) { case GankType.daily: this.presenter.getDaily(true, GankTypeDict.DONT_SWITCH); break; // 其他类型数据请求... } }MainPresenter的getDaily()方法实现数据请求逻辑:
public void getDaily(final boolean refresh, final int oldPage) { this.mCompositeSubscription.add(this.mDataManager.getDailyDataByNetwork(this.currentDate) .subscribe(new Subscriber<List<GankDaily>>() { @Override public void onCompleted() { // 完成处理 } @Override public void onError(Throwable e) { // 错误处理 } @Override public void onNext(List<GankDaily> dailyData) { // 刷新缓存 if (refresh) MainPresenter.this.reservoirUtils.refresh(GankType.daily + "", dailyData); // 通知View更新 if (MainPresenter.this.getMvpView() != null) MainPresenter.this.getMvpView().onGetDailySuccess(dailyData, refresh); } })); }3. 数据响应与UI更新
当Presenter获取到数据后,通过MainView接口通知View更新UI:
// MainPresenter.java MainPresenter.this.getMvpView().onGetDailySuccess(dailyData, refresh); // MainActivity.java (实现MainView接口) @Override public void onGetDailySuccess(List<GankDaily> dailyData, boolean refresh) { if (refresh) { this.emptyCount = 0; this.mainAdapter.clear(); this.mainAdapter.setList(dailyData); } else { this.mainAdapter.addAll(dailyData); } this.mainAdapter.notifyDataSetChanged(); this.refresh(false); }这种方式实现了业务逻辑与UI展示的分离,符合MVP模式的设计思想。
网络请求实现细节
1. DataManager数据管理
DataManager是数据获取的统一入口,封装了网络请求和本地缓存操作:
public class DataManager { private static DataManager ourInstance; private GankService mGankService; private DataManager() { this.mGankService = GankApi.getGankService(); } public static DataManager getInstance() { if (ourInstance == null) { ourInstance = new DataManager(); } return ourInstance; } public Observable<List<GankDaily>> getDailyDataByNetwork(MainPresenter.EasyDate currentDate) { return Observable.just(currentDate) .flatMapIterable(MainPresenter.EasyDate::getPastTime) .flatMap(this::getDailyDataByEasyDate) .filter(gankDaily -> gankDaily != null) .toList(); } }2. Retrofit网络请求
项目使用Retrofit进行网络请求,相关代码位于app/src/main/java/com/camnter/easygank/gank/目录:
// GankApi.java public class GankApi { public static final String GANK_API_URL = "http://gank.io/api/"; public static final String GANK_DATA_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SS'Z'"; public static final int DEFAULT_DATA_SIZE = 10; public static final int DEFAULT_DAILY_SIZE = 7; private static GankService gankService; public static GankService getGankService() { if (gankService == null) { Retrofit retrofit = new Retrofit.Builder() .baseUrl(GANK_API_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); gankService = retrofit.create(GankService.class); } return gankService; } } // GankService.java public interface GankService { @GET("day/{year}/{month}/{day}") Observable<GankDaily> getDailyData( @Path("year") int year, @Path("month") int month, @Path("day") int day ); @GET("data/{type}/{count}/{page}") Observable<GankData> getGankData( @Path("type") String type, @Path("count") int count, @Path("page") int page ); }3. RxJava异步处理
项目大量使用RxJava进行异步操作和线程调度,例如在MainPresenter的getDaily()方法中:
this.mCompositeSubscription.add(this.mDataManager.getDailyDataByNetwork(this.currentDate) .subscribeOn(Schedulers.io()) // 订阅在IO线程 .observeOn(AndroidSchedulers.mainThread()) // 观察在主线程 .subscribe(new Subscriber<List<GankDaily>>() { // 回调处理... }));通过CompositeSubscription管理订阅关系,确保在适当的时候取消订阅,避免内存泄漏。
数据缓存策略
EasyGank使用Reservoir库实现本地数据缓存,在EasyApplication中初始化:
private void initReservoir() { try { Reservoir.init(this, CACHE_DATA_MAX_SIZE, this.gson); } catch (Exception e) { e.printStackTrace(); } }在MainPresenter中,数据请求成功后会更新缓存:
// 刷新缓存 if (refresh) MainPresenter.this.reservoirUtils.refresh(GankType.daily + "", dailyData);当网络请求失败时,会尝试从缓存中读取数据:
if (refresh) { Type resultType = new TypeToken<List<GankDaily>>() {}.getType(); MainPresenter.this.reservoirUtils.get(GankType.daily + "", resultType, new ReservoirGetCallback<List<GankDaily>>() { @Override public void onSuccess(List<GankDaily> object) { // 有缓存显示缓存数据 if (MainPresenter.this.getMvpView() != null) MainPresenter.this.getMvpView().onGetDailySuccess(object, refresh); } @Override public void onFailure(Exception e) { MainPresenter.this.switchFailure(oldPage, e); } }); }这种缓存策略提高了应用的离线可用性和响应速度。
总结与最佳实践
通过对EasyGank源码的分析,我们可以总结出以下几点MVP架构的最佳实践:
- 职责分离:View只负责UI展示,Presenter处理业务逻辑,Model管理数据
- 接口定义:通过接口明确View和Presenter的通信契约
- 生命周期管理:在Activity/Fragment的生命周期方法中绑定和解绑Presenter
- 异步处理:使用RxJava处理异步操作,避免阻塞主线程
- 数据缓存:实现网络请求与本地缓存的结合,提升用户体验
EasyGank项目展示了如何在Android应用中优雅地实现MVP架构,通过RxJava和Retrofit的结合,构建了一个响应式、可维护的应用框架。开发者可以借鉴其设计思想,在自己的项目中实践MVP模式,提高代码质量和开发效率。
要开始使用EasyGank项目,只需执行以下命令克隆仓库:
git clone https://gitcode.com/gh_mirrors/ea/EasyGank【免费下载链接】EasyGank💊 The project build framework based on the Rx series and MVP pattern.项目地址: https://gitcode.com/gh_mirrors/ea/EasyGank
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考