Android Okhttp3+Retrofit2网络加载效率优化

本文主要介绍了如何在一个老项目中替换将旧的Http框架替换成OkHttp3或Retrofit2。并介绍了使用OkHttp3和Retrofit2发送GET和POST请求的代码示例。介绍了Retrofit2配合RxJava请求网络的方法,介绍了线程池的调度方法,提升网络加载效率和用户体验。并且通过抓包分析了OkHttp3的TCP连接保活效果,分析OkHttp的网络请求的优点。最后介绍了我在项目中如何停止没有意义的网络请求,节省带宽流量和内存的思路。
摘要由CSDN通过智能技术生成

一、开发背景:

我目前在做的是一个3年左右的老项目,项目开始的时候okhttp还不像现在这么火,基本上使用HttpURLConnection类来实现所有的HTTP请求,当时采用的是xUtils框架来实现异步的,回调式的接口请求。现在发现xUtils这套框架存在几个很大的问题。

老框架的性能问题:

1、xUtils的图片加载任务会阻塞Http请求,因为xUtils中的图片加载框架BitmapUtils和网络请求框架HttpUtils的线程池是共用的,这个线程池的大小默认为3,也就是说当我在下载图片的时候会阻塞Http请求数据接口的任务。这样会带来一个严重后果,当一个页面图片很多的时候,我打开一个新的页面,新的页面需要下载相应的json字符串来显示,但是由于线程池里满满的都是图片下载任务,所以用户必须等所有图片都下载完毕之后才能调json的接口,本来很快就可以显示的页面现在却要等无意义的图片的下载,大大降低了用户体验。

2、xUtils框架连接握手太频繁,根据抓包结果来看,xUtils在完成一次Http请求之后,会主动发送挥手的FIN报文,将TCP连接关闭。这样的话如果短期内频繁请求同一个服务器多次,那么每次都要重新进行三次握手的步骤,浪费了许多时间,根据抓包结果来看,大约每次连接会浪费300ms左右的时间。抓包截图如下


可以看出倒数第3行是由Android客户端主动向服务器发送FIN报文,而且发送的时间是紧接着接口数据传输完毕后的。也就是说几乎没有进行连接保活,这样如果短时间请求同一个接口多次的话,每次调用都会执行一次握手,大量的握手会消耗大量的时间,不适合目前APP会大量调用接口的情况。

3、Android 6.0发布之后,谷歌已经将所有旧版的HttpURLConnection,HttpClient,和一些和apache有关包的类和方法定义为过时方法,并且Android SDK 23之后不再内置旧版的类和接口,需要额外引用jar包,为了代码的健壮性也需要抛弃旧版Android的HTTP框架。

OkHttp3.0的引入和配置:

在我的编程经验里来看,优秀的开源框架引入起来总不会是一帆风顺的,OkHttp也是如此,这里讲讲引入过程中的几个大坑

首先在gradle里添加引用(Eclipse可以下载连个jar包直接导入项目okhttp-3.3.1.jar,okio-1.8.0.jar):

compile 'com.squareup.okhttp3:okhttp:3.2.0'
导入完打一个带签名的包马上就会出问题

注意上面这些gradle编译的报错指示note,并不影响编译进程,也不会影响打出来的apk包。这些note是progard在混淆的时候发现有重复的类报出来的,虽然不影响使用但是这里还是要分析一下,去掉重复的类。报错的矛头指向旧版的旧版的HttpURLConnection和HttpClient的类,说它们重复了,重复的包主要是org.apache.commons.codec包。

于是我在项目里搜索该包的引用,首先发现,我现在的编译版本是23,但是23已经没有这些类了,于是我添加了apache旧框架的支持jar包,在build.gradle里是这样配置的:

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"
    defaultConfig {
        applicationId "com.xxx.app"
        minSdkVersion 15
        targetSdkVersion 17
        versionCode 1
        versionName '1.0.0.0'
        multiDexEnabled true
    }
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
    }
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
    packagingOptions {
        exclude 'META-INF/LICENSE.txt'
    }
    useLibrary 'org.apache.http.legacy'
    ...
}
重点是这一句useLibrary 'org.apache.http.legacy'

他会将SDK目录中\platforms\android-23\optional\org.apache.http.legacy.jar这个jar包自动添加到项目中来,而这个jar包里面就有apache的一些类。

但它又是怎样重复的呢?经过一番搜寻我又发现在xUtils这个第三方库中有一个commons-codec.jar


正是这个jar包和org.apache.http.legacy.jar中的类出现了重复,于是把xUtils第三方库中的

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,我可以帮助你搭建一个基于MVP模式的Android项目框架,其中包含Okhttp+Retrofit网络封装、Base基类的抽取、APPLocation的代码,且能直接使用写项目的那种,并包含包名结构。 首先,我们需要创建一个Android项目,然后按照以下步骤进行框架搭建: 1. 创建包名结构 可以按照以下结构创建包名: - app:存放应用程序的 Activities 和 Application 类 - base:存放 Base 类 - model:存放数据模型相关的类 - presenter:存放 Presenter 类 - view:存放 View 类和相关接口 - utils:存放工具类 - net:存放网络请求相关的类 2. 添加依赖 在 app 模块的 build.gradle 文件中添加以下依赖: ``` dependencies { // Retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // OkHttp implementation 'com.squareup.okhttp3:okhttp:4.9.1' // ButterKnife implementation 'com.jakewharton:butterknife:10.2.3' annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' // Gson implementation 'com.google.code.gson:gson:2.8.7' // RxJava implementation 'io.reactivex.rxjava2:rxjava:2.2.19' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' } ``` 3. 创建 BaseActivity 类 BaseActivity 类是所有 Activity 的基类,它包含一些通用的方法和属性,如 Toast 弹窗、ProgressDialog 等。 ``` public abstract class BaseActivity extends AppCompatActivity { private ProgressDialog mProgressDialog; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId()); ButterKnife.bind(this); initView(); initData(); } protected abstract int getLayoutId(); protected abstract void initView(); protected abstract void initData(); protected void showToast(String message) { Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); } protected void showProgressDialog() { if (mProgressDialog == null) { mProgressDialog = new ProgressDialog(this); mProgressDialog.setMessage("加载中..."); mProgressDialog.setCancelable(false); } if (!mProgressDialog.isShowing()) { mProgressDialog.show(); } } protected void hideProgressDialog() { if (mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.dismiss(); } } } ``` 4. 创建 BasePresenter 类 BasePresenter 类是所有 Presenter 的基类,它包含一些通用的方法和属性,如 attachView()、detachView() 等。 ``` public abstract class BasePresenter<V extends BaseView> { private V mView; public void attachView(V view) { mView = view; } public void detachView() { mView = null; } protected V getView() { return mView; } protected boolean isViewAttached() { return mView != null; } } ``` 5. 创建 BaseView 接口 BaseView 接口是所有 View 的基类接口,它包含一些通用的方法和属性,如 showLoading()、hideLoading() 等。 ``` public interface BaseView { void showLoading(); void hideLoading(); void showError(String errorMsg); } ``` 6. 创建 AppApplication 类 AppApplication 类是整个应用程序的入口点,它继承自 Application 类。在该类中可以初始化一些全局的变量、配置等。 ``` public class AppApplication extends Application { private static AppApplication sInstance; @Override public void onCreate() { super.onCreate(); sInstance = this; } public static AppApplication getInstance() { return sInstance; } } ``` 7. 创建 RetrofitUtils 类 RetrofitUtils 类是用于封装 RetrofitOkHttp网络请求封装类,它包含一些通用的方法和属性,如 create()、get()、post() 等。 ``` public class RetrofitUtils { private static Retrofit sRetrofit; public static Retrofit create(String baseUrl) { if (sRetrofit == null) { synchronized (RetrofitUtils.class) { if (sRetrofit == null) { OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .build(); sRetrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .client(client) .build(); } } } return sRetrofit; } public static <T> void get(String url, Map<String, String> params, final HttpCallback<T> callback) { Retrofit retrofit = create(url); ApiService apiService = retrofit.create(ApiService.class); Call<ResponseBody> call = apiService.get(url, params); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { String result = response.body().string(); T data = new Gson().fromJson(result, callback.getType()); callback.onSuccess(data); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { callback.onFailure(t.getMessage()); } }); } public static <T> void post(String url, Map<String, String> params, final HttpCallback<T> callback) { Retrofit retrofit = create(url); ApiService apiService = retrofit.create(ApiService.class); Call<ResponseBody> call = apiService.post(url, params); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { String result = response.body().string(); T data = new Gson().fromJson(result, callback.getType()); callback.onSuccess(data); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { callback.onFailure(t.getMessage()); } }); } } ``` 8. 创建 ApiService 接口 ApiService 接口是 Retrofit 的请求接口,它定义了所有的网络请求方法。 ``` public interface ApiService { @GET Call<ResponseBody> get(@Url String url, @QueryMap Map<String, String> params); @FormUrlEncoded @POST Call<ResponseBody> post(@Url String url, @FieldMap Map<String, String> params); } ``` 9. 创建 HttpCallback 类 HttpCallback 类是网络请求回调接口,它定义了 onSuccess() 和 onFailure() 方法。 ``` public interface HttpCallback<T> { Type getType(); void onSuccess(T data); void onFailure(String errorMsg); } ``` 至此,一个基于 MVP 模式的 Android 项目框架就搭建完成了,你可以在此基础上进行后续的开发工作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值