为了账号安全,请及时绑定邮箱和手机立即绑定

Android设置Volley以从缓存中使用

Android设置Volley以从缓存中使用

人到中年有点甜 2019-11-14 14:19:51
我正在尝试为服务器JSON响应创建并使用缓存。例如:将JSON对象缓存到内部存储器中,并在没有互联网连接时使用它。在下面的示例代码中,我找不到任何有关如何对其进行缓存Volley并在服务器头再次更新未到期时重新使用的文档。像这样:将过期设置为标头并使用缓存,并在过期后尝试再次加载。我正在尝试为此方法设置缓存机制:private void makeJsonArryReq() {    JsonArrayRequest req = new JsonArrayRequest(Const.URL_JSON_ARRAY,            new Response.Listener<JSONArray>() {                @Override                public void onResponse(JSONArray response) {                    msgResponse.setText(response.toString());                }            }, new Response.ErrorListener() {        @Override        public void onErrorResponse(VolleyError error) {        }    });    AppController.getInstance().addToRequestQueue(req,tag_json_arry);}缓存方法:public static Cache.Entry parseIgnoreCacheHeaders(NetworkResponse response) {    long now = System.currentTimeMillis();    Map<String, String> headers = response.headers;    long serverDate = 0;    String serverEtag = null;    String headerValue;    headerValue = headers.get("Date");    if (headerValue != null) {        serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);    }    serverEtag = headers.get("ETag");    final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background    final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely    final long softExpire = now + cacheHitButRefreshed;    final long ttl = now + cacheExpired;    Cache.Entry entry = new Cache.Entry();    entry.data = response.data;    entry.etag = serverEtag;    entry.softTtl = softExpire;    entry.ttl = ttl;    entry.serverDate = serverDate;    entry.responseHeaders = headers;    return entry;}
查看完整描述

2 回答

?
慕慕森

TA贡献1856条经验 获得超17个赞

请注意,如果Web服务支持缓存输出,则无需在CacheRequest下面使用,因为Volley它将自动缓存。


对于您的问题,我在内部使用了一些代码parseCacheHeaders(并引用了@ oleksandr_yefremov的代码)。我测试了以下代码。当然也可以使用JsonArrayRequest。希望对您有所帮助!


    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(0, mUrl, new Response.Listener<JSONObject>() {

        @Override

        public void onResponse(JSONObject response) {

            try {

                mTextView.setText(response.toString(5));

            } catch (JSONException e) {

                mTextView.setText(e.toString());

            }

        }

    }, new Response.ErrorListener() {

        @Override

        public void onErrorResponse(VolleyError error) {


        }

    }) {

        @Override

        protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {

            try {                    

                Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response);

                if (cacheEntry == null) {

                    cacheEntry = new Cache.Entry();

                }

                final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background

                final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely

                long now = System.currentTimeMillis();

                final long softExpire = now + cacheHitButRefreshed;

                final long ttl = now + cacheExpired;

                cacheEntry.data = response.data;

                cacheEntry.softTtl = softExpire;

                cacheEntry.ttl = ttl;

                String headerValue;

                headerValue = response.headers.get("Date");

                if (headerValue != null) {

                    cacheEntry.serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);

                }

                headerValue = response.headers.get("Last-Modified");

                if (headerValue != null) {

                    cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue);

                }

                cacheEntry.responseHeaders = response.headers;

                final String jsonString = new String(response.data,

                        HttpHeaderParser.parseCharset(response.headers));

                return Response.success(new JSONObject(jsonString), cacheEntry);

            } catch (UnsupportedEncodingException e) {

                return Response.error(new ParseError(e));

            } catch (JSONException e) {

                return Response.error(new ParseError(e));

            }

        }


        @Override

        protected void deliverResponse(JSONObject response) {

            super.deliverResponse(response);

        }


        @Override

        public void deliverError(VolleyError error) {

            super.deliverError(error);

        }


        @Override

        protected VolleyError parseNetworkError(VolleyError volleyError) {

            return super.parseNetworkError(volleyError);

        }

    };


    MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);

更新:


如果需要基类,请参考以下代码:


public class CacheRequest extends Request<NetworkResponse> {

    private final Response.Listener<NetworkResponse> mListener;

    private final Response.ErrorListener mErrorListener;


    public CacheRequest(int method, String url, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) {

        super(method, url, errorListener);

        this.mListener = listener;

        this.mErrorListener = errorListener;

    }



    @Override

    protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {

        Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response);

        if (cacheEntry == null) {

            cacheEntry = new Cache.Entry();

        }

        final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background

        final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely

        long now = System.currentTimeMillis();

        final long softExpire = now + cacheHitButRefreshed;

        final long ttl = now + cacheExpired;

        cacheEntry.data = response.data;

        cacheEntry.softTtl = softExpire;

        cacheEntry.ttl = ttl;

        String headerValue;

        headerValue = response.headers.get("Date");

        if (headerValue != null) {

            cacheEntry.serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);

        }

        headerValue = response.headers.get("Last-Modified");

        if (headerValue != null) {

            cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue);

        }

        cacheEntry.responseHeaders = response.headers;

        return Response.success(response, cacheEntry);

    }


    @Override

    protected void deliverResponse(NetworkResponse response) {

        mListener.onResponse(response);

    }


    @Override

    protected VolleyError parseNetworkError(VolleyError volleyError) {

        return super.parseNetworkError(volleyError);

    }


    @Override

    public void deliverError(VolleyError error) {

        mErrorListener.onErrorResponse(error);

    }

}

然后在MainActivity中,您可以像这样调用


CacheRequest cacheRequest = new CacheRequest(0, mUrl, new Response.Listener<NetworkResponse>() {

        @Override

        public void onResponse(NetworkResponse response) {

            try {

                final String jsonString = new String(response.data,

                        HttpHeaderParser.parseCharset(response.headers));

                JSONObject jsonObject = new JSONObject(jsonString);

                mTextView.setText(jsonObject.toString(5));

            } catch (UnsupportedEncodingException | JSONException e) {

                e.printStackTrace();

            }

        }

    }, new Response.ErrorListener() {

        @Override

        public void onErrorResponse(VolleyError error) {

            mTextView.setText(error.toString());

        }

    });


    MySingleton.getInstance(this).addToRequestQueue(cacheRequest);

用全源代码更新:


MainActivity.java:


package com.example.cachevolley;


import android.content.Context;

import android.os.Bundle;

import android.support.v7.app.AppCompatActivity;

import android.view.Menu;

import android.view.MenuItem;

import android.widget.TextView;

import android.widget.Toast;


import com.android.volley.Cache;

import com.android.volley.NetworkResponse;

import com.android.volley.Request;

import com.android.volley.RequestQueue;

import com.android.volley.Response;

import com.android.volley.VolleyError;

import com.android.volley.toolbox.HttpHeaderParser;

import com.android.volley.toolbox.Volley;


import org.json.JSONException;

import org.json.JSONObject;


import java.io.UnsupportedEncodingException;


public class MainActivity extends AppCompatActivity {


    private final Context mContext = this;


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


        final TextView textView = (TextView) findViewById(R.id.textView);


        RequestQueue queue = Volley.newRequestQueue(this);

        String url = "http://192.168.0.100/apitest";


        CacheRequest cacheRequest = new CacheRequest(0, url, new Response.Listener<NetworkResponse>() {

            @Override

            public void onResponse(NetworkResponse response) {

                try {

                    final String jsonString = new String(response.data,

                            HttpHeaderParser.parseCharset(response.headers));

                    JSONObject jsonObject = new JSONObject(jsonString);

                    textView.setText(jsonObject.toString(5));

                    Toast.makeText(mContext, "onResponse:\n\n" + jsonObject.toString(), Toast.LENGTH_SHORT).show();

                } catch (UnsupportedEncodingException | JSONException e) {

                    e.printStackTrace();

                }

            }

        }, new Response.ErrorListener() {

            @Override

            public void onErrorResponse(VolleyError error) {

                Toast.makeText(mContext, "onErrorResponse:\n\n" + error.toString(), Toast.LENGTH_SHORT).show();

            }

        });


        // Add the request to the RequestQueue.

        queue.add(cacheRequest);

    }


    @Override

    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.

        getMenuInflater().inflate(R.menu.menu_main, menu);

        return true;

    }


    @Override

    public boolean onOptionsItemSelected(MenuItem item) {

        // Handle action bar item clicks here. The action bar will

        // automatically handle clicks on the Home/Up button, so long

        // as you specify a parent activity in AndroidManifest.xml.

        int id = item.getItemId();


        //noinspection SimplifiableIfStatement

        if (id == R.id.action_settings) {

            return true;

        }


        return super.onOptionsItemSelected(item);

    }


    private class CacheRequest extends Request<NetworkResponse> {

        private final Response.Listener<NetworkResponse> mListener;

        private final Response.ErrorListener mErrorListener;


        public CacheRequest(int method, String url, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) {

            super(method, url, errorListener);

            this.mListener = listener;

            this.mErrorListener = errorListener;

        }



        @Override

        protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {

            Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response);

            if (cacheEntry == null) {

                cacheEntry = new Cache.Entry();

            }

            final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background

            final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely

            long now = System.currentTimeMillis();

            final long softExpire = now + cacheHitButRefreshed;

            final long ttl = now + cacheExpired;

            cacheEntry.data = response.data;

            cacheEntry.softTtl = softExpire;

            cacheEntry.ttl = ttl;

            String headerValue;

            headerValue = response.headers.get("Date");

            if (headerValue != null) {

                cacheEntry.serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);

            }

            headerValue = response.headers.get("Last-Modified");

            if (headerValue != null) {

                cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue);

            }

            cacheEntry.responseHeaders = response.headers;

            return Response.success(response, cacheEntry);

        }


        @Override

        protected void deliverResponse(NetworkResponse response) {

            mListener.onResponse(response);

        }


        @Override

        protected VolleyError parseNetworkError(VolleyError volleyError) {

            return super.parseNetworkError(volleyError);

        }


        @Override

        public void deliverError(VolleyError error) {

            mErrorListener.onErrorResponse(error);

        }

    }

}

清单文件:


<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.cachevolley" >


    <uses-permission android:name="android.permission.INTERNET" />


    <application

        android:allowBackup="true"

        android:icon="@mipmap/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name=".MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />


                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>


</manifest>

布局文件:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context=".MainActivity">


    <TextView

        android:id="@+id/textView"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/hello_world" />


</RelativeLayout>


查看完整回答
反对 回复 2019-11-14
?
精慕HU

TA贡献1845条经验 获得超8个赞

如果响应是使用字符串请求从服务器获取的,则只需替换行


return Response.success(new JSONObject(jsonString), cacheEntry);

有了这个


return Response.success(new String(jsonString), cacheEntry);

在我的情况下有效。尝试使用您自己的代码。


查看完整回答
反对 回复 2019-11-14
  • 2 回答
  • 0 关注
  • 599 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信