banner
NEWS LETTER

自己的网络框架配合数据库缓存使用

Scroll down

首先创建IDaoSupport接口规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public interface IDaoSupport<T> {
/**
* 初始化
*
* @param sqLiteDatabase s
* @param clazz c
*/
void init(SQLiteDatabase sqLiteDatabase, Class<T> clazz);

/**
* 插入
*
* @param t t
* @return l
*/
long insert(T t);

/**
* 批量插入,检测性能
*
* @param datas l
*/
void insert(List<T> datas);

/**
* 获取专门查询的支持类
*/
QuerySupport<T> querySupport();

/**
* 删除
*/
int delete(String whereClause, String... whereArgs);

/**
* 更新
*/
int update(T object, String whereClause, String... whereArgs);
}

创建DaoSupportFactory工厂类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class DaoSupportFactory {
private static DaoSupportFactory mFactory;

/**
* 持有外部数据库的引用
*/
private final SQLiteDatabase mSqLiteDatabase;

private DaoSupportFactory() {
//打开或者创建一个数据库,放到内存卡里
File dbRoot = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator + "nhdz" + File.separator + "database");
if (!dbRoot.exists()) {
dbRoot.mkdirs();
}
File dbFile = new File(dbRoot, "nhdz.db");
mSqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
}

public static DaoSupportFactory getFactory() {
if (mFactory == null) {
synchronized (DaoSupportFactory.class) {
if (mFactory == null) {
mFactory = new DaoSupportFactory();
}
}
}
return mFactory;
}

public <T> IDaoSupport<T> getDao(Class<T> clazz) {
IDaoSupport<T> daoSupport = new DaoSupport<>();
daoSupport.init(mSqLiteDatabase, clazz);
return daoSupport;
}
}

创建DaoUtils工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class DaoUtils {
private DaoUtils() {
throw new UnsupportedOperationException("cannot be instantiated");
}

public static String getTableName(Class<?> clazz) {
return clazz.getSimpleName();
}

public static String getColumnType(String type) {
String value = null;
if (type.contains("String")) {
value = " text";
} else if (type.contains("int")) {
value = " integer";
} else if (type.contains("boolean")) {
value = " boolean";
} else if (type.contains("float")) {
value = " float";
} else if (type.contains("double")) {
value = " double";
} else if (type.contains("char")) {
value = " varchar";
} else if (type.contains("long")) {
value = " long";
}

return value;
}

public static String capitalize(String string) {
if (!TextUtils.isEmpty(string)) {
return string.substring(0, 1).toUpperCase(Locale.US) + string.substring(1);
}
return string;
}
}

创建查询类QuerySupport

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
public class QuerySupport<T> {
/**
* 查询列
*/
private String[] mQueryColumns;
/**
* 查询条件
*/
private String mQuerySelection;
/**
* 查询参数
*/
private String[] mQuerySelectionArgs;
/**
* 查询分组
*/
private String mQueryGroupBy;
/**
* 查询对结果进行过滤
*/
private String mQueryHaving;
/**
* 查询排序
*/
private String mQueryOrderBy;
/**
* 查询可用于分页
*/
private String mQueryLimit;

private final Class<T> mClazz;
private final SQLiteDatabase mSqLiteDatabase;

public QuerySupport(SQLiteDatabase sqLiteDatabase, Class<T> mClass) {
this.mClazz = mClass;
this.mSqLiteDatabase = sqLiteDatabase;
}

public QuerySupport<T> columns(String... columns) {
this.mQueryColumns = columns;
return this;
}

public QuerySupport<T> selectionArgs(String... selectionArgs) {
this.mQuerySelectionArgs = selectionArgs;
return this;
}

public QuerySupport<T> having(String having) {
this.mQueryHaving = having;
return this;
}

public QuerySupport<T> orderBy(String orderBy) {
this.mQueryOrderBy = orderBy;
return this;
}

public QuerySupport<T> limit(String limit) {
this.mQueryLimit = limit;
return this;
}

public QuerySupport<T> groupBy(String groupBy) {
this.mQueryGroupBy = groupBy;
return this;
}

public QuerySupport<T> selection(String selection) {
this.mQuerySelection = selection;
return this;
}

public List<T> query() {
Cursor cursor = mSqLiteDatabase.query(DaoUtils.getTableName(mClazz), mQueryColumns,
mQuerySelection, mQuerySelectionArgs, mQueryGroupBy, mQueryHaving, mQueryOrderBy, mQueryLimit);
clearQueryParams();
return cursorToList(cursor);
}

public List<T> queryAll() {
Cursor cursor = mSqLiteDatabase.query(DaoUtils.getTableName(mClazz),
null, null, null, null, null, null);
return cursorToList(cursor);
}

private void clearQueryParams() {
mQueryColumns = null;
mQuerySelection = null;
mQuerySelectionArgs = null;
mQueryGroupBy = null;
mQueryHaving = null;
mQueryOrderBy = null;
mQueryLimit = null;
}

private List<T> cursorToList(Cursor cursor) {
List<T> list = new ArrayList<>();
if (cursor != null && cursor.moveToFirst()) {
//不断从游标里面获取数据
do {
try {
//通过反射new对象
T instance = mClazz.newInstance();
Field[] fields = mClazz.getDeclaredFields();
for (Field field : fields) {
//遍历属性,设置权限
field.setAccessible(true);
String name = field.getName();
//获取角标
int index = cursor.getColumnIndex(name);
if (index == -1) {
continue;
}
//通过反射获取游标的方法 ,field.getType()获取类型
Method cursorMethod = cursorMethod(field.getType());
Object value = cursorMethod.invoke(cursor, index);
if (value == null) {
continue;
}
//处理一些特殊的部分
if (field.getType() == boolean.class || field.getType() == boolean.class) {
if ("0".equals(String.valueOf(value))) {
value = false;
} else if ("1".equals(String.valueOf(value))) {
value = true;
}
} else if (field.getType() == char.class || field.getType() == Character.class) {
value = ((String) value).charAt(0);
} else if (field.getType() == Date.class) {
long date = (Long) value;
if (date <= 0) {
value = null;
} else {
value = new Date(date);
}
}
//通过反射注入
field.set(instance, value);
}
list.add(instance);
} catch (Exception e) {
e.printStackTrace();
}
} while (cursor.moveToNext());
}
assert cursor != null;
cursor.close();
return list;
}

private Method cursorMethod(Class<?> type) throws Exception {
String methodName = getColumnMethodName(type);
return Cursor.class.getMethod(methodName, int.class);
}

private String getColumnMethodName(Class<?> fieldType) {
String typeName;
if (fieldType.isPrimitive()) {
typeName = DaoUtils.capitalize(fieldType.getName());
} else {
typeName = fieldType.getSimpleName();
}
String methodName = "get" + typeName;
switch (methodName) {
case "getBoolean":
case "getInteger":
methodName = "getInt";
break;
case "getChar":
case "getCharacter":
methodName = "getString";
break;
case "getData":
methodName = "getLong";
break;
default:
break;
}
return methodName;
}
}

创建DaoSupport类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
public class DaoSupport<T> implements IDaoSupport<T> {
private SQLiteDatabase mSqLiteDatabase;
private Class<T> mClazz;
private static final String TAG = "DaoSupport";
private static final Object[] M_PUT_METHOD_ARGS = new Object[2];
private static final Map<String, Method> M_PUT_METHODS = new ArrayMap<>();
private QuerySupport<T> mQuerySupport;

@Override
public void init(SQLiteDatabase sqLiteDatabase, Class<T> clazz) {
this.mSqLiteDatabase = sqLiteDatabase;
this.mClazz = clazz;
StringBuilder sb = new StringBuilder();
sb.append("create table if not exists ")
.append(DaoUtils.getTableName(clazz))
.append(" (id integer primary key autoincrement, ");
Field[] fields = mClazz.getDeclaredFields();
for (Field field : fields) {
//设置权限
field.setAccessible(true);
String name = field.getName();
// int String boolean
String type = field.getType().getSimpleName();
//type需要转换 int ->Integer String ->text
sb.append(name).append(DaoUtils.getColumnType(type)).append(", ");
}
sb.replace(sb.length() - 2, sb.length(), ") ");
String createTableSql = sb.toString();
Log.e(TAG, "表语句-->" + createTableSql);
mSqLiteDatabase.execSQL(createTableSql);
}

/**
* 插入数据,T是任何对象
*
* @param object o
* @return i
*/
@Override
public long insert(T object) {
//使用的其实还是 原生的,只封装了一下
ContentValues values = contentValuesByObj(object);
return mSqLiteDatabase.insert(DaoUtils.getTableName(mClazz), null, values);
}

@Override
public void insert(List<T> datas) {
//多条插入采用事务
mSqLiteDatabase.beginTransaction();
for (T data : datas) {
//调用单条插入
insert(data);
}
mSqLiteDatabase.setTransactionSuccessful();
mSqLiteDatabase.endTransaction();
}

/**
* 查询
*/
@Override
public QuerySupport<T> querySupport() {
if (mQuerySupport == null) {
mQuerySupport = new QuerySupport<>(mSqLiteDatabase, mClazz);
}
return mQuerySupport;
}


/**
* 删除
*/
@Override
public int delete(String whereClause, String... whereArgs) {
return mSqLiteDatabase.delete(DaoUtils.getTableName(mClazz), whereClause, whereArgs);
}

/**
* 更新
*/
@Override
public int update(T object, String whereClause, String... whereArgs) {
ContentValues values = contentValuesByObj(object);
return mSqLiteDatabase.update(DaoUtils.getTableName(mClazz), values, whereClause, whereArgs);
}

/**
* obj 转成ContentValues
*/
private ContentValues contentValuesByObj(T object) {
ContentValues values = new ContentValues();
//封装values
Field[] declaredFields = mClazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
try {
//设置权限,私有和公有都可以使用
declaredField.setAccessible(true);
String key = declaredField.getName();
//获取value,第二个参数是类型,把它转换
Object value = declaredField.get(object);
if (value == null) {
continue;
}
String declaredFieldTypeName = declaredField.getType().getName();
//使用反射 获取方法,反射一定程度上会影响性能
//缓存方法
Method putMethod = M_PUT_METHODS.get(declaredFieldTypeName);
if (putMethod == null) {
putMethod = ContentValues.class.getMethod("put"
, String.class, value.getClass());
M_PUT_METHODS.put(declaredFieldTypeName, putMethod);
}
M_PUT_METHOD_ARGS[0] = key;
M_PUT_METHOD_ARGS[1] = value;
putMethod.invoke(values, M_PUT_METHOD_ARGS);
} catch (Exception e) {
e.printStackTrace();
} finally {
M_PUT_METHOD_ARGS[0] = null;
M_PUT_METHOD_ARGS[1] = null;
}
}
return values;
}
}

创建CacheData实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class CacheData {
public String getUrlKey() {
return mUrlKey;
}
public String getResultJson() {
return mResultJson;
}

/**
* 请求的链接
*/
private String mUrlKey;
/**
* 后台返回的json
*/
private String mResultJson;

public CacheData() {
}

public CacheData(String urlKey, String resultJson) {
this.mResultJson = resultJson;
this.mUrlKey = urlKey;
}
}

创建缓存帮助类CacheDataUtil

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class CacheDataUtil {
/**
* 获取数据
*/
public static String getCacheResultJson(String jointUrl) {
final IDaoSupport<CacheData> dataDaoSupport = DaoSupportFactory.getFactory().getDao(CacheData.class);
List<CacheData> cacheData = dataDaoSupport.querySupport().selection("mUrlKey = ?")
.selectionArgs(MD5Util.string2MD5(jointUrl)).query();
if (cacheData.size() != 0) {
//如果有数据
CacheData data = cacheData.get(0);
return data.getResultJson();
}
return null;
}

/**
* 缓存数据
*/
public static long cacheData(String jointUrl, String result) {
final IDaoSupport<CacheData> dataDaoSupport = DaoSupportFactory.getFactory().getDao(CacheData.class);
dataDaoSupport.delete("mUrlKey=?", MD5Util.string2MD5(jointUrl));
long number = dataDaoSupport.insert(new CacheData(MD5Util.string2MD5(jointUrl), result));
Log.e("number", "number->" + number);
return number;
}
}

将网络请求引擎OkHttpEngine提到中间层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
public class OkHttpEngine implements IHttpEngine {
private static final OkHttpClient M_OK_HTTP_CLIENT = new OkHttpClient();
private final Handler mHandler = new Handler();
@Override
public void get(boolean cache, Context context, String url, Map<String, Object> params, EngineCallback callback) {
final String jointUrl = HttpUtils.joinParams(url, params);
Log.e("Get请求路径: ", jointUrl);
//判断缓存有没有
if (cache) {
//需要缓存,拿缓存
String resultJson = CacheDataUtil.getCacheResultJson(jointUrl);
if (!TextUtils.isEmpty(resultJson)) {
//需要缓存,而且数据库有缓存,直接返回数据
Log.e("Get数据和缓存一致直接返回: ", resultJson);
callback.onSuccess(resultJson);
}
}
Request request = new Request.Builder()
.url(url)
.get()
.tag(context)
.build();
M_OK_HTTP_CLIENT.newCall(request).enqueue(
new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
mHandler.post(() -> callback.onError(e));
}

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
String result = Objects.requireNonNull(response.body()).string();
//每次拿到数据之后比对上一次的内容
if (cache) {
String resultJson = CacheDataUtil.getCacheResultJson(jointUrl);
if (resultJson != null && !TextUtils.isEmpty(resultJson) && resultJson.equals(result)) {
//比对内容
//内容相同,不需要执行success方法
Log.e("Get数据和缓存一致: ", result);
return;
}
}
//执行success方法,缓存数据
Log.e("Get返回结果: ", result);
mHandler.post(() -> callback.onSuccess(result));
if (cache) {
//缓存数据
CacheDataUtil.cacheData(jointUrl, result);
}
}
}
);
}

@Override
public void post(boolean cache, Context context, String url, Map<String, Object> params, EngineCallback callback) {
final String jointUrl = HttpUtils.joinParams(url, params);
Log.e("Post请求路径: ", jointUrl);
RequestBody requestBody = appendBody(params);
Request request = new Request.Builder()
.url(url)
.tag(context)
.post(requestBody)
.build();
M_OK_HTTP_CLIENT.newCall(request).enqueue(
new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
mHandler.post(() -> callback.onError(e));
}

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
String result = Objects.requireNonNull(response.body()).string();
Log.e("Post返回结果: ", result);
mHandler.post(() -> callback.onSuccess(result));
}
}
);
}

/**
* 组装post请求参数body
*/
protected RequestBody appendBody(Map<String, Object> params) {
MultipartBody.Builder builder = new MultipartBody.Builder()
.setType(MultipartBody.FORM);
addParams(builder, params);
return builder.build();
}

/**
* 添加参数
*/
private void addParams(MultipartBody.Builder builder, Map<String, Object> params) {
if (params != null && !params.isEmpty()) {
for (String key : params.keySet()) {
builder.addFormDataPart(key, params.get(key) + "");
Object value = params.get(key);
if (value instanceof File) {
//处理文件 -->Object -->file
File file = (File) value;
builder.addFormDataPart(key, file.getName(), RequestBody
.create(file, MediaType.parse(guessMimeType(file.getAbsolutePath()))));
} else if (value instanceof List) {
try {
List<File> fileList = (List<File>) value;
for (int i = 0; i < fileList.size(); i++) {
//获取文件
File file = fileList.get(i);
builder.addFormDataPart(key + i, file.getName(), RequestBody
.create(file, MediaType.parse(guessMimeType(file.getAbsolutePath()))));
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
builder.addFormDataPart(key, value + "");
}
}
}
}

/**
* 猜测文件的类型
*/
private String guessMimeType(String path) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String contentTypeFor = fileNameMap.getContentTypeFor(path);
if (contentTypeFor == null) {
contentTypeFor = "application/octet-stream";
}
return contentTypeFor;
}
}

修改IHttpEngine

1
2
3
4
public interface IHttpEngine {
void get(boolean cache, Context context, String url, Map<String, Object> params, EngineCallback callback);
void post(boolean cache, Context context, String url, Map<String, Object> params, EngineCallback callback);
}

修改HttpUtils

1
2
3
4
5
6
7
8
9
10
11
12
 /**
* 是否配置缓存
*/
public HttpUtils cache(boolean isCache) {
mCache = isCache;
return this;
}
/**
* 默认OkHttpEngine
*/
private static IHttpEngine mIHttpEngine = null;

使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
IDaoSupport<Person> daoSupport = DaoSupportFactory.getFactory().getDao(Person.class);
List<Person> people = daoSupport.querySupport().queryAll();
Log.d("size", people.size() + "");
HttpUtils.with(this).get().exchangeEngine(new OkHttpEngine()).execute(new HttpCallback<Person>() {
@Override
public void onError(Exception e) {

}

@Override
public void onSuccess(Person result) {

}
});
其他文章
目录导航 置顶
  1. 1. 首先创建IDaoSupport接口规范
  2. 2. 创建DaoSupportFactory工厂类
  3. 3. 创建DaoUtils工具类
  4. 4. 创建查询类QuerySupport
  5. 5. 创建DaoSupport类
  6. 6. 创建CacheData实体类
  7. 7. 创建缓存帮助类CacheDataUtil
  8. 8. 将网络请求引擎OkHttpEngine提到中间层
  9. 9. 修改IHttpEngine
  10. 10. 修改HttpUtils
  11. 11. 使用方法
请输入关键词进行搜索