Android主流框架RxJava+Retrofit+MVP

简介

最近公司新创立一个项目,准备开始前期工作,搭建框架,正在想着要怎么搭建更好的框架,以便轻松应付后续需求。想着最近比较流行的RxJava+Retrofit+MVP框架,自己也准备写一个通用的前端项目框架,撸起袖子准备开干。

备注:该项目会一直维护在github上,去往github看

RxJava

RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,概括得非常精准。当然这是比较官网的解释,也是一头雾水,以我的理解,其实就是观察者模式,观察者与被观察者,类似Android里面的button点击事件。用来实现异步操作,Android里面有很多方法实现异步操作,RxJava的优势就是很简洁,代码看着很舒服,像我们这种有代码洁癖的人来说简直就是福音,更重要的是随着项目的开展,产品的需求迭代,依然能保持简洁。当然网上有很多RxJava的博文,一些大神讲解的也是非常的细,比我讲的那是好多了,我就不一一说了,推荐几篇文章。 

RxJava:http://gank.io/post/560e15be2dca930e00da1083#toc_1。

Retrofit

retrofit是一款针对Android网络请求的开源框架,它与okhttp一样出自Square公司。Rotrofit2.0的网络框架全部交给了okhttp来实现,Android N之后Apache的httpclient已经被Google从SDK中移除,Okhttp则成功上位。Retrofit的网络请求实现风格与URLconnection和httpClient有较大的差别。创建请求的时候需要先创建基于注解的服务接口(不了解的可以先了解一下注解),进行网络请求的时候再通过Retrofit.creat()方法来创建请求。以我的理解其实就是对Okhttp进行了一层的封装,而且retrofit可以很好的搭配RxJava使用,所以说retrofit和RxJava更配哦。。

Retrofit:https://blog.csdn.net/carson_ho/article/details/73732076


MVP

MVP模式是MVC模式在Android上的一种变体,要介绍MVP就得先介绍MVC。在MVC模式中,Activity应该是属于View这一层。而实质上,它既承担了View,同时也包含一些Controller的东西在里面。这对于开发与维护来说不太友好,耦合度大高了。把Activity的View和Controller抽离出来就变成了View和Presenter,这就是MVP模式。以我的理解其实MVP模式跟MVC差不多,MVP分离的更细,有利于扩展,特别是项目需求不停的更改时,就能理解到MVP是多么的好用,更重要的代码看上去也非常的简洁。

MVP:https://blog.csdn.net/briblue/article/details/52839242


项目搭建

介绍完一堆理论,最重要的就是撸起袖子写代码,这才是关键,很多人很喜欢看技术博文,但是自己很少动手自己写,很快就会遗忘,很多问题只有自己去动手写才能发现。话不多说,开撸。

引入我们需要的JAR包

在gradle引入jar包

  //Retrofit
    compile 'com.squareup.retrofit2:retrofit:2.4.0'
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
    compile 'com.squareup.retrofit2:converter-gson:2.4.0'
    //RxJava
    compile 'io.reactivex.rxjava2:rxjava:2.1.12'
    //Rxlife用于管理RxJava的订阅和解除
    compile 'com.trello.rxlifecycle2:rxlifecycle:2.2.1'
    compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.1'
    //RxAndroid
    compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
public interface ApiService {

    /**
     * 广告banner
     * @return
     */
    @GET("/ace-app/bannerInfo/{id}")
    Observable<BaseResult<List<OtherProductModel>>> getBannerInfo(@Path("id") String id);
    /**
     * 测试数据接口
     * @param q
     * @param tag
     * @param start
     * @param end
     * @return
     */
    @GET("book/search")
    Observable<BookModel> getBooks(@Query("q") String q,
                                   @Query("tag") String tag,
                                   @Query("start") String start,
                                   @Query("end") String end);


}

因为结合RxJava使用,需要返回被观察者Observable<T>对象。

创建Retrofit辅助类,用于网络请求

/**
 * Retrofit 辅助类
 * @author Veer
 * @email 276412667@qq.com
 * @date 18/7/2
 */

public class RetrofitHelper {
    private static String TGA = "RetrofitHelper";
    private  long CONNECT_TIMEOUT = 60L;
    private  long READ_TIMEOUT = 30L;
    private  long WRITE_TIMEOUT = 30L;
    private static RetrofitHelper mInstance = null;
    private Retrofit mRetrofit = null;

    public static RetrofitHelper getInstance(){
        synchronized (RetrofitHelper.class){
            if (mInstance == null){
                mInstance = new RetrofitHelper();
            }
        }
        return mInstance;
    }
    private RetrofitHelper(){
        init();
    }
    private void init() {
        resetApp();
    }

    private void resetApp() {
        mRetrofit = new Retrofit.Builder()
                .baseUrl(Contacts.DEV_BASE_URL)
                .client(getOkHttpClient())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }
    /**
     * 获取OkHttpClient实例
     *
     * @return
     */

    private  OkHttpClient getOkHttpClient() {
        OkHttpClient   okHttpClient = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
                .addInterceptor(new RqInterceptor())
                .addInterceptor(new LogInterceptor())
                .build();
        return okHttpClient;
    }

    /**
     * 请求拦截器
     */
    private  class RqInterceptor implements Interceptor {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            Request request  =  chain.request()
                    .newBuilder()
                    .addHeader("X-APP-TYPE","android")
                    .build();
            Response response = chain.proceed(request);
            return response;
        }
    }
    /**
     * 日志拦截器
     */
    private class LogInterceptor implements Interceptor {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            Request request  =  chain.request();
            String url = request.url().toString();
            String params = requestBodyToString(request.body());
            Response response = chain.proceed(request);
            String responseString = JsonHandleUtils.jsonHandle(response.body().string());
            String time = DateUtils.getNowDateFormat(DateUtils.DATE_FORMAT_2);
            String log = "\n\n*****请求时间*****:\n" + time+"\n*******路径*******:\n" + url + "\n*******参数*******:\n" + params +  "\n*******报文*******:\n"  + responseString+"\n \n";
            Log.d(TGA,log);
            return chain.proceed(request);
        }
    }

    private  String requestBodyToString(final RequestBody request) {
        try {
            final RequestBody copy = request;
            final Buffer buffer = new Buffer();
            if (copy != null){

                copy.writeTo(buffer);
            }
            else{
                return "";
            }
            return buffer.readUtf8();
        } catch (final IOException e) {
            return "did not work";
        }
    }

    public ApiService getServer(){
        return mRetrofit.create(ApiService.class);
    }
}

这里面代码比较多,了解Okhttp的同学应该看得懂,Retrofit也是基于Okhttp的,我使用了单例进行了一层的处理,方便的我们的接口请求,这里比较重要的是拦截器,我们在配置Okhttp的时候可以配置一些拦截器,做一些请求头和日志等处理。看不懂的同学也不用担心,我会把项目源码贴出来,GitHub上也会一直维护。

配置完了Retrofit,现在最重要的就是搭建MVP,搭建MVP前期工作一定要做好,方便我们后续的扩展,前期可能会写很多接口,如果想后续不被产品的需求磨得脑壳疼的话,这些都是免不了的。

/**
 * 基础配置约定
 * @author Veer
 * @email 276412667@qq.com
 * @date 18/7/2
 */

public interface BaseContract {
    interface BasePresenter<T extends BaseView>{
        /**
         * view挂载
         *
         * @param view
         */
        void attachView(T view);

        /**
         * View卸载
         */
        void detachView();
    }
    interface BaseView{

        /**
         * 显示进度中
         */
        void showLoading();

        /**
         * 隐藏进度
         */
        void hideLoading();

        /**
         * 显示请求成功
         *
         * @param message
         */
        void showSuccess(String message);

        /**
         * 失败重试
         *
         * @param message
         */
        void showFailed(String message);

        /**
         * 显示当前网络不可用
         */
        void showNoNet();

        /**
         * 重试
         */
        void onRetry();

        /**
         * 绑定生命周期
         *
         * @param <T>
         * @return
         */
        <T> LifecycleTransformer<T> bindToLife();
    }
}
/**
 * 书本配置约定
 * @author Veer
 * @email 276412667@qq.com
 * @date 18/7/2
 */

public interface BookContract {
    interface View extends BaseContract.BaseView{
        void setBook(BookModel model);

    }
    interface Presenter extends BaseContract.BasePresenter<View>{
        void getBook(FrameLayout4Loading frameLayout4Loading,String p, String tag, String start, String end);
    }
}


这里包括了P V,P用来处理业务逻辑,V更新视图。activity中的代码就少了很多了

/**
 * 描述
 *
 * @author Veer
 * @email 276412667@qq.com
 * @date 18/7/2
 */
@Route(path= ActivityContracts.ACTIVITY_BOOK)
public class BookActivity extends BaseActivity<BookPresenter> implements BookContract.View{
    @BindView(R.id.tv_book)
    TextView mTvBook;
    @BindView(R.id.loading)
    FrameLayout4Loading mFrameLayout4Loading;

    @Override
    public void setBook(BookModel model) {
        mTvBook.setText(model.getBooks().toString());
    }

    @Override
    protected void initView() {
        mFrameLayout4Loading.setRefreashClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPresenter.getBook(mFrameLayout4Loading,"三国演义","","0","1");
            }
        });
        mPresenter.getBook(mFrameLayout4Loading,"三国演义","","0","1");
    }

    @Override
    protected  BookPresenter initPresenter() {
        return new BookPresenter();
    }

    @Override
    protected int getActivityLayoutID() {
        return R.layout.activity_book;
    }
}

业务逻辑都在P中处理

public class BookPresenter extends BasePresenter<BookContract.View> implements BookContract.Presenter{

    @Override
    public void getBook(final FrameLayout4Loading frameLayout4Loading, String p, String tag, String start, String end) {
//       mView.showLoading();
        frameLayout4Loading.showLoadingView();
        RetrofitHelper.getInstance().getServer()
                .getBooks(p,tag,start,end)
                .compose(RxSchedulers.<BookModel>applySchedulers())
                .compose(mView.<BookModel>bindToLife())
                .subscribe(new Consumer<BookModel>() {
                    @Override
                    public void accept(BookModel bookModel) throws Exception {
//                        mView.hideLoading();
                        frameLayout4Loading.hideLoadingView();
                        mView.setBook(bookModel);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
//                       mView.hideLoading();
                        frameLayout4Loading.hideLoadingView();
                        frameLayout4Loading.showDefaultExceptionView();
                    }
                });
    }
}

因为在大部分项目中都要网络请求,都需要加载框,统一封装了一个控件,用于加载框显示。

大部分加载框都有用到动画,可以使用Lottie  非常好用的一个开源动画,适用于android ios  h5。可参考 Lottie的使用

我就贴一些主要代码:

/***
 * 加载页面
 * @author Veer
 * @email  276412667@qq.com
 * @date   18/7/3
 */
public class FrameLayout4Loading extends FrameLayout {

	/*** 没有数据显示 */
	public static final int ViewType_EmptyView = -1;
	/*** 请求中 */
	public static final int ViewType_Loading = 0;
	/*** 加载异常, 在无合适的异常类型使用的情况下使用此异常 */
	public static final int ViewType_DefaultException = 1;
	/*** 无网络 */
	public static final int ViewType_NoNetwork = 4;
	/*** 网络超时 */
	public static final int ViewType_Timeout = 5;
	/*** 数据异常, 服务器返回数据有误(比如反序列化失败) */
	public static final int ViewType_ServerException = 3;

	/** 其他错误 */
	public static final int EXP_DEFAULT_FAIL = 10001;
	/** 无法连接到网络,请检查网络配置 */
	public static final int EXP_NETWORK_NOTAVAILABLE = 90001;
	/** 超时了,请您重试 */
	public static final int EXP_REQUEST_TIMEOUT = 90003;
	/** 服务出错啦,请稍后重试 */
	public static final int EXP_SERVICE_FAIL = 90004;
	/** 服务调用出错,但不带重试按钮只显示信息 */
	public static final int EXP_SERVICE_FAIL_INFO = 150101;

	private static Animation loadingAnim;

	private SparseArray<Integer> defaultLayout = new SparseArray<Integer>(7);
	public SparseArray<View> cachedLayout = new SparseArray<View>(7);

	private LayoutInflater mInflater;

	private OnClickListener mRefreshClickListener;



	private ImageView icon;
	private TextView tip;
	private TextView subTip;
	private boolean viewUp = false;

	private LottieAnimationView mLottieAnimationView;

	private Context mContext;

	public boolean isViewUp() {
		return viewUp;
	}

	public void setViewUp(boolean viewUp) {
		this.viewUp = viewUp;
	}


	public FrameLayout4Loading(Context context) {
		super(context);
		init(context, null);
	}

	public FrameLayout4Loading(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);

	}

	public FrameLayout4Loading(Context context, AttributeSet attrs,
							   int defStyle) {
		super(context, attrs, defStyle);
		init(context, attrs);
	}

	private void init(Context context, AttributeSet attrs) {

		this.mContext = context;

		if (isInEditMode())
			return;

		if (loadingAnim==null){
			loadingAnim = AnimationUtils.loadAnimation(context, R.anim.round_loading);
		}

		mInflater = (LayoutInflater) getContext().getSystemService(
				Context.LAYOUT_INFLATER_SERVICE);

		if (attrs != null) {
			TypedArray a = context.obtainStyledAttributes(attrs,
					R.styleable.FrameLayout4Loading);
			if (a != null) {
				setDefaultView(ViewType_Loading, a.getResourceId(
						R.styleable.FrameLayout4Loading_loadingView,
						R.layout.common_loading_indicator));

				setDefaultView(ViewType_NoNetwork, a.getResourceId(
						R.styleable.FrameLayout4Loading_loadingView,
						R.layout.common_error_default_style));

				setDefaultView(ViewType_Timeout, a.getResourceId(
						R.styleable.FrameLayout4Loading_loadingView,
						R.layout.common_error_default_style));

				setDefaultView(ViewType_DefaultException, a.getResourceId(
						R.styleable.FrameLayout4Loading_loadingView,
						R.layout.common_error_default_style));

				setDefaultView(ViewType_ServerException, a.getResourceId(
						R.styleable.FrameLayout4Loading_defaultExceptionView,
						R.layout.common_error_default_style));

				setDefaultView(ViewType_EmptyView,
						R.layout.common_empty_view);

				a.recycle();
			}
		}
	}

	public void setDefaultView(int viewType, int resLayout) {
		defaultLayout.put(viewType, resLayout);
	}

	public int getDefaultViewResId(int viewType) {
		return defaultLayout.get(viewType);
	}

	public void showView(int viewType, Drawable background) {
		int count = defaultLayout.size();
		for (int i = 0; i < count; i++) {
			int key = defaultLayout.keyAt(i);
			if (key == viewType) {
				doShowView(key, background);
			} else {
				hideView(key, background);
			}
		}
	}

	private void hideView(int viewType, Drawable background) {
		View view = cachedLayout.get(viewType);

		if (view == null)
			return;
		if (background != null) {
			view.setBackground(background);
		}
		view.setVisibility(GONE);
	}
	/**
	 * 没有数据时显示
	 * @param background  图片
	 * @param msg  描述文字
	 */
	public void doShowNoData(Drawable background, String msg) {
		doShowNoData(background,msg,null,null);
	}


	/**
	 * 没有数据时显示
	 * @param background  图片
	 * @param msg  描述文字
	 * @param btnTxt  按钮文字
	 * @param click   点击事件
	 */
	public void doShowNoData(Drawable background, String msg, String btnTxt, OnClickListener click) {
		int resLayoutId = defaultLayout.get(ViewType_EmptyView);
		if (resLayoutId <= 0)
			throw new IllegalStateException("layout is not set for " + ViewType_EmptyView);


		View view = cachedLayout.get(ViewType_EmptyView);

		if (view == null || click != null) {
			view = mInflater.inflate(resLayoutId, null);
			try {
				ImageView image = (ImageView)view.findViewById(R.id.empty_icon_iv);

				image.setBackground(background);

				TextView empText = (TextView) view
						.findViewById(R.id.empty_tip_tv);
				empText.setText(msg);

				if (click!=null){
					TextView empty_btn = (TextView) view.findViewById(R.id.empty_btn);
					empty_btn.setVisibility(View.VISIBLE);
					empty_btn.setOnClickListener(click);
					empty_btn.setText(btnTxt);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}

			cachedLayout.put(ViewType_EmptyView, view);
			addView(view, new LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
					Gravity.CENTER));
			initView(view, ViewType_EmptyView);
			initListener(view);
		}

		view.setVisibility(VISIBLE);
		view.bringToFront();
	}



	private void doShowView(int viewType, Drawable background) {
		int resLayoutId = defaultLayout.get(viewType);
		if (resLayoutId <= 0)
			throw new IllegalStateException("layout is not set for " + viewType);

		View view = cachedLayout.get(viewType);

		if (view == null) {
			view = mInflater.inflate(resLayoutId, null);
			try {
				TextView errorText = (TextView) view.findViewById(R.id.loading_error_text);
				if ( viewType == ViewType_Timeout
						|| viewType == ViewType_NoNetwork
						) {
					errorText.setText("亲爱的,您的网络开小差了哦");

				}else if(viewType == ViewType_DefaultException
						||viewType == ViewType_ServerException){
					errorText.setText("系统繁忙,请稍后再试!");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			if (background != null) {
				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
					view.setBackground(background);
				} else {
					view.setBackgroundDrawable(background);
				}
			}
			cachedLayout.put(viewType, view);
			addView(view, new LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
					Gravity.CENTER));
			initView(view, viewType);
			initListener(view);
		}

		view.setVisibility(VISIBLE);
		view.bringToFront();
	}

	private void initView(View v, int viewType) {

		if (ViewType_EmptyView == viewType) {
			icon = (ImageView) v.findViewById(R.id.empty_icon_iv);
			tip = (TextView) v.findViewById(R.id.empty_tip_tv);
			subTip = (TextView) v.findViewById(R.id.empty_sub_tip_tv);
		} else if (ViewType_Loading == viewType) {
			mLottieAnimationView = v.findViewById(R.id.loading_iv);
			//设置加载速度
			mLottieAnimationView.setSpeed(10);
		}
	}

	private void initListener(View view) {
		View refreshBtn = view.findViewById(R.id.loading_refreash_btn);
		if (refreshBtn != null && mRefreshClickListener != null) {
			refreshBtn.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					mRefreshClickListener.onClick(v);
				}
			});
		}
	}

	/**
	 * 显示加载动态图
	 */
	public void showLoadingView() {
		showLoadingView(null);
	}
	/**
	 * 显示加载动态图
	 * @param backgroundId  背景图ID
	 */
	public void showLoadingView(int backgroundId) {
		showLoadingView(getResources().getDrawable(backgroundId));
	}
	/**
	 * 显示加载动态图
	 * @param background  背景图
	 */
	public void showLoadingView(Drawable background) {
		showView(ViewType_Loading, background);
	}
	/**
	 * 隐藏加载动态图
	 */
	public void hideLoadingView() {
		hideLoadingView(null);
	}

	public void hideLoadingView(int backgroundId) {
		hideLoadingView(getResources().getDrawable(backgroundId));
	}

	public void hideLoadingView(Drawable background) {
		hideView(ViewType_Loading, background);
	}


	public void showDefaultExceptionView() {
		showExceptionView(EXP_DEFAULT_FAIL);
	}
	/**
	 * 显示空页面
	 */
	public void showEmptyView() {
		showEmptyView(null);
	}

	public void showEmptyView(int backgroundId) {
		showEmptyView(getResources().getDrawable(backgroundId));
	}

	public void showEmptyView(Drawable background) {
		showView(ViewType_EmptyView, background);
	}

	/**
	 * 显示异常页面
	 * @param errorCode
	 */
	public void showExceptionView(int errorCode) {
		showView(getViewTypeByErrorCode(errorCode), null);
	}

	public void showExceptionView(int errorCode, int backgroundId) {
		showExceptionView(errorCode, getResources().getDrawable(backgroundId));
	}

	public void showExceptionView(int errorCode, Drawable background) {
		showView(getViewTypeByErrorCode(errorCode), background);
	}

	public void setExceptionViewIconVisibility(int visibility) {
		View view = cachedLayout.get(ViewType_DefaultException);
		view.findViewById(R.id.listview_error_pic).setVisibility(visibility);
	}

	public <T> FrameLayout4Loading setEmptyViewIcon(T obj) {
		if (obj == null || icon == null)
			return null;
		if (obj instanceof Integer)
			icon.setImageResource((Integer) obj);
		else
			ViewCompat.setBackground(icon, (Drawable) obj);
		return this;
	}

	public <T> FrameLayout4Loading setEmptyViewTip(T obj) {
		if (obj == null || tip == null)
			return null;
		if (obj instanceof Integer)
			((TextView) tip).setText(getResources().getString((Integer) obj));
		else if (obj instanceof CharSequence)
			((TextView) tip).setText((CharSequence) obj);
		return this;
	}

	public <T> FrameLayout4Loading setEmptyViewTip(T obj, T obj1) {
		if (obj == null || tip == null)
			return null;

		if (obj instanceof Integer)
			((TextView) tip).setText(getResources().getString((Integer) obj));
		else if (obj instanceof CharSequence)
			((TextView) tip).setText((CharSequence) obj);

		if (obj1 == null || subTip == null) {
			return null;
		}

		subTip.setVisibility(View.VISIBLE);
		if (obj1 instanceof Integer)
			((TextView) subTip).setText(getResources()
					.getString((Integer) obj1));
		else if (obj instanceof CharSequence)
			((TextView) subTip).setText((CharSequence) obj1);

		return this;
	}

	public void hideAllMask() {
		hideAllMask(null);
	}

	public void hideAllMask(int backgroundId) {
		hideAllMask(getResources().getDrawable(backgroundId));
	}

	public void hideAllMask(Drawable background) {
		int count = cachedLayout.size();
		for (int i = 0; i < count; i++) {
			int key = cachedLayout.keyAt(i);
			hideView(key, background);
		}
	}

	private static int getViewTypeByErrorCode(int errorCode) {
		switch (errorCode) {
			case EXP_NETWORK_NOTAVAILABLE :
				return ViewType_NoNetwork;

			case EXP_REQUEST_TIMEOUT :
				return ViewType_Timeout;

			case EXP_SERVICE_FAIL :
				return ViewType_ServerException;

			case EXP_DEFAULT_FAIL :
			case EXP_SERVICE_FAIL_INFO :
			default :
				return ViewType_DefaultException;
		}
	}

	public void setRefreashClickListener(OnClickListener listener) {
		mRefreshClickListener = listener;
	}

}

然后项目中海使用了一些比较方便编程的框架:

阿里的ARouter :activity直接跳转的管理。

ButterKnife  :控件注解。

Glide :图片框架。

这个项目框架后续我后一直更新完善:https://github.com/fuweiwei/RxJavaRetrofitMvp


源码下载


  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
对于Android项目中的网络请求,RxJavaRetrofitMVP是常用的框架组合。下面是一个简单的网络框架封装示例: 首先,在项目中引入RxJavaRetrofit的依赖。 ``` implementation 'io.reactivex.rxjava2:rxjava:2.2.19' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' ``` 然后,创建一个Retrofit的单例类,用于进行网络请求的初始化和配置。 ```java public class RetrofitClient { private static Retrofit retrofit; private static final String BASE_URL = "https://api.example.com/"; public static Retrofit getClient() { if (retrofit == null) { retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } return retrofit; } } ``` 接下来,创建一个ApiService接口,定义网络请求的方法。 ```java public interface ApiService { @GET("users") Observable<List<User>> getUsers(); } ``` 然后,创建一个DataManager类,用于管理网络请求。 ```java public class DataManager { private ApiService apiService; public DataManager() { apiService = RetrofitClient.getClient().create(ApiService.class); } public Observable<List<User>> getUsers() { return apiService.getUsers(); } } ``` 最后,在MVP的Presenter中调用DataManager类进行网络请求。 ```java public class UserPresenter { private UserView userView; private DataManager dataManager; public UserPresenter(UserView userView) { this.userView = userView; dataManager = new DataManager(); } public void getUsers() { dataManager.getUsers() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<List<User>>() { @Override public void onSubscribe(Disposable d) { // 在请求开始时的操作 } @Override public void onNext(List<User> users) { // 请求成功返回数据时的操作 userView.showUsers(users); } @Override public void onError(Throwable e) { // 请求失败时的操作 userView.showError(e.getMessage()); } @Override public void onComplete() { // 请求完成时的操作 } }); } } ``` 这样,就完成了一个简单的Android RxJava + Retrofit + MVP网络框架封装。你可以根据自己的需要,进行进一步的封装和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值