在搞清楚这个问题之前,我们回顾一下基本概念
RxJava
: ReactiveX
在JVM
上的一个实现,ReactiveX
使用Observable
序列组合异步和基于事件的程序;掌握了它,你可以优美地处理异步任务和事件的回调
Retrofit
:一个 RESTful
的 HTTP
网络请求框架的封装,网络请求的工作本质上是OkHttp
完成,而 Retrofit
仅负责 网络请求接口的封装:掌握了它,你能优美地进行网络请求。
MVP
:一种解耦模型和视图的模式,是现在很多公司的主流模式。
由此可见,在平时的开发中熟练运用这种模式,不仅可以满足生活中大部分应用程序的场景,还可以为将来的工作积攒宝贵的实战经验。
二.核心用法
本项目基于
Android X
进行构建,完整代码可在我的Github
上下载:带你封装自己的MVP+Retrofit+RxJava2框架
首先,看一下我们项目的基本结构,下面笔者将为大家详细介绍每个类的相关信息
项目基本结构
2.1 基类Base
Base
基类是封装了一些基类,方便后面新建新的Activity
或者Fragment
,减少耦合
2.1.1 BaseActivity
这个类是
Activity
的基类,注意与下面的BaseMvpActivity
区分开
`/**
- Description : BaseActivity 基类活动
- @author XuCanyou666
- @date 2020/2/2
/
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
initPresenter();
initViews();
ButterKnife.bind(this);
}
/* - 抽象方法:实例化Presenter
/
protected abstract void initPresenter();
/* - 抽象方法:初始化控件,一般在BaseActivity中通过ButterKnife来绑定,所以该方法内部一般我们初始化界面相关的操作
- @return 控件
/
protected abstract void initViews();
/* - 抽象方法:得到布局id
- @return 布局id
/
protected abstract int getLayoutId();
/* - 启动Fragment
- @param id id
- @param fragment 碎片
*/
protected void startFragment(int id, Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(id, fragment);
fragmentTransaction.commit();
}
}`
2.1.2 BaseView
一个接口,说明了每一个
View
基本需要的一些操作
`package com.users.xucanyou666.rxjava2_retrofit_mvp.base;
/**
- created by xucanyou666
- on 2020/1/31 18:26
- email:913710642@qq.com
/
public interface BaseView {
/* - 显示进度框
/
void showProgressDialog();
/* - 关闭进度框
/
void hideProgressDialog();
/* - 出错信息的回调
- @param result 错误信息
*/
void onError(String result);
}`
2.1.3 BaseMvpActivity
MVP
活动的基类继承自
BaseActivity
,它是MVP
活动的基类,封装好了Presenter
的相关操作
`package com.users.xucanyou666.rxjava2_retrofit_mvp.base;
/**
- created by xucanyou666 MVP活动的基类,封装好了presenter的相关操作
- on 2019/12/24 20:53
- email:913710642@qq.com
/
public abstract class BaseMvpActivity<V extends BaseView, P extends BasePresenter> extends BaseActivity {
private P presenter;
/* - 初始化presenter
/
@Override
protected void initPresenter() {
presenter = createPresenter();
if (presenter != null) {
presenter.attachView((V) this);
}
}
/* - 创建presenter
- @return Presenter
/
protected abstract P createPresenter();
/* - 得到presenter
- @return presenter
/
protected P getPresenter() {
return presenter;
}
/* - 销毁
*/
@Override
protected void onDestroy() {
super.onDestroy();
if (presenter != null) {
presenter.detachView();
}
}
}`
2.1.4 BaseFragment
Fragment
的基类需要注意的是,这里用了
ButterKnife
框架,对碎片进行了绑定和解绑操作
`/**
- Fragment的基类,封装了一些Fragment的相关操作
- created by xucanyou666
- on 2020/1/31 16:21
- email:913710642@qq.com
/
public abstract class BaseFragment extends Fragment implements BaseView {
protected T mPresenter;
protected Context mContext;
protected Bundle mBundle;
protected Unbinder unbinder;
protected View view;
/* - 恢复数据
- @param outState bundle
/
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (mBundle != null) {
outState.putBundle(“bundle”, mBundle);
}
}
/* - 绑定activity
- @param context context
/
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
mContext = context;
}
/* - 运行在onAttach之后,可以接收别人传递过来的参数,实例化对象
- 可以解决返回的时候页面空白的bug
- @param savedInstanceState
/
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mBundle = savedInstanceState.getBundle(“bundle”);
} else {
mBundle = getArguments() == null ? new Bundle() : getArguments();
}
//初始化presenter
mPresenter = initPresenter();
}
protected T getPresenter() {
return mPresenter;
}
/* - 运行在onCreate之后,生成View视图
- @param inflater
- @param container
- @param savedInstanceState
- @return
/
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = initView(inflater, container, savedInstanceState);
unbinder = ButterKnife.bind(this, view);
return view;
}
/* - 运行在onCreateView之后
- 加载数据
- @param savedInstanceState
/
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mPresenter.attachView(this);
}
/* - 跳转Fragment
- @param toFragment 跳转去的fragment
/
public void startFragment(Fragment toFragment) {
Log.d(TAG, “haha”);
startFragment(toFragment, null);
}
/* - 跳转Fragment
- @param toFragment 跳转到的fragment
- @param tag fragment的标签
/
public void startFragment(Fragment toFragment, String tag) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.hide(this).add(android.R.id.content, toFragment, tag);
fragmentTransaction.addToBackStack(tag);
fragmentTransaction.commitAllowingStateLoss();
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
/* - fragment进行回退
- 类似于activity的OnBackPress
/
public void onBack() {
getFragmentManager().popBackStack();
}
@Override
public void onDetach() {
mPresenter.detachView();
super.onDetach();
}
/* - 初始化Fragment应有的视图
- @return view
/
public abstract View initView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState);
/* - 创建presenter
- @return 必须是BasePresenter的子类
/
public abstract T initPresenter();
/* - 得到context
- @return context
/
@Override
public Context getContext() {
return mContext;
}
/* - 得到bundle
- @return bundle
/
public Bundle getBundle() {
return mBundle;
}
/* - 得到fragment
- @return fragment
*/
public Fragment getFragment() {
return this;
}
}`
2.1.5 BasePresenter
Presenter
的基类,
CompositeDisposable
主要用途是及时取消订阅,以防止内存泄漏,具体CompositeDisposable
的用法可参照Rxjava关于Disposable你应该知道的事
`/**
- created by xucanyou666
- on 2020/1/16 17:12
- email:913710642@qq.com
/
public abstract class BasePresenter {
//将所有正在处理的Subscription都添加到CompositeSubscription中。统一退出的时候注销观察
private CompositeDisposable mCompositeDisposable;
private V baseView;
/* - 和View绑定
- @param baseView
/
public void attachView(V baseView) {
this.baseView = baseView;
}
/* - 解绑View,该方法在BaseMvpActivity类中被调用
/
public void detachView() {
baseView = null;
// 在界面退出等需要解绑观察者的情况下调用此方法统一解绑,防止Rx造成的内存泄漏
if (mCompositeDisposable != null) {
mCompositeDisposable.dispose();
}
}
/* - 获取View
- @return view
/
public V getMvpView() {
return baseView;
}
/* - 将Disposable添加,在每次网络访问之前初始化时进行添加操作
- @param subscription subscription
*/
public void addDisposable(Disposable subscription) {
//csb 如果解绑了的话添加 sb 需要新的实例否则绑定时无效的
if (mCompositeDisposable == null || mCompositeDisposable.isDisposed()) {
mCompositeDisposable = new CompositeDisposable();
}
mCompositeDisposable.add(subscription);
}
}`
2.1.6 MyApplication
- 封装了一个可以全局获取
Context
的方法,参考写法自:《第一行代码–第二版》- 注意:记得在
AndroidManifest
中注册Application
`package com.users.xucanyou666.rxjava2_retrofit_mvp.base;
import android.app.Application;
import android.content.Context;
/**
- 基类
- created by xucanyou666
- on 2019/11/2 14:46
- email:913710642@qq.com
- @author xucanyou666
*/
public class MyApplication extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getContext() {
return context;
}
}`
2.2 工具类 Util
2.2.1 RetrofitManager
Retrofit
单例工具类
`/**
- Retrofit单例工具类
- created by xucanyou666
- on 2020/1/16 16:38
- email:913710642@qq.com
/
public class RetrofitManager {
private Retrofit mRetrofit;
//构造器私有,这个工具类只有一个实例
private RetrofitManager() {
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.connectTimeout(15, TimeUnit.SECONDS);
mRetrofit = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
}
/* - 静态内部类单例模式
- @return
/
public static RetrofitManager getInstance() {
return Inner.retrofitManager;
}
private static class Inner {
private static final RetrofitManager retrofitManager = new RetrofitManager();
}
/* - 利用泛型传入接口class返回接口实例
- @param ser 类
- @param 类的类型
- @return Observable
*/
public T createRs(Class ser) {
return mRetrofit.create(ser);
}
}`
2.2.2 RxJavaUtil
RxJava
的工具类,执行线程调度工作
`/**
- created by xucanyou666
- on 2019/11/17 19:20
- email:913710642@qq.com
- @author xucanyou666
/
public class RxJavaUtil {
/* - 线程调度工作
- @param observable 被观察者
- @param 类型
*/
public static Observable toSubscribe(Observable observable) {
return observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}`
2.3 常量类 Contant
常量池,特别感谢
api open
网提供的免费API
`/**
- created by xucanyou666
- on 2019/11/17 19:01
- email:913710642@qq.com
*/
public class StaticQuality {
public static final String BASE_URL=“https://api.gushi.ci/”;
}`
2.4 接口管理器 Contract
这里集中了一些
Model
层,Presenter
层,View
层的与诗歌相关的接口
`/**
- 诗歌的接口管理器
- created by xucanyou666
- on 2020/2/2 15:33
- email:913710642@qq.com
/
public interface IPoetryContract {
interface IPoetryModel {
/* - 得到诗歌
- @return 诗歌
/
Observable getPoetry();
}
interface IPoetryPresenter {
void getPoetry();
}
interface IPoetryView extends BaseView {
/* - @param author 作者
*/
void searchSuccess(String author);
}
}`
2.5 实体类 Entity
`/**
- 诗歌的实体类
- created by xucanyou666
- on 2020/1/23 21:23
- email:913710642@qq.com
- API返回示例:
- {
- “content”: “胡瓶落膊紫薄汗,碎叶城西秋月团。”,
- “origin”: “从军行七首”,
- “author”: “王昌龄”,
- “category”: “古诗文-天气-月亮”
- }
*/
public class PoetryEntity {
private String content; //诗歌内容
private String origin; //来源
private String author; //作者
private String category; //分类
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
}`
2.6 Retrofit
接口 iApiService
`/**
- retrofit接口
- created by xucanyou666
- on 2020/1/23 21:25
- email:913710642@qq.com
/
public interface GetPoetryEntity {
/* - 获取古诗词
- @return 古诗词
*/
@GET(“all.json”)
Observable getPoetry();
}`
2.7 视图层 View
这里为了减少代码量,方便读者们掌握核心操作,故
View
层都是用的同一个Presenter
和Model
,仅作学习参考
2.7.1 MainActivity
需要注意的是,这里
BaseMvpActivity<activity, presenter>
中Activity
填入的是当前的Activity
,Presenter
填入的是对应的Presenter
`/**
- Description : MainActivity
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
上面分享的百度、腾讯、网易、字节跳动、阿里等公司2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。
【Android思维脑图(技能树)】
知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。
【Android高级架构视频学习资源】
**Android部分精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
上面分享的百度、腾讯、网易、字节跳动、阿里等公司2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。
【Android思维脑图(技能树)】
知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。
[外链图片转存中…(img-9TYkLSzU-1712406228077)]
【Android高级架构视频学习资源】
**Android部分精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!