retrofit怎么本地缓存数据

retrofit怎么本地缓存数据,第1张

首先是抽象的基类

public abstract class BaseApi {

public static final String API_SERVER = "服务器地址"

private static final OkHttpClient mOkHttpClient = new OkHttpClient()

private static Retrofit mRetrofit

protected static Retrofit getRetrofit() {

if (Retrofit == null) {

Context context = Application.getInstance().getApplicationContext()

//设定30秒超时

mOkHttpClient.setConnectTimeout(30, TimeUnit.SECONDS)

//设置拦截器,以用于自定义Cookies的设置

mOkHttpClient.networkInterceptors()

.add(new CookiesInterceptor(context))

//设置缓存目录

File cacheDirectory = new File(context.getCacheDir()

.getAbsolutePath(), "HttpCache")

Cache cache = new Cache(cacheDirectory, 20 * 1024 * 1024)

mOkHttpClient.setCache(cache)

//构建Retrofit

mRetrofit = new Retrofit.Builder()

//配置服务器路径

.baseUrl(API_SERVER + "/")

//设置日期解析格式,这样可以直接解析Date类型

.setDateFormat("-MM-dd HH:mm:ss")

//配置转化库,默认是Gson

.addConverterFactory(ResponseConverterFactory.create())

//配置回调库,采用RxJava

.addCallAdapterFactory(RxJavaCallAdapterFactory.create())

//设置OKHttpClient为网络客户端

.client(mOkHttpClient)

.build()

}

return mRetrofit

}

}1234567891011121314151617181920212223242526272829303132333435

然后是Cookies拦截器

public class CookiesInterceptor implements Interceptor{

private Context context

public CookiesInterceptor(Context context) {

this.context = context

}

//重写拦截方法,处理自定义的Cookies信息

@Override

public Response intercept(Chain chain) throws IOException {

Request request = chain.request()

Request compressedRequest = request.newBuilder()

.header("cookie", CookieUtil.getCookies(context))

.build()

Response response = chain.proceed(compressedRequest)

CookieUtil.saveCookies(response.headers(), context)

return response

}

}123456789101112131415161718

CookieUtil则是一些自定义解析和生成方法以及SharedPreferences的存取,代码略

然后是Api类

public class UserApi extends BaseApi{

//定义接口

private interface UserService {

//GET注解不可用@FormUrlEncoded,要用@Query注解引入请求参数

@GET("user/user_queryProfile")

Observable<UserProfileResp>queryProfile(@Query("userId") int userId)

//POST方法没有缓存,适用于更新数据

@FormUrlEncoded

@POST("user/user_updateUserName")

Observable<BaseResp>updateUserName(@Field("userName") String userName)

}

protected static final UserService service = getRetrofit().create(UserService.class)

//查询用户信息接口

public static Observable<UserProfileResp>queryProfile(int userId){

return service.queryProfile(userId)

}

//更新用户名接口

public static Observable<BaseResp>updateUserName(String userName){

return service.updateUserName(userName)

}

}123456789101112131415161718192021222324

再就是将Retrofit的响应消息经过Gson解析成期望的数据结构,称之为Model类

上文的BaseResp和UserProfileResp则是自定义的Model

假定服务器约定返回的Json格式为

{

"result":"结果代号,0表示成功",

"msg":"异常信息,仅在失败时返回数据",

"userInfo":

{

"id":"用户id",

"userName":"用户名名字"

}

}123456789

那么UserProfileResp可以写成

public class UserProfileResp {

//@SerializedName是指定Json格式中的Key名

//可以不写,则默认采用与变量名一样的Key名

@SerializedName("userInfo")

private UserProfileModel userInfo

public UserProfileModel getUserInfo() {

return userInfo

}

}12345678910

UserProfileModel则是具体的数据结构

public class UserProfileModel {

private int userId

private String userName

public String getUserName(){

return userName

}

}12345678

需要注意的是,如果没有使用@SerializedName指定Key名,当工程被混淆时,变量名会被混淆得与期望的Key名不符。因此需要将这类Model类统一放到一个工程目录,再在proguard-project文件中加入排除项

//不混淆Model类

-keep class com.xxx.model.xxx.** { *}12

最后是实际调用

public void getProfile(int userId){

UserApi.queryProfile(userId)

.subscribeOn(Schedulers.io())

.subscribe(new Subscriber<UserProfileResp>(){

@Override

public void onCompleted() {

}

@Override

public void onError(Throwable e) {

}

@Override

public void onNext(UserProfileResp userProfileResp) {

}

})

}

OkHttp是一个在开发可汗学院AndroidAPP过程中非常重要的依赖库。它的默认的配置为我们提供了非常重要实用功能,下面一些步骤我们可以让Okhttp提供功能使用灵活和内省能力。1.启用文件系统上的响应缓存默认情况下,Okhttp不支持响应缓存,包括HTTPCache-Control头允许缓存响应。因此,客户端通过一次又一次的请求相同的资源浪费时间和带宽。而不是简单地读取初始响应后缓存的副本。要在文件系统中启用响应缓存,需要配置com.squareup.okhttp.Cache实例,并把它传递给你的OkHttpClient实例的setCache方法。你必须初始化缓存与存放目录的文件,并以字节为单位的最大值。响应返回数据可以写入给定目录文件,如果一个响应的缓存超过了给定的大小。我们可以采取LRUpolicy。我们可以在stackoverflow查看JesseWilson的回复。我们可以通过context.getCacheDir()在子目录中缓存我们的响应://Basedirectoryrecommendedby/q/4441849/400717.final@NullableFilebaseDir=context.getCacheDir()if(baseDir!=null){finalFilecacheDir=newFile(baseDir,"HttpResponseCache")okHttpClient.setCache(newCache(cacheDir,HTTP_RESPONSE_DISK_CACHE_MAX_SIZE))}//Basedirectoryrecommendedby/q/4441849/400717.final@NullableFilebaseDir=context.getCacheDir()if(baseDir!=null){finalFilecacheDir=newFile(baseDir,"HttpResponseCache")okHttpClient.setCache(newCache(cacheDir,HTTP_RESPONSE_DISK_CACHE_MAX_SIZE))}在可汗学院的程序中我们指定HTTP_RESPONSE_DISK_CACHE_MAX_SIZEas10*1024*1024,or10MB的大小2.集成StethoStetho是Facebook的一个可爱的库,可以使用Chrome浏览器的Chrome开发人员工具功能来检查你的Android应用程序。Stetho除了允许你检查你的应用程序的SQLite数据库,还可以查看View的层次结构。允许你检查由OkHttp发起的每个请求和响应:这种自省机制是确保服务器返回允许资源缓存的HTTP头是非常有用的,以及验证没有请求时,保证缓存的资源存在。要想使用Stetho,只需添加一个StethoInterceptor实例的网络拦截器列表:okHttpClient.networkInterceptors().add(newStethoInterceptor())okHttpClient.networkInterceptors().add(newStethoInterceptor())然后,运行应用程序,打开浏览器后,输入chrome://inspect。然后你就会看到应用程序的设备和标识符的列表。然后鼠标右键选择inspect打开开发者工具,然后打开新的tab,开始监控OkHttp请求。3.使用Picasso和Retrofit你可能使用过Picasso来加载网络图片,或者使用Retrofit来简化发出请求和解码响应。这些第三方库将隐式地创建自己的OkHttpClient供内部使用,如果你不明确指定一个。Picassoversion2.5.2的OkHttpDownloader类:privatestaticOkHttpClientdefaultOkHttpClient(){OkHttpClientclient=newOkHttpClient()client.setConnectTimeout(Utils.DEFAULT_CONNECT_TIMEOUT_MILLIS,TimeUnit.MILLISECONDS)client.setReadTimeout(Utils.DEFAULT_READ_TIMEOUT_MILLIS,TimeUnit.MILLISECONDS)client.setWriteTimeout(Utils.DEFAULT_WRITE_TIMEOUT_MILLIS,TimeUnit.MILLISECONDS)returnclient}privatestaticOkHttpClientdefaultOkHttpClient(){OkHttpClientclient=newOkHttpClient()client.setConnectTimeout(Utils.DEFAULT_CONNECT_TIMEOUT_MILLIS,TimeUnit.MILLISECONDS)client.setReadTimeout(Utils.DEFAULT_READ_TIMEOUT_MILLIS,TimeUnit.MILLISECONDS)client.setWriteTimeout(Utils.DEFAULT_WRITE_TIMEOUT_MILLIS,TimeUnit.MILLISECONDS)returnclient}Retrofit也有类似的工厂方法来创建自己的OkHttpClient。图片一般在应用程序中需要加载的比较大的资源。尽管Picasso自己维护它的LRU机制来缓存图片,在内存中严格执行。如果客户端尝试使用Picasso来加载图片。Picasso会找不到其在内存中缓存图像,然后将委托加载该图片到它的内部OkHttpClient实例。并且默认情况下该实例将始终从服务器加载图片资源。作为defaultOkHttpClient的方法不能与上面提到的文件系统中的响应缓存配置结合起来。指定你自己的OkHttpClient实例允许返回数据从文件系统缓存响应,图片不会从服务器加载。这是非常重要的在程序第一次启动以后。这个时候Picasso的内存缓存是冷的。所以它会频繁的委托OkHttpClient实例去加载图片。这就需要构建配置了您Picasso的OkHttpClient实例,如果你在你的代码中使用Picasso.with(context).load()Picasso.with(context).load()加载图片,你是用的是Picasso的单例模式。这是通过with方法懒汉模式地实例化并配置自己的OkHttpClient。因此,我们必须使我们自己的Picasso实例在单例之前通过wiht方法调用。实现这个,可以简单的将OkHttpClient实例封装在OkHttpDownloader中,然后传递给Picasso.Builder实例的downloader方法。finalPicassopicasso=newPicasso.Builder(context).downloader(newOkHttpDownloader(okHttpClient)).build()//Theclientshouldinjectthisinstancewheneveritisneeded,butreplacethesingleton//instancejustincase.Picasso.setSingletonInstance(picasso)finalPicassopicasso=newPicasso.Builder(context).downloader(newOkHttpDownloader(okHttpClient)).build()//Theclientshouldinjectthisinstancewheneveritisneeded,butreplacethesingleton//instancejustincase.Picasso.setSingletonInstance(picasso)在Retrofit中要使用OkHttpClient实例,需要改造1.9.x的一个RestAdapter,需要将OkHttpClient封装OkClient的实例中。然后把它传递给RestAdapter.Builder实例的setClient方法。restAdapterBuilder.setClient(newOkClient(httpClient))restAdapterBuilder.setClient(newOkClient(httpClient))在Retrofit2.0中只需要简单的将OkHttpClient传递给Retrofit.Builder实例的client方法。在可汗学院的APP中我们通过Dagger依赖注入来确保我们只有一个OkHttpClient的实例。这种方法同样也适用于Picasso和Retrofit我们提供了一个为OkHttpClient实例提供单例模式的注解示例:@Provides@SingletonpublicOkHttpClientokHttpClient(finalContextcontext,){finalOkHttpClientokHttpClient=newOkHttpClient()configureClient(okHttpClient,)returnokHttpClient}@Provides@SingletonpublicOkHttpClientokHttpClient(finalContextcontext,){finalOkHttpClientokHttpClient=newOkHttpClient()configureClient(okHttpClient,)returnokHttpClient}OkHttpClient将会通过Dagger的注解创建一个实例提供给我们的Picasso和Retrofit。4.指定一个用户代理拦截器日志文件和分析为我们提供了有用的信息,当客户在每个请求提供详细的User-Agentheader值的时候。默认情况下,Okhttp包含User-Agent值只有在特定的Okhttp版本中。为了指定我们自己的useragent。首先创建拦截器的替换值,我们可以看stackoverflow的建议。publicfinalclassUserAgentInterceptorimplementsInterceptor{privatestaticfinalStringUSER_AGENT_HEADER_NAME="User-Agent"privatefinalStringuserAgentHeaderValuepublicUserAgentInterceptor(StringuserAgentHeaderValue){this.userAgentHeaderValue=Preconditions.checkNotNull(userAgentHeaderValue)}@OverridepublicResponseintercept(Chainchain)throwsIOException{finalRequestoriginalRequest=chain.request()finalRequestrequestWithUserAgent=originalRequest.newBuilder().removeHeader(USER_AGENT_HEADER_NAME).addHeader(USER_AGENT_HEADER_NAME,userAgentHeaderValue).build()returnchain.proceed(requestWithUserAgent)}}publicfinalclassUserAgentInterceptorimplementsInterceptor{privatestaticfinalStringUSER_AGENT_HEADER_NAME="User-Agent"privatefinalStringuserAgentHeaderValuepublicUserAgentInterceptor(StringuserAgentHeaderValue){this.userAgentHeaderValue=Preconditions.checkNotNull(userAgentHeaderValue)}@OverridepublicResponseintercept(Chainchain)throwsIOException{finalRequestoriginalRequest=chain.request()finalRequestrequestWithUserAgent=originalRequest.newBuilder().removeHeader(USER_AGENT_HEADER_NAME).addHeader(USER_AGENT_HEADER_NAME,userAgentHeaderValue).build()returnchain.proceed(requestWithUserAgent)}}为了创建User-Agentheader值人然后传递给UserAgentInterceptor的构造器,使用你得到的任何信息。我们可以使用:android的系统信息可以清晰的传递出这是一台android设备Build.MODEL或者“制造商提供的用户可见最终可见的名称”Build.BRAND或者“消费者可见的品牌与产品/硬件相关信息”Build.VERSION.SDK_INT或者“消费者可见的Android提供的SDK版本号”BuildConfig.APPLICATION_IDBuildConfig.VERSION_NAMEBuildConfig.VERSION_CODE最后三个值由的applicationID,VERSIONCODE和VERSIONNAME的值在我们的Gradlebuild脚本中了解信息可以查看versioningyourapplications和configuringyourapplicationIdwithGradle请注意,如果您的应用程序使用的是WebView,您可以配置使用相同的User-Agentheader值,你可以通过下面方法创建UserAgentInterceptor:WebSettingssettings=webView.getSettings()settings.setUserAgentString(userAgentHeaderValue)WebSettingssettings=webView.getSettings()settings.setUserAgentString(userAgentHeaderValue)5.指定合理的超时2.5.0版本之前,OkHttp请求默认为永不超时。2.5.0版本开始如果建立连接请求超时,如果从连接读取下一个字节或写入的下一个字节到连接,花费超过10秒,就终止。这样做需要更新到2.5.0版本我们就不需要在我们的代码中修改bug。原因很简单是我因为我们第一次使用的时候使用了错误的路径。要覆盖这些默认值,可以分别调用setConnectTimeout,setReadTimeout或setWriteTimeout。需要注意的是Picasso和Retrofit为OkHttpClient实例指定不同的超时值时,默认情况下,Picasso指定:连接超过15秒.读取超过20秒写入超过20秒而Retrofit指定:连接超过15秒.读取超过20秒没有写入超时通过配置Picasso和Retrofit自己的OkHttpClient实例你可以确保所有的请求超时是一致的

public String getWebContent(String url) { // 创建一个http请求对象 HttpGet request = new HttpGet(url)// 创建HttpParams以用来设置HTTP参数 HttpParams params = new BasicHttpParams()// 设置连接超时或响应超时 // HttpConnectionParams.setConnectionTimeout(params, 3000)// HttpConnectionParams.setSoTimeout(params, 5000)// 创建一个网络访问处理对象 HttpClient httpClient = new DefaultHttpClient(params)try { // 执行请求参数项 HttpResponse response = httpClient.execute(request)// 判断是否请求成功 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { // 获得响应信息 String content = EntityUtils.toString(response.getEntity())return content} else { // 网连接失败,使用Toast显示提示信息 Toast.makeText( context, context.getResources().... public String getWebContent(String url) { // 创建一个http请求对象 HttpGet request = new HttpGet(url)// 创建HttpParams以用来设置HTTP参数 HttpParams params = new BasicHttpParams()// 设置连接超时或响应超时 // HttpConnectionParams.setConnectionTimeout(params, 3000)// HttpConnectionParams.setSoTimeout(params, 5000)// 创建一个网络访问处理对象 HttpClient httpClient = new DefaultHttpClient(params)try { // 执行请求参数项 HttpResponse response = httpClient.execute(request)// 判断是否请求成功 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { // 获得响应信息 String content = EntityUtils.toString(response.getEntity())return content} else { // 网连接失败,使用Toast显示提示信息 Toast.makeText( context, context.getResources().getString( R.string.connected_fails), 3000).show()} } catch (Exception e) { // e.printStackTrace()} finally { // 释放网络连接资源 httpClient.getConnectionManager().shutdown()} return null}content:即为json数据。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/7827781.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-10
下一篇 2023-04-10

发表评论

登录后才能评论

评论列表(0条)

保存