通过Github开源项目学习知识,是一种非常好的学习方式。下面我们就来看看一个非常流行的框架App,它采用了最火的OkHttp+Rxjava+Retrofit来搭建网络框架,并且完全遵守Metarial design 新特性,还有项目采用了MVP模式,是真正的学习干货,在此声明,博客只是个人学习记录的方式。
UGank下载地址
/**
业务操作父类,定义两个基本的操作
*/
public interface BasePresenter {
void subscribe();
void unsubscribe();
}
/**
定义一个类,里面有两个接口,一个涉及界面操作,一个涉及业务操作
**/
public class LauncherContract {
interface View extends BaseView {
void goHomeActivity();
void loadImg(String url);
}
interface Presenter extends BasePresenter {
}
}
定义一个业务实现类,来实现业务接口。
/**
* LauncherPresenter
* Presenter的具体实现类
*/
public class LauncherPresenter implements LauncherContract.Presenter {
/**
*这是一个接口,用来操作UI
*/
private LauncherContract.View mLauncherView;
/**
* 通过构造传递接口对象
* @param view
*/
public LauncherPresenter(LauncherContract.View view) {
mLauncherView = view;
}
/**
* 操作业务逻辑
*/
@Override
public void subscribe() {
if (!ConfigManage.INSTANCE.isShowLauncherImg()) {
mLauncherView.goHomeActivity();
return;
}
String imgCacheUrl = ConfigManage.INSTANCE.getBannerURL();
if (!TextUtils.isEmpty(imgCacheUrl)) {
mLauncherView.loadImg(imgCacheUrl);
} else {
mLauncherView.goHomeActivity();
}
}
/**
* Activity销毁时的业务操作
*/
@Override
public void unsubscribe() {
}
}
然后界面Activity实现业务接口的Ui操作接口,并且持有一个业务操作接口实现类对象。
/**
* LauncherActivity
* SplashActivity实现了Ui操作接口
*/
public class LauncherActivity extends AppCompatActivity implements LauncherContract.View {
@BindView(R.id.img_launcher_welcome)
AppCompatImageView mImageView;
// 记录该 Activity 是否在前台显示
private boolean isResume;
/**
* 创建了一个业务操作的对象,通过传参把界面对象传入
*/
private LauncherContract.Presenter mLauncherPresenter = new LauncherPresenter(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_launcher);
ButterKnife.bind(this);//绑定View对象
mLauncherPresenter.subscribe();//执行业务操作
}
/**
* UI界面操作,加载显示Logo妹子
* @param url
*/
@Override
public void loadImg(String url) {
try {
Picasso.with(this).load(url).into(mImageView, new Callback() {
@Override
public void onSuccess() {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (!isResume) {
finish();
return;
}
goHomeActivity();
}
}, 1200);
}
@Override
public void onError() {
goHomeActivity();
}
});
} catch (Exception e) {
goHomeActivity();
}
}
@Override
protected void onResume() {
super.onResume();
isResume = true;
}
@Override
protected void onPause() {
super.onPause();
isResume = false;
}
@Override
public void goHomeActivity() {
Intent intent = new Intent(LauncherActivity.this, HomeActivity.class);
startActivity(intent);
// Activity 切换淡入淡出动画
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
finish();
}
@Override
public void onBackPressed() {
// 禁掉返回键
}
/**
* Activity销毁时的业务逻辑
*/
@Override
protected void onDestroy() {
super.onDestroy();
mLauncherPresenter.unsubscribe();
}
}
通过实现接口的形式,来分离UI和业务之间的耦合,然后在Presenter层来反操作Ui,去实现业务。
然后我们看看网络框架工具类。
/**
* 网络层
* 封装OkHttp和Retrofit+RxJava搭建网络框架
*/
public class NetWork {
private static GankApi gankApi; //使用Retrofit封装请求
private static OkHttpClient okHttpClient = new OkHttpClient();// 创建OkHttpClient实例
//使用Gson解析的解析工厂类,来自Retrofit包
private static Converter.Factory gsonConverterFactory = GsonConverterFactory.create();
//使用RxJava来创建观察者对象的工厂类,来自Retrofit包
private static CallAdapter.Factory rxJavaCallAdapterFactory = RxJavaCallAdapterFactory.create();
public static GankApi getGankApi() {
if (gankApi == null) {
Retrofit retrofit = new Retrofit.Builder().client(okHttpClient)
.baseUrl("http://gank.io/api/")
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(rxJavaCallAdapterFactory)
.build();
gankApi = retrofit.create(GankApi.class);
}
return gankApi;
}
}
/**
* gank.io 接口
* 使用注解来定义网络接口和需要的传参,和Model层实现链接
*/
public interface GankApi {
/**
android、ios、前端等数据接口
*/
@GET("data/{category}/{number}/{page}")
Observable<CategoryResult> getCategoryDate(@Path("category") String category,
@Path("number") int number, @Path("page") int page);
/**
*首页Banner的妹子图接口
*/
@GET("random/data/福利/{number}")
Observable<CategoryResult> getRandomBeauties(@Path("number") int number);
/**
搜索框接口
*/
@GET("search/query/{key}/category/all/count/{count}/page/{page}")
Observable<SearchResult> getSearchResult(@Path("key") String key,
@Path("count") int count, @Path("page") int page);
}
项目总共三个接口,妹子图通过FloatingActionButton来获取下一张,底部的Fragement数据通过传参的不同,返回不同的数据集合进行展示,还有一个查询接口来查询数据。下面看看最主要的数据获取的Presenter。
/**
* CategoryPresenter
* 首页所有的Fragment的数据,通过 View层的(mCategoryView.getCategoryName()来改变数据展示
*/
public class CategoryPresenter implements CategoryContract.Presenter {
private int mPage = 1;//数据的页数
private CategoryContract.View mCategoryView;//View层的对象引用
@NonNull
private CompositeSubscription mSubscriptions;//统一的事件回调监听器
public CategoryPresenter(CategoryContract.View androidView) {
mCategoryView = androidView;
mSubscriptions = new CompositeSubscription(); //创建统一的事件回调监听器
}
/**
* 加载数据
*/
@Override
public void subscribe() {
getCategoryItems(true);
}
/**
* 清空订阅器
*/
@Override
public void unsubscribe() {
mSubscriptions.clear();
}
@Override
public void getCategoryItems(final boolean isRefresh) {
if (isRefresh) {
mCategoryView.showSwipeLoading();
mPage = 1;
} else {
mPage += 1;
}
Subscription subscription = NetWork.getGankApi()
.getCategoryDate(mCategoryView.getCategoryName(), GlobalConfig.PAGE_SIZE_CATEGORY, mPage)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<CategoryResult>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
mCategoryView.hideSwipeLoading(); //隐藏加载框
mCategoryView.getCategoryItemsFail(mCategoryView.getCategoryName()
+ " 列表数据获取失败。");
}
@Override
public void onNext(CategoryResult androidResult) {
if (isRefresh) {//是否刷新
mCategoryView.setCategoryItems(androidResult);
mCategoryView.hideSwipeLoading();
mCategoryView.setLoading();
} else {
mCategoryView.addCategoryItems(androidResult); //添加数据
}
}
});
mSubscriptions.add(subscription);//添加订阅
}
}
可以看出,网络数据获取发生在Presenter层,然后通过拿到View层的一个引用去操作UI展示,每一个业务或者Ui的更改,都会对应一个接口定义的一个抽象方法,然后通过实现的方式去实现业务逻辑。
FloatingActionButton 完全解析
Material Design之CoordinatorLayout+AppBarLayout实现上滑隐藏ToolBar