越深入学习,越明白缓存的重要性,例举我认为的需要缓存的场景:
- 从网络上获取的数据不会马上更新的情况,比如 快递信息就不会立马更新,这时候就可以使用缓存机制将获取到的数据缓存到内存,有网络情况下下拉刷新,无网络情况下从缓存中获取数据。
- 一些阅读类,新闻类的app,大部分都是图文结合,频繁的去服务器获取信息 图片的显示会很慢,这时候使用缓存机制,将相关信息存在缓存中,当需要加载相关信息时,先从缓存数据中获取,如果有,直接加载,如果没有,再从服务器去获取数据,速度会快很多。
- 如果数据是网络中获取的,如果不做缓存,那么在无网络情况下,进入界面就是空白一片,造成非常不好的体验,所以缓存是非常重要的一件事。
使用ASimpleCache实现一个快递信息的缓存
ASimpleCache下载链接:
https://github.com/yangfuhai/ASimpleCache
首先activity的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background"
tools:context="example.com.huancuntest.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
</RelativeLayout>
RecyclerView的item布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:layout_margin="2dp"
>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="content"
android:textColor="@color/textColor"
android:layout_margin="5dp"
android:textSize="18sp"/>
<TextView
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="time"
android:textColor="@color/textColor"
android:layout_marginLeft="5dp"/>
</LinearLayout>
接下来实体类,先看json数组
{
"message": "ok",
"nu": "227873745185",
"ischeck": "1",
"condition": "F00",
"com": "shentong",
"status": "200",
"state": "3",
"data": [
{
"time": "2017-03-19 20:01:33",
"ftime": "2017-03-19 20:01:33",
"context": "[云南丽江公司]小许派,本人签-已签收",
"location": null
},
{
"time": "2017-03-19 10:37:25",
"ftime": "2017-03-19 10:37:25",
"context": "[云南丽江公司]云南丽江公司-南门片区-派件中",
"location": null
},
{
"time": "2017-03-19 09:16:33",
"ftime": "2017-03-19 09:16:33",
"context": "[云南丽江公司]已到达-云南丽江公司",
"location": null
},
{
"time": "2017-03-19 09:16:22",
"ftime": "2017-03-19 09:16:22",
"context": "[云南丽江公司]已到达-云南丽江公司",
"location": null
},
{
"time": "2017-03-18 10:07:16",
"ftime": "2017-03-18 10:07:16",
"context": "[云南昆明航空部]已到达-云南昆明航空部",
"location": null
},
{
"time": "2017-03-18 10:07:12",
"ftime": "2017-03-18 10:07:12",
"context": "[云南昆明航空部]云南昆明航空部-已发往-云南丽江公司",
"location": null
},
{
"time": "2017-03-17 02:03:37",
"ftime": "2017-03-17 02:03:37",
"context": "[广东东莞中转部]广东东莞中转部-已装袋发往-云南昆明航空部",
"location": null
},
{
"time": "2017-03-16 23:14:29",
"ftime": "2017-03-16 23:14:29",
"context": "[广东东莞凤岗分部]广东东莞凤岗分部-已发往-广东东莞中转部",
"location": null
},
{
"time": "2017-03-16 22:08:38",
"ftime": "2017-03-16 22:08:38",
"context": "[广东东莞凤岗分部]广东东莞凤岗分部-刘国贤-已收件",
"location": null
}
]
}
"message": "ok",
"nu": "227873745185",
"ischeck": "1",
"condition": "F00",
"com": "shentong",
"status": "200",
"state": "3",
"data": [
{
"time": "2017-03-19 20:01:33",
"ftime": "2017-03-19 20:01:33",
"context": "[云南丽江公司]小许派,本人签-已签收",
"location": null
},
{
"time": "2017-03-19 10:37:25",
"ftime": "2017-03-19 10:37:25",
"context": "[云南丽江公司]云南丽江公司-南门片区-派件中",
"location": null
},
{
"time": "2017-03-19 09:16:33",
"ftime": "2017-03-19 09:16:33",
"context": "[云南丽江公司]已到达-云南丽江公司",
"location": null
},
{
"time": "2017-03-19 09:16:22",
"ftime": "2017-03-19 09:16:22",
"context": "[云南丽江公司]已到达-云南丽江公司",
"location": null
},
{
"time": "2017-03-18 10:07:16",
"ftime": "2017-03-18 10:07:16",
"context": "[云南昆明航空部]已到达-云南昆明航空部",
"location": null
},
{
"time": "2017-03-18 10:07:12",
"ftime": "2017-03-18 10:07:12",
"context": "[云南昆明航空部]云南昆明航空部-已发往-云南丽江公司",
"location": null
},
{
"time": "2017-03-17 02:03:37",
"ftime": "2017-03-17 02:03:37",
"context": "[广东东莞中转部]广东东莞中转部-已装袋发往-云南昆明航空部",
"location": null
},
{
"time": "2017-03-16 23:14:29",
"ftime": "2017-03-16 23:14:29",
"context": "[广东东莞凤岗分部]广东东莞凤岗分部-已发往-广东东莞中转部",
"location": null
},
{
"time": "2017-03-16 22:08:38",
"ftime": "2017-03-16 22:08:38",
"context": "[广东东莞凤岗分部]广东东莞凤岗分部-刘国贤-已收件",
"location": null
}
]
}
Message.java
package example.com.huancuntest.entity;
import java.util.Date;
import java.util.List;
/**
* Created by csjy on 2017/5/9.
*/
public class MessageEntity {
private List<DataEntity> data;
public List<DataEntity> getData() {
return data;
}
public void setData(List<DataEntity> data) {
this.data = data;
}
}
DataEntity.java
package example.com.huancuntest.entity;
/**
* Created by csjy on 2017/5/9.
*/
public class DataEntity {
private String time;
private String context;
public void setContext(String context) {
this.context = context;
}
public void setTime(String time) {
this.time = time;
}
public String getTime() {
return time;
}
public String getContext() {
return context;
}
}
最后在写一个用于存放相关数据的实体
TotalEntity.java
package example.com.huancuntest.entity;
/**
* Created by csjy on 2017/5/9.
*/
public class TotalEntity {
private String context;
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
private String time;
}
RecyclerView的适配器:
package example.com.huancuntest;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import example.com.huancuntest.entity.TotalEntity;
/**
* Created by Administrator on 2017/5/9.
*/
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder>{
private LayoutInflater inflater;
private List<TotalEntity> mList;
public RecyclerViewAdapter(Context context, List<TotalEntity> mList) {
inflater = LayoutInflater.from(context);
this.mList = mList;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
MyViewHolder holder = new MyViewHolder(inflater.inflate(R.layout.item_activity_main,parent,false));
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tvContent.setText(mList.get(position).getContext());
holder.tvTime.setText(mList.get(position).getTime());
}
@Override
public int getItemCount() {
return mList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder{
private TextView tvContent,tvTime;
public MyViewHolder(View itemView) {
super(itemView);
tvContent = (TextView) itemView.findViewById(R.id.tv_content);
tvTime = (TextView) itemView.findViewById(R.id.tv_time);
}
}
}
声明一个泛型为TotalEntity的List,在绑定数据的方法中通过TotalEntity的get方法提供数据。
MainActivity
package example.com.huancuntest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.Toast;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import example.com.huancuntest.Util.ACache;
import example.com.huancuntest.entity.DataEntity;
import example.com.huancuntest.entity.MessageEntity;
import example.com.huancuntest.entity.TotalEntity;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private RecyclerViewAdapter adapter;
private List<TotalEntity> mList;
private TotalEntity total;
private Gson gson;
private SPUtil spUtil;
private ACache aCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
recyclerView = (RecyclerView)this.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
initData();
adapter = new RecyclerViewAdapter(this,mList);
recyclerView.setAdapter(adapter);
}
private void initData() {
mList = new ArrayList<TotalEntity>();
gson = new Gson();
spUtil = SPUtil.getInstance();
aCache = ACache.get(MainActivity.this);
String company = "shentong";
String num = "227873745185";
if (NetUtil.isNetwork(this)){
RequestQueue queue = Volley.newRequestQueue(this);
GsonRequest<MessageEntity> request = new GsonRequest<MessageEntity>(
"http://www.kuaidi100.com/query?type="+company+"&postid="+num,
MessageEntity.class, new Response.Listener<MessageEntity>() {
@Override
public void onResponse(MessageEntity response) {
for (int i = 0; i < response.getData().size(); i++){
total = new TotalEntity();
DataEntity entity = response.getData().get(i);
total.setContext(entity.getContext());
total.setTime(entity.getTime());
mList.add(total);
}
Log.d("tag", "response----" + response.getData().toString());
try {
JSONArray jsonArray = new JSONArray(gson.toJson(response.getData()));
aCache.put("test",jsonArray);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("Tag", error.getMessage(),error);
}
});
queue.add(request);
}else{
JSONArray jsonArray = aCache.getAsJSONArray("test");
for (int i = 0; i < jsonArray.length(); i++) {
try {
total = gson.fromJson(jsonArray.get(i).toString(), TotalEntity.class);
Log.d("tag","json array-----" + jsonArray.get(i).toString());
Log.d("Tag","getContect----" + total.getContext());
Log.d("Tag","getTime----" + total.getTime());
mList.add(total);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}
在initData()方法中,首先判断有没有网络,如果有,利用volley获取网络中的数据,将获取到的数据添加进List中,并将数据存入缓存,如果没有网络,获取缓存中的数据,并将数据添加进List中。
判断是否有网络的类:
package example.com.huancuntest.Util;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
/**
* Created by csjy on 2017/5/9.
* 判断是否有网络
*/
public class NetUtil {
public static boolean isNetwork(Context context){
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = manager.getActiveNetworkInfo();
if (info != null && info.isConnected()){
if (info.getState() == NetworkInfo.State.CONNECTED){
return true;
}
}
return false;
}
}
使用SharedPreferances实现缓存
这里只改动了MainActivity.java
package example.com.huancuntest;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.LruCache;
import android.widget.Toast;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import example.com.huancuntest.Util.ACache;
import example.com.huancuntest.Util.NetUtil;
import example.com.huancuntest.Util.SPUtil;
import example.com.huancuntest.Util.SpUtils;
import example.com.huancuntest.entity.DataEntity;
import example.com.huancuntest.entity.MessageEntity;
import example.com.huancuntest.entity.TotalEntity;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private RecyclerViewAdapter adapter;
private List<TotalEntity> mList;
private TotalEntity total;
private Gson gson;
private SPUtil spUtil;
private ACache aCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
recyclerView = (RecyclerView)this.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
initData();
adapter = new RecyclerViewAdapter(this,mList);
recyclerView.setAdapter(adapter);
}
private void initData() {
mList = new ArrayList<TotalEntity>();
gson = new Gson();
spUtil = SPUtil.getInstance();
aCache = ACache.get(MainActivity.this);
String company = "shentong";
String num = "227873745185";
if (NetUtil.isNetwork(this)){
RequestQueue queue = Volley.newRequestQueue(this);
GsonRequest<MessageEntity> request = new GsonRequest<MessageEntity>(
"http://www.kuaidi100.com/query?type="+company+"&postid="+num,
MessageEntity.class, new Response.Listener<MessageEntity>() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onResponse(MessageEntity response) {
for (int i = 0; i < response.getData().size(); i++){
total = new TotalEntity();
DataEntity entity = response.getData().get(i);
total.setContext(entity.getContext());
total.setTime(entity.getTime());
mList.add(total);
}
// JSONArray jsonArray = new JSONArray(gson.toJson(response.getData()));
// Log.d("tag", "jsonArray test == " + jsonArray);
// aCache.put("test",jsonArray);
spUtil.putJsonArray(MainActivity.this,"test",gson.toJson(response.getData()));
Toast.makeText(MainActivity.this, "has network", Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("Tag", error.getMessage(),error);
}
});
queue.add(request);
}else{
// JSONArray jsonArray = aCache.getAsJSONArray("test");
// for (int i = 0; i < jsonArray.length(); i++) {
// try {
// total = gson.fromJson(jsonArray.get(i).toString(), TotalEntity.class);
// Log.d("tag","json array-----" + jsonArray.get(i).toString());
// Log.d("Tag","getContect----" + total.getContext());
// Log.d("Tag","getTime----" + total.getTime());
// mList.add(total);
// } catch (JSONException e) {
// e.printStackTrace();
// }
// }
String test = spUtil.getJsonArray(MainActivity.this,"test","");
JSONArray jsonArray = null;
try {
jsonArray = new JSONArray(test);
for (int i = 0; i < jsonArray.length(); i++){
total = gson.fromJson(jsonArray.get(i).toString(),TotalEntity.class);
mList.add(total);
}
} catch (JSONException e) {
e.printStackTrace();
}
Toast.makeText(this, "no network", Toast.LENGTH_SHORT).show();
}
}
}
initData()方法中,将网络返回的数据(response)通过sharedPreferances缓存至内存中,
在没有网络的情况下直接从内存中读取,没网络情况下,首先实例化一个Json数组,将此json数组序列化为TotalEntity对象
(通过gson.fromJosn()方法实现),最后将数据添加进List中。
package example.com.huancuntest.Util;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import org.json.JSONObject;
/**
* Created by csjy on 2017/5/10.
*/
public class SPUtil {
public static final String SP_NAME = "name";
private static SPUtil instance;
private static SharedPreferences mSp;
private JSONObject mJsonObject;
private SPUtil() {
}
public static SPUtil getInstance() {
if (instance == null) {
synchronized (SPUtil.class) {
if (instance == null) {
instance = new SPUtil();
}
}
}
return instance;
}
public String getJsonArray(Context context,String key, String defVal) {
mSp = context.getSharedPreferences(SP_NAME,Context.MODE_PRIVATE);
Log.d("TAG", "getJsonArray: " + mSp.getString(key,defVal));
return mSp.getString(key,defVal);
}
public void putJsonArray(Context context, String key, String value){
mSp = context.getSharedPreferences(SP_NAME,Context.MODE_PRIVATE);
SharedPreferences.Editor editor = mSp.edit();
editor.putString(key,value);
Log.d("tag","value====" + value);
editor.commit();
}
}
该类是一个单例模式。
putJsonArray()方法中,首先实例化sharedpreferances,调用Editor的putString()方法以键值对的形式添加数据。
getJsonArray()方法调用sharedpreferances的getString()方法通过键值对的值来取值。