ORM重构
This commit is contained in:
@@ -41,7 +41,7 @@ import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.upload.UploadReceiver;
|
||||
import com.arialyy.aria.core.upload.UploadTaskEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.orm.DbUtil;
|
||||
import com.arialyy.aria.orm.DelegateWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.File;
|
||||
@@ -77,7 +77,7 @@ import org.xml.sax.SAXException;
|
||||
private Configuration.UploadConfig mUConfig;
|
||||
|
||||
private AriaManager(Context context) {
|
||||
DbUtil.init(context.getApplicationContext());
|
||||
DelegateWrapper.init(context.getApplicationContext());
|
||||
APP = context.getApplicationContext();
|
||||
regAppLifeCallback(context);
|
||||
initConfig();
|
||||
|
||||
@@ -16,13 +16,7 @@
|
||||
|
||||
package com.arialyy.aria.core.command.normal;
|
||||
|
||||
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
|
||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.core.upload.UploadTaskEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/6/27.
|
||||
@@ -44,46 +38,5 @@ public class CancelAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
|
||||
|
||||
@Override public void executeCmd() {
|
||||
removeAll();
|
||||
if (mTaskEntity instanceof DownloadTaskEntity
|
||||
|| mTaskEntity instanceof DownloadGroupTaskEntity) {
|
||||
handleDownloadRemove();
|
||||
handleDownloadGroupRemove();
|
||||
} else if (mTaskEntity instanceof UploadTaskEntity) {
|
||||
handleUploadRemove();
|
||||
handleUploadRemove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理下载任务组的删除操作
|
||||
*/
|
||||
private void handleDownloadGroupRemove() {
|
||||
List<DownloadGroupTaskEntity> allEntity = DbEntity.findAllData(DownloadGroupTaskEntity.class);
|
||||
if (allEntity == null || allEntity.size() == 0) return;
|
||||
for (DownloadGroupTaskEntity entity : allEntity) {
|
||||
CommonUtil.delDownloadGroupTaskConfig(removeFile, entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理上传的删除
|
||||
*/
|
||||
private void handleUploadRemove() {
|
||||
List<UploadTaskEntity> allEntity = DbEntity.findAllData(UploadTaskEntity.class);
|
||||
if (allEntity == null || allEntity.size() == 0) return;
|
||||
for (UploadTaskEntity entity : allEntity) {
|
||||
CommonUtil.delUploadTaskConfig(removeFile, entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理下载的删除
|
||||
*/
|
||||
private void handleDownloadRemove() {
|
||||
List<DownloadTaskEntity> allEntity = DbEntity.findAllData(DownloadTaskEntity.class);
|
||||
if (allEntity == null || allEntity.size() == 0) return;
|
||||
for (DownloadTaskEntity entity : allEntity) {
|
||||
CommonUtil.delDownloadTaskConfig(removeFile, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
|
||||
|| task.getState() == IEntity.STATE_OTHER
|
||||
|| task.getState() == IEntity.STATE_POST_PRE
|
||||
|| task.getState() == IEntity.STATE_COMPLETE) {
|
||||
//startTask();
|
||||
resumeTask();
|
||||
} else {
|
||||
sendWaitState();
|
||||
@@ -85,7 +84,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
|
||||
}
|
||||
} else {
|
||||
if (!task.isRunning()) {
|
||||
//startTask();
|
||||
resumeTask();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,13 @@ package com.arialyy.aria.core.common;
|
||||
import android.content.Context;
|
||||
import android.util.SparseArray;
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||
import com.arialyy.aria.core.inf.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.core.inf.IDownloadListener;
|
||||
import com.arialyy.aria.core.inf.IEventListener;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.upload.UploadTaskEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
@@ -89,7 +91,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override public void run() {
|
||||
if (mConstance.isRunning) {
|
||||
return;
|
||||
@@ -193,9 +194,11 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
}
|
||||
}
|
||||
if (mTaskEntity instanceof DownloadTaskEntity) {
|
||||
CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, (DownloadTaskEntity) mTaskEntity);
|
||||
CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile,
|
||||
(DownloadEntity) mTaskEntity.getEntity());
|
||||
} else if (mTaskEntity instanceof UploadTaskEntity) {
|
||||
CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile, (UploadTaskEntity) mTaskEntity);
|
||||
CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile,
|
||||
(UploadEntity) mTaskEntity.getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +229,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查任务是否是新任务,新任务条件:
|
||||
* 1、文件不存在
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.arialyy.aria.orm.DbEntity;
|
||||
* Created by laoyuyu on 2018/3/21.
|
||||
* 任务上传或下载的记录
|
||||
*/
|
||||
class TaskRecord extends DbEntity{
|
||||
class TaskRecord extends DbEntity {
|
||||
/**
|
||||
* 任务线程数
|
||||
*/
|
||||
|
||||
@@ -63,10 +63,8 @@ public class HttpHeaderDelegate<TARGET extends ITarget, ENTITY extends AbsEntity
|
||||
}
|
||||
if (mTaskEntity.headers.get(key) == null) {
|
||||
mTaskEntity.headers.put(key, value);
|
||||
mTaskEntity.update();
|
||||
} else if (!mTaskEntity.headers.get(key).equals(value)) {
|
||||
mTaskEntity.headers.put(key, value);
|
||||
mTaskEntity.update();
|
||||
}
|
||||
return mTarget;
|
||||
}
|
||||
@@ -122,7 +120,6 @@ public class HttpHeaderDelegate<TARGET extends ITarget, ENTITY extends AbsEntity
|
||||
for (String key : keys) {
|
||||
mTaskEntity.headers.put(key, headers.get(key));
|
||||
}
|
||||
mTaskEntity.update();
|
||||
}
|
||||
|
||||
return mTarget;
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.arialyy.aria.core.download;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.manager.SubTaskManager;
|
||||
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
|
||||
import com.arialyy.aria.core.queue.DownloadTaskQueue;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.io.File;
|
||||
@@ -29,7 +28,6 @@ import java.util.List;
|
||||
*/
|
||||
abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
|
||||
extends AbsDownloadTarget<TARGET, DownloadGroupEntity, DownloadGroupTaskEntity> {
|
||||
private static final String TAG = "BaseGroupTarget";
|
||||
|
||||
/**
|
||||
* 组任务名
|
||||
@@ -60,7 +58,6 @@ abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
|
||||
public TARGET setGroupAlias(String alias) {
|
||||
if (TextUtils.isEmpty(alias)) return (TARGET) this;
|
||||
mEntity.setAlias(alias);
|
||||
mEntity.update();
|
||||
return (TARGET) this;
|
||||
}
|
||||
|
||||
@@ -158,7 +155,6 @@ abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
|
||||
}
|
||||
mEntity.setDirPath(dirPath);
|
||||
reChangeDirPath(dirPath);
|
||||
mEntity.update();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.io.File;
|
||||
abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
|
||||
extends AbsDownloadTarget<TARGET, DownloadEntity, DownloadTaskEntity> {
|
||||
|
||||
private static final String TAG = "BaseNormalTarget";
|
||||
/**
|
||||
* 资源地址
|
||||
*/
|
||||
@@ -42,9 +41,6 @@ abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
|
||||
this.url = url;
|
||||
mTargetName = targetName;
|
||||
mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url);
|
||||
if (mTaskEntity == null) {
|
||||
mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, url);
|
||||
}
|
||||
mEntity = mTaskEntity.entity;
|
||||
mTaskEntity.refreshInfo = refreshInfo;
|
||||
if (mEntity != null) {
|
||||
@@ -110,7 +106,11 @@ abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
|
||||
* @return {@code true}合法
|
||||
*/
|
||||
@Override protected boolean checkEntity() {
|
||||
return getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath();
|
||||
boolean b = getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath();
|
||||
if (b) {
|
||||
mTaskEntity.save(mEntity);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,7 +149,7 @@ abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
|
||||
mEntity.setDownloadPath(filePath);
|
||||
mEntity.setFileName(newFile.getName());
|
||||
mTaskEntity.key = filePath;
|
||||
mTaskEntity.update();
|
||||
//mTaskEntity.update();
|
||||
CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.inf.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.orm.Foreign;
|
||||
import com.arialyy.aria.orm.Primary;
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
|
||||
/**
|
||||
@@ -35,12 +35,7 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable {
|
||||
/**
|
||||
* 所属任务组
|
||||
*/
|
||||
@Foreign(table = DownloadGroupEntity.class, column = "groupName") private String groupName = "";
|
||||
|
||||
/**
|
||||
* 下载任务实体的key
|
||||
*/
|
||||
@Foreign(table = DownloadTaskEntity.class, column = "key") private String taskKey = "";
|
||||
@Foreign(parent = DownloadGroupEntity.class, column = "groupName") private String groupName = "";
|
||||
|
||||
/**
|
||||
* 从服务器的返回信息中获取的文件md5信息,如果服务器没有返回,则不会设置该信息
|
||||
|
||||
@@ -18,8 +18,7 @@ package com.arialyy.aria.core.download;
|
||||
import android.os.Parcel;
|
||||
import com.arialyy.aria.core.inf.AbsGroupEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.orm.OneToMany;
|
||||
import java.util.ArrayList;
|
||||
import com.arialyy.aria.orm.annotation.Ignore;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -28,8 +27,11 @@ import java.util.List;
|
||||
*/
|
||||
public class DownloadGroupEntity extends AbsGroupEntity {
|
||||
|
||||
@OneToMany(table = DownloadEntity.class, key = "groupName") private List<DownloadEntity> subtask =
|
||||
new ArrayList<>();
|
||||
//@OneToMany(table = DownloadEntity.class, key = "groupName") private List<DownloadEntity> subtask =
|
||||
// new ArrayList<>();
|
||||
|
||||
@Ignore
|
||||
private List<DownloadEntity> subtask;
|
||||
|
||||
/**
|
||||
* 任务组下载文件的文件夹地址
|
||||
|
||||
@@ -24,16 +24,13 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/6/29.
|
||||
* 下载任务组
|
||||
*/
|
||||
public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
|
||||
private final String TAG = "DownloadGroupTarget";
|
||||
/**
|
||||
* 子任务下载地址,
|
||||
*/
|
||||
@@ -50,12 +47,8 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
|
||||
this.mUrls.addAll(groupEntity.getUrls());
|
||||
}
|
||||
mGroupName = CommonUtil.getMd5Code(groupEntity.getUrls());
|
||||
mTaskEntity = TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, mGroupName);
|
||||
if (mTaskEntity == null) {
|
||||
mTaskEntity =
|
||||
TEManager.getInstance().createTEntity(DownloadGroupTaskEntity.class, groupEntity);
|
||||
}
|
||||
mEntity = mTaskEntity.entity;
|
||||
mTaskEntity = TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, mUrls);
|
||||
mEntity = mTaskEntity.getEntity();
|
||||
|
||||
if (mEntity != null) {
|
||||
mDirPathTemp = mEntity.getDirPath();
|
||||
@@ -66,11 +59,8 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
|
||||
this.mTargetName = targetName;
|
||||
this.mUrls = urls;
|
||||
mGroupName = CommonUtil.getMd5Code(urls);
|
||||
mTaskEntity = TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, mGroupName);
|
||||
if (mTaskEntity == null) {
|
||||
mTaskEntity = TEManager.getInstance().createGTEntity(DownloadGroupTaskEntity.class, mUrls);
|
||||
}
|
||||
mEntity = mTaskEntity.entity;
|
||||
mTaskEntity = TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, mUrls);
|
||||
mEntity = mTaskEntity.getEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,7 +78,6 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
|
||||
}
|
||||
if (mEntity.getFileSize() <= 1 || mEntity.getFileSize() != fileSize) {
|
||||
mEntity.setFileSize(fileSize);
|
||||
mEntity.update();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -137,7 +126,8 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
|
||||
entity.setGroupName(mGroupName);
|
||||
entity.setGroupChild(true);
|
||||
entity.setFileName(fileName);
|
||||
entity.insert();
|
||||
// TODO: 2018/4/3 是否需要在这个插入?
|
||||
//entity.insert();
|
||||
list.add(entity);
|
||||
}
|
||||
return list;
|
||||
@@ -164,7 +154,6 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
|
||||
//文件夹路径通过后,并且该实体没有子任务,则创建子任务
|
||||
if (mEntity.getSubTask() == null || mEntity.getSubTask().isEmpty()) {
|
||||
mEntity.setSubTasks(createSubTask());
|
||||
mTaskEntity.update();
|
||||
} else {
|
||||
updateSingleSubFileName();
|
||||
}
|
||||
@@ -230,7 +219,6 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
|
||||
}
|
||||
|
||||
mEntity.setGroupName(CommonUtil.getMd5Code(mUrls));
|
||||
mEntity.update();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -251,7 +239,8 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
|
||||
"UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
|
||||
entity.setDownloadPath(newPath);
|
||||
entity.setFileName(newName);
|
||||
entity.update();
|
||||
// TODO: 2018/4/3 是否需要在这个更新?
|
||||
//entity.update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,24 +16,42 @@
|
||||
package com.arialyy.aria.core.download;
|
||||
|
||||
import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
|
||||
import com.arialyy.aria.orm.OneToOne;
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
import com.arialyy.aria.orm.annotation.Ignore;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/7/1.
|
||||
*/
|
||||
public class DownloadGroupTaskEntity extends AbsGroupTaskEntity<DownloadGroupEntity> {
|
||||
|
||||
@OneToOne(table = DownloadGroupEntity.class, key = "groupName") public DownloadGroupEntity entity;
|
||||
@Ignore private DownloadGroupEntity entity;
|
||||
|
||||
@Primary @Foreign(parent = DownloadGroupEntity.class, column = "groupName")
|
||||
private String key;
|
||||
|
||||
@Override public DownloadGroupEntity getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
public void setEntity(DownloadGroupEntity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public void save(DownloadGroupEntity groupEntity){
|
||||
key = groupEntity.getKey();
|
||||
entity = groupEntity;
|
||||
groupEntity.save();
|
||||
@Override public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void save(DownloadGroupEntity groupEntity) {
|
||||
if (groupEntity != null) {
|
||||
key = groupEntity.getKey();
|
||||
entity = groupEntity;
|
||||
groupEntity.save();
|
||||
}
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.download;
|
||||
|
||||
import com.arialyy.aria.orm.AbsWrapper;
|
||||
import com.arialyy.aria.orm.annotation.Many;
|
||||
import com.arialyy.aria.orm.annotation.One;
|
||||
import com.arialyy.aria.orm.annotation.Wrapper;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/30.
|
||||
*/
|
||||
@Wrapper
|
||||
public class DownloadGroupTaskWrapper extends AbsWrapper {
|
||||
|
||||
@One
|
||||
public DownloadGroupEntity entity;
|
||||
|
||||
@Many(parentColumn = "key", entityColumn = "groupName")
|
||||
private List<DownloadGroupTaskEntity> taskEntitys;
|
||||
|
||||
public DownloadGroupTaskEntity taskEntity;
|
||||
|
||||
@Override protected void handleConvert() {
|
||||
taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0);
|
||||
if (taskEntity != null) {
|
||||
taskEntity.setEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.download;
|
||||
|
||||
import com.arialyy.aria.orm.AbsWrapper;
|
||||
import com.arialyy.aria.orm.annotation.Many;
|
||||
import com.arialyy.aria.orm.annotation.One;
|
||||
import com.arialyy.aria.orm.annotation.Wrapper;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/30.
|
||||
*/
|
||||
@Wrapper
|
||||
public class DownloadGroupWrapper extends AbsWrapper {
|
||||
|
||||
@One
|
||||
public DownloadGroupEntity groupEntity;
|
||||
|
||||
@Many(parentColumn = "groupName", entityColumn = "groupName")
|
||||
public List<DownloadEntity> subEntity;
|
||||
|
||||
@Override protected void handleConvert() {
|
||||
if (subEntity != null && !subEntity.isEmpty()) {
|
||||
groupEntity.setSubTasks(subEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,11 @@ import com.arialyy.aria.core.common.ProxyHelper;
|
||||
import com.arialyy.aria.core.inf.AbsEntity;
|
||||
import com.arialyy.aria.core.inf.AbsReceiver;
|
||||
import com.arialyy.aria.core.inf.AbsTarget;
|
||||
import com.arialyy.aria.core.manager.TEManager;
|
||||
import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers;
|
||||
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.util.ArrayList;
|
||||
@@ -106,14 +108,14 @@ public class DownloadReceiver extends AbsReceiver {
|
||||
* </pre>
|
||||
*/
|
||||
@Deprecated public DownloadTarget load(@NonNull String url, boolean refreshInfo) {
|
||||
url = CheckUtil.checkUrl(url);
|
||||
CheckUtil.checkUrlInvalidThrow(url);
|
||||
return new DownloadTarget(url, targetName, refreshInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组
|
||||
*
|
||||
* @param urls 人刷谁
|
||||
* @param urls 任务组子任务下载地址列表
|
||||
*/
|
||||
@Deprecated
|
||||
public DownloadGroupTarget load(List<String> urls) {
|
||||
@@ -173,7 +175,7 @@ public class DownloadReceiver extends AbsReceiver {
|
||||
* @param refreshInfo 是否刷新下载信息
|
||||
*/
|
||||
public FtpDownloadTarget loadFtp(@NonNull String url, boolean refreshInfo) {
|
||||
url = CheckUtil.checkUrl(url);
|
||||
CheckUtil.checkUrlInvalidThrow(url);
|
||||
return new FtpDownloadTarget(url, targetName, refreshInfo);
|
||||
}
|
||||
|
||||
@@ -203,7 +205,7 @@ public class DownloadReceiver extends AbsReceiver {
|
||||
* 加载ftp文件夹下载地址
|
||||
*/
|
||||
public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) {
|
||||
dirUrl = CheckUtil.checkUrl(dirUrl);
|
||||
CheckUtil.checkUrlInvalidThrow(dirUrl);
|
||||
return new FtpDirDownloadTarget(dirUrl, targetName);
|
||||
}
|
||||
|
||||
@@ -257,39 +259,55 @@ public class DownloadReceiver extends AbsReceiver {
|
||||
|
||||
/**
|
||||
* 通过下载链接获取下载实体
|
||||
*
|
||||
* @return 如果url错误或查找不到数据,则返回null
|
||||
*/
|
||||
public DownloadEntity getDownloadEntity(String downloadUrl) {
|
||||
downloadUrl = CheckUtil.checkUrl(downloadUrl);
|
||||
if (CheckUtil.checkUrl(downloadUrl)) {
|
||||
return null;
|
||||
}
|
||||
return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过下载链接获取保存在数据库的下载任务实体
|
||||
* 通过下载地址和文件保存路径获取下载任务实体
|
||||
*
|
||||
* @param downloadUrl 下载地址
|
||||
* @return 如果url错误或查找不到数据,则返回null
|
||||
*/
|
||||
public DownloadTaskEntity getDownloadTask(String downloadUrl) {
|
||||
downloadUrl = CheckUtil.checkUrl(downloadUrl);
|
||||
DownloadEntity entity = getDownloadEntity(downloadUrl);
|
||||
if (entity == null || TextUtils.isEmpty(entity.getDownloadPath())) return null;
|
||||
return DbEntity.findFirst(DownloadTaskEntity.class, "key=? and isGroupTask='false'",
|
||||
entity.getDownloadPath());
|
||||
if (CheckUtil.checkUrl(downloadUrl)) {
|
||||
return null;
|
||||
}
|
||||
return TEManager.getInstance().getTEntity(DownloadTaskEntity.class, downloadUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过下载链接获取保存在数据库的下载任务组实体
|
||||
*
|
||||
* @param urls 任务组子任务下载地址列表
|
||||
* @return 返回对应的任务组实体;如果查找不到对应的数据或子任务列表为null,返回null
|
||||
*/
|
||||
public DownloadGroupTaskEntity getDownloadGroupTask(List<String> urls) {
|
||||
CheckUtil.checkDownloadUrls(urls);
|
||||
String hashCode = CommonUtil.getMd5Code(urls);
|
||||
return DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", hashCode);
|
||||
public DownloadGroupTaskEntity getGroupTask(List<String> urls) {
|
||||
if (urls == null || urls.isEmpty()) {
|
||||
ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null");
|
||||
return null;
|
||||
}
|
||||
return TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, urls);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过任务组key,获取任务组实体
|
||||
* 如果是http,key为所有子任务下载地址拼接后取md5
|
||||
* 如果是ftp,key为ftp服务器的文件夹路径
|
||||
* 获取FTP文件夹下载任务实体
|
||||
*
|
||||
* @param dirPath FTP文件夹本地保存路径
|
||||
* @return 返回对应的任务组实体;如果查找不到对应的数据或路径为null,返回null
|
||||
*/
|
||||
public DownloadGroupTaskEntity getDownloadGroupTask(String key) {
|
||||
return DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", key);
|
||||
public DownloadGroupTaskEntity getFtpDirTask(String dirPath) {
|
||||
if (TextUtils.isEmpty(dirPath)) {
|
||||
ALog.e(TAG, "获取FTP文件夹实体失败:文件夹路径为null");
|
||||
return null;
|
||||
}
|
||||
return TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, dirPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,15 +345,25 @@ public class DownloadReceiver extends AbsReceiver {
|
||||
|
||||
/**
|
||||
* 获取任务组列表
|
||||
*
|
||||
* @return 如果没有任务组列表,则返回null
|
||||
*/
|
||||
public List<DownloadGroupEntity> getGroupTaskList() {
|
||||
return DownloadEntity.findAllData(DownloadGroupEntity.class);
|
||||
List<DownloadGroupWrapper> wrappers = DbEntity.findRelationData(DownloadGroupWrapper.class);
|
||||
if (wrappers == null || wrappers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
List<DownloadGroupEntity> entities = new ArrayList<>();
|
||||
for (DownloadGroupWrapper wrapper : wrappers) {
|
||||
entities.add(wrapper.groupEntity);
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取普通任务和任务组的任务列表
|
||||
*/
|
||||
public List<AbsEntity> getTotleTaskList() {
|
||||
public List<AbsEntity> getTotalTaskList() {
|
||||
List<AbsEntity> list = new ArrayList<>();
|
||||
List<DownloadEntity> simpleTask = getTaskList();
|
||||
List<DownloadGroupEntity> groupTask = getGroupTaskList();
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.util.Map;
|
||||
*/
|
||||
public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
|
||||
implements IHttpHeaderTarget<DownloadTarget> {
|
||||
private static final String TAG = "DownloadTarget";
|
||||
private HttpHeaderDelegate<DownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
|
||||
|
||||
DownloadTarget(DownloadEntity entity, String targetName) {
|
||||
|
||||
@@ -16,17 +16,19 @@
|
||||
package com.arialyy.aria.core.download;
|
||||
|
||||
import com.arialyy.aria.core.inf.AbsNormalTaskEntity;
|
||||
import com.arialyy.aria.orm.Ignore;
|
||||
import com.arialyy.aria.orm.NoNull;
|
||||
import com.arialyy.aria.orm.OneToOne;
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
import com.arialyy.aria.orm.annotation.Ignore;
|
||||
import com.arialyy.aria.orm.annotation.NoNull;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/1/23.
|
||||
* 下载任务实体
|
||||
* 下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除
|
||||
*/
|
||||
public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
|
||||
|
||||
@OneToOne(table = DownloadEntity.class, key = "downloadPath") public DownloadEntity entity;
|
||||
//@OneToOne(table = DownloadEntity.class, key = "downloadPath") public DownloadEntity entity;
|
||||
@Ignore public DownloadEntity entity;
|
||||
|
||||
/**
|
||||
* 任务的url
|
||||
@@ -48,6 +50,11 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
|
||||
*/
|
||||
public boolean isGroupTask = false;
|
||||
|
||||
/**
|
||||
* Task实体对应的key
|
||||
*/
|
||||
@Primary @Foreign(parent = DownloadEntity.class, column = "downloadPath") public String key = "";
|
||||
|
||||
public DownloadTaskEntity() {
|
||||
}
|
||||
|
||||
@@ -55,6 +62,10 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void save(DownloadEntity entity) {
|
||||
this.entity = entity;
|
||||
if (entity != null) {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.download;
|
||||
|
||||
import com.arialyy.aria.orm.AbsWrapper;
|
||||
import com.arialyy.aria.orm.annotation.Many;
|
||||
import com.arialyy.aria.orm.annotation.One;
|
||||
import com.arialyy.aria.orm.annotation.Wrapper;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/30.
|
||||
*/
|
||||
@Wrapper
|
||||
public class DownloadTaskWrapper extends AbsWrapper {
|
||||
|
||||
@One
|
||||
public DownloadEntity entity;
|
||||
|
||||
@Many(parentColumn = "downloadPath", entityColumn = "key")
|
||||
private List<DownloadTaskEntity> taskEntitys = null;
|
||||
|
||||
public DownloadTaskEntity taskEntity;
|
||||
|
||||
@Override public void handleConvert() {
|
||||
taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0);
|
||||
if (taskEntity != null) {
|
||||
taskEntity.entity = entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import com.arialyy.aria.util.ALog;
|
||||
*/
|
||||
public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
|
||||
implements IFtpTarget<FtpDirDownloadTarget> {
|
||||
private final String TAG = "FtpDirDownloadTarget";
|
||||
private FtpDelegate<FtpDirDownloadTarget, DownloadGroupEntity, DownloadGroupTaskEntity> mDelegate;
|
||||
|
||||
FtpDirDownloadTarget(String url, String targetName) {
|
||||
@@ -39,11 +38,8 @@ public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
|
||||
private void init(String key) {
|
||||
mGroupName = key;
|
||||
mTaskEntity = TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, key);
|
||||
if (mTaskEntity == null) {
|
||||
mTaskEntity = TEManager.getInstance().createTEntity(DownloadGroupTaskEntity.class, key);
|
||||
}
|
||||
mTaskEntity.requestType = AbsTaskEntity.D_FTP_DIR;
|
||||
mEntity = mTaskEntity.entity;
|
||||
mEntity = mTaskEntity.getEntity();
|
||||
if (mEntity != null) {
|
||||
mDirPathTemp = mEntity.getDirPath();
|
||||
}
|
||||
@@ -55,7 +51,11 @@ public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
|
||||
}
|
||||
|
||||
@Override protected boolean checkEntity() {
|
||||
return getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl();
|
||||
boolean b = getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl();
|
||||
if (b) {
|
||||
mTaskEntity.save(mEntity);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.arialyy.aria.util.CommonUtil;
|
||||
*/
|
||||
public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
|
||||
implements IFtpTarget<FtpDownloadTarget> {
|
||||
private final String TAG = "FtpDownloadTarget";
|
||||
private FtpDelegate<FtpDownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
|
||||
|
||||
FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
|
||||
|
||||
@@ -106,7 +106,7 @@ public abstract class AbsGroupUtil implements IUtil {
|
||||
mGTEntity = groupEntity;
|
||||
mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||
List<DownloadTaskEntity> tasks =
|
||||
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mGTEntity.key);
|
||||
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mGTEntity.getKey());
|
||||
if (tasks != null && !tasks.isEmpty()) {
|
||||
for (DownloadTaskEntity te : tasks) {
|
||||
te.removeFile = mGTEntity.removeFile;
|
||||
@@ -114,10 +114,10 @@ public abstract class AbsGroupUtil implements IUtil {
|
||||
mTasksMap.put(te.getEntity().getUrl(), te);
|
||||
}
|
||||
}
|
||||
mGroupSize = mGTEntity.entity.getSubTask().size();
|
||||
mGroupSize = mGTEntity.getEntity().getSubTask().size();
|
||||
mTotalLen = groupEntity.getEntity().getFileSize();
|
||||
isNeedLoadFileSize = mTotalLen <= 1;
|
||||
for (DownloadEntity entity : mGTEntity.entity.getSubTask()) {
|
||||
for (DownloadEntity entity : mGTEntity.getEntity().getSubTask()) {
|
||||
File file = new File(entity.getDownloadPath());
|
||||
if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) {
|
||||
mCompleteNum++;
|
||||
@@ -190,9 +190,10 @@ public abstract class AbsGroupUtil implements IUtil {
|
||||
* @param url 子任务下载地址
|
||||
*/
|
||||
public void cancelSubTask(String url) {
|
||||
List<String> urls = mGTEntity.entity.getUrls();
|
||||
List<String> urls = mGTEntity.getEntity().getUrls();
|
||||
if (urls != null && !urls.isEmpty() && urls.contains(url)) {
|
||||
urls.remove(url);
|
||||
// TODO: 2018/4/4 有问题
|
||||
DownloadTaskEntity det =
|
||||
DbEntity.findFirst(DownloadTaskEntity.class, "url=? and isGroupTask='true'", url);
|
||||
if (det != null) {
|
||||
@@ -273,7 +274,7 @@ public abstract class AbsGroupUtil implements IUtil {
|
||||
dt.cancel();
|
||||
}
|
||||
}
|
||||
delDownloadInfo();
|
||||
CommonUtil.delDownloadGroupTaskConfig(mGTEntity.removeFile, mGTEntity.getEntity());
|
||||
mGTEntity.deleteData();
|
||||
}
|
||||
|
||||
@@ -281,30 +282,6 @@ public abstract class AbsGroupUtil implements IUtil {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除所有子任务的下载信息
|
||||
*/
|
||||
private void delDownloadInfo() {
|
||||
List<DownloadTaskEntity> tasks =
|
||||
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mGTEntity.key);
|
||||
if (tasks != null && !tasks.isEmpty()) {
|
||||
for (DownloadTaskEntity taskEntity : tasks) {
|
||||
CommonUtil.delDownloadTaskConfig(mGTEntity.removeFile, taskEntity);
|
||||
}
|
||||
}
|
||||
|
||||
File dir = new File(mGTEntity.getEntity().getDirPath());
|
||||
if (mGTEntity.removeFile) {
|
||||
if (dir.exists()) {
|
||||
dir.delete();
|
||||
}
|
||||
} else {
|
||||
if (!mGTEntity.getEntity().isComplete()) {
|
||||
dir.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void stop() {
|
||||
closeTimer(false);
|
||||
onStop();
|
||||
@@ -418,7 +395,7 @@ public abstract class AbsGroupUtil implements IUtil {
|
||||
taskEntity.headers = mGTEntity.headers;
|
||||
taskEntity.requestEnum = mGTEntity.requestEnum;
|
||||
taskEntity.removeFile = mGTEntity.removeFile;
|
||||
taskEntity.groupName = mGTEntity.key;
|
||||
taskEntity.groupName = mGTEntity.getKey();
|
||||
taskEntity.isGroupTask = true;
|
||||
taskEntity.requestType = mGTEntity.requestType;
|
||||
taskEntity.key = entity.getDownloadPath();
|
||||
|
||||
@@ -44,12 +44,12 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
|
||||
new FtpDirInfoThread(mGTEntity, new OnFileInfoCallback() {
|
||||
@Override public void onComplete(String url, CompleteInfo info) {
|
||||
if (info.code >= 200 && info.code < 300) {
|
||||
for (DownloadEntity entity : mGTEntity.entity.getSubTask()) {
|
||||
for (DownloadEntity entity : mGTEntity.getEntity().getSubTask()) {
|
||||
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
|
||||
}
|
||||
mActualTaskNum = mGTEntity.entity.getSubTask().size();
|
||||
mActualTaskNum = mGTEntity.getEntity().getSubTask().size();
|
||||
mGroupSize = mActualTaskNum;
|
||||
mTotalLen = mGTEntity.entity.getFileSize();
|
||||
mTotalLen = mGTEntity.getEntity().getFileSize();
|
||||
startDownload();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,10 @@ class HttpFileInfoThread implements Runnable {
|
||||
}
|
||||
return;
|
||||
}
|
||||
newUrl = CheckUtil.checkUrl(newUrl);
|
||||
if (!CheckUtil.checkUrl(newUrl)) {
|
||||
failDownload("下载失败,重定向url错误", false);
|
||||
return;
|
||||
}
|
||||
String cookies = conn.getHeaderField("Set-Cookie");
|
||||
conn = (HttpURLConnection) new URL(newUrl).openConnection();
|
||||
conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.arialyy.aria.core.inf;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.orm.Ignore;
|
||||
import com.arialyy.aria.orm.annotation.Ignore;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/6/29.
|
||||
|
||||
@@ -17,10 +17,7 @@ package com.arialyy.aria.core.inf;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
|
||||
import com.arialyy.aria.orm.Foreign;
|
||||
import com.arialyy.aria.orm.NormalList;
|
||||
import com.arialyy.aria.orm.Primary;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -29,20 +26,16 @@ import java.util.List;
|
||||
*/
|
||||
public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
|
||||
/**
|
||||
* 组名,组名为任务地址相加的urlMd5
|
||||
* 组名,组名为任务地址相加的url的Md5
|
||||
*/
|
||||
@Primary @Foreign(table = DownloadGroupTaskEntity.class, column = "key") protected String
|
||||
groupName = "";
|
||||
@Primary protected String groupName = "";
|
||||
|
||||
/**
|
||||
* 任务组别名
|
||||
*/
|
||||
private String alias = "";
|
||||
|
||||
/**
|
||||
* 子任务链接组
|
||||
*/
|
||||
@NormalList(clazz = String.class) private List<String> urls = new ArrayList<>();
|
||||
private List<String> urls = new ArrayList<>();
|
||||
|
||||
public List<String> getUrls() {
|
||||
return urls;
|
||||
|
||||
@@ -17,8 +17,6 @@ package com.arialyy.aria.core.inf;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.orm.Ignore;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/6/3.
|
||||
|
||||
@@ -34,17 +34,25 @@ import java.util.List;
|
||||
*/
|
||||
public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
|
||||
implements ITarget<TARGET> {
|
||||
protected String TAG = "";
|
||||
protected ENTITY mEntity;
|
||||
protected TASK_ENTITY mTaskEntity;
|
||||
protected String mTargetName;
|
||||
|
||||
protected AbsTarget() {
|
||||
TAG = CommonUtil.getClassName(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置下载状态,将任务状态设置为未开始状态
|
||||
* 重置状态,将任务状态设置为未开始状态
|
||||
*/
|
||||
public TARGET resetState() {
|
||||
mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
|
||||
mTaskEntity.refreshInfo = true;
|
||||
mTaskEntity.update();
|
||||
if (checkEntity()) {
|
||||
mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
|
||||
mTaskEntity.refreshInfo = true;
|
||||
} else {
|
||||
ALog.e(TAG, "重置状态失败");
|
||||
}
|
||||
return (TARGET) this;
|
||||
}
|
||||
|
||||
@@ -96,10 +104,16 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
|
||||
*/
|
||||
public TARGET setExtendField(String str) {
|
||||
if (TextUtils.isEmpty(str)) return (TARGET) this;
|
||||
if (TextUtils.isEmpty(mEntity.getStr()) || !mEntity.getStr().equals(str)) {
|
||||
mEntity.setStr(str);
|
||||
mEntity.save();
|
||||
if (checkEntity()) {
|
||||
if (TextUtils.isEmpty(mEntity.getStr()) || !mEntity.getStr().equals(str)) {
|
||||
mEntity.setStr(str);
|
||||
} else {
|
||||
ALog.e(TAG, "设置扩展字段失败,扩展字段为null");
|
||||
}
|
||||
} else {
|
||||
ALog.e(TAG, "设置扩展字段失败");
|
||||
}
|
||||
|
||||
return (TARGET) this;
|
||||
}
|
||||
|
||||
@@ -138,7 +152,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实体是否合法
|
||||
* 检查实体是否合法,如果实体合法,将保存实体到数据库,或更新数据库中的实体对象
|
||||
*
|
||||
* @return {@code true} 合法
|
||||
*/
|
||||
@@ -252,6 +266,4 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ package com.arialyy.aria.core.inf;
|
||||
import com.arialyy.aria.core.FtpUrlEntity;
|
||||
import com.arialyy.aria.core.common.RequestEnum;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.orm.Ignore;
|
||||
import com.arialyy.aria.orm.Primary;
|
||||
import com.arialyy.aria.orm.annotation.Ignore;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -55,11 +54,6 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
|
||||
*/
|
||||
public static final int U_FTP = 0xA2;
|
||||
|
||||
/**
|
||||
* Task实体对应的key
|
||||
*/
|
||||
@Primary public String key = "";
|
||||
|
||||
/**
|
||||
* 账号和密码
|
||||
*/
|
||||
@@ -144,12 +138,7 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
|
||||
return getEntity().getState();
|
||||
}
|
||||
|
||||
@Override public void deleteData() {
|
||||
if (getEntity() != null) {
|
||||
getEntity().deleteData();
|
||||
}
|
||||
super.deleteData();
|
||||
}
|
||||
public abstract String getKey();
|
||||
|
||||
@Override public void update() {
|
||||
if (getEntity() != null) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.inf;
|
||||
|
||||
import com.arialyy.aria.orm.Ignore;
|
||||
import com.arialyy.aria.orm.annotation.Ignore;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/2/23.
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.inf;
|
||||
|
||||
import com.arialyy.aria.core.inf.IEventListener;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/2/9.
|
||||
* 上传监听
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.arialyy.aria.core.manager;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadGroupWrapper;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.util.List;
|
||||
@@ -46,36 +48,56 @@ class DGTEntityFactory implements ITEntityFactory<DownloadGroupEntity, DownloadG
|
||||
/**
|
||||
* 通过下载实体创建任务实体
|
||||
*/
|
||||
@Override public DownloadGroupTaskEntity create(DownloadGroupEntity entity) {
|
||||
DownloadGroupTaskEntity dgTaskEntity =
|
||||
DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", entity.getGroupName());
|
||||
if (dgTaskEntity == null) {
|
||||
private DownloadGroupTaskEntity create(DownloadGroupEntity entity) {
|
||||
List<DownloadGroupTaskWrapper> wrapper =
|
||||
DbEntity.findRelationData(DownloadGroupTaskWrapper.class, "DownloadGroupTaskWrapper.key=?",
|
||||
entity.getGroupName());
|
||||
DownloadGroupTaskEntity dgTaskEntity;
|
||||
|
||||
if (wrapper != null && !wrapper.isEmpty()) {
|
||||
dgTaskEntity = wrapper.get(0).taskEntity;
|
||||
if (dgTaskEntity == null) {
|
||||
dgTaskEntity = new DownloadGroupTaskEntity();
|
||||
dgTaskEntity.setEntity(entity);
|
||||
} else if (dgTaskEntity.getEntity() == null || TextUtils.isEmpty(
|
||||
dgTaskEntity.getEntity().getKey())) {
|
||||
dgTaskEntity.setEntity(entity);
|
||||
}
|
||||
} else {
|
||||
dgTaskEntity = new DownloadGroupTaskEntity();
|
||||
dgTaskEntity.save(entity);
|
||||
}
|
||||
if (dgTaskEntity.entity == null || TextUtils.isEmpty(dgTaskEntity.entity.getKey())) {
|
||||
dgTaskEntity.save(entity);
|
||||
dgTaskEntity.setEntity(entity);
|
||||
}
|
||||
|
||||
return dgTaskEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对于任务组,不能使用这个,可用于FTP文件夹下载
|
||||
* 对于任务组,不能使用这个,该方法只用于FTP文件夹下载
|
||||
*
|
||||
* @deprecated {@link #create(String, List)}
|
||||
* @deprecated 任务组使用:{@link #create(String, List)}
|
||||
*/
|
||||
@Override @Deprecated public DownloadGroupTaskEntity create(String key) {
|
||||
DownloadGroupTaskEntity dgTaskEntity =
|
||||
DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", key);
|
||||
if (dgTaskEntity == null) {
|
||||
List<DownloadGroupTaskWrapper> wrapper =
|
||||
DbEntity.findRelationData(DownloadGroupTaskWrapper.class, "DownloadGroupTaskWrapper.key=?",
|
||||
key);
|
||||
DownloadGroupTaskEntity dgTaskEntity;
|
||||
if (wrapper != null && !wrapper.isEmpty()) {
|
||||
dgTaskEntity = wrapper.get(0).taskEntity;
|
||||
if (dgTaskEntity == null) {
|
||||
dgTaskEntity = new DownloadGroupTaskEntity();
|
||||
dgTaskEntity.setEntity(getDownloadGroupEntity(key, null));
|
||||
} else if (dgTaskEntity.getEntity() == null || TextUtils.isEmpty(
|
||||
dgTaskEntity.getEntity().getKey())) {
|
||||
dgTaskEntity.setEntity(getDownloadGroupEntity(key, null));
|
||||
}
|
||||
dgTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(key);
|
||||
return dgTaskEntity;
|
||||
} else {
|
||||
dgTaskEntity = new DownloadGroupTaskEntity();
|
||||
dgTaskEntity.save(getDownloadGroupEntity(key, null));
|
||||
dgTaskEntity.setEntity(getDownloadGroupEntity(key, null));
|
||||
dgTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(key);
|
||||
return dgTaskEntity;
|
||||
}
|
||||
if (dgTaskEntity.entity == null || TextUtils.isEmpty(dgTaskEntity.entity.getKey())) {
|
||||
dgTaskEntity.save(getDownloadGroupEntity(key, null));
|
||||
}
|
||||
dgTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(key);
|
||||
return dgTaskEntity;
|
||||
}
|
||||
|
||||
@Override public DownloadGroupTaskEntity create(String groupName, List<String> urls) {
|
||||
@@ -86,13 +108,21 @@ class DGTEntityFactory implements ITEntityFactory<DownloadGroupEntity, DownloadG
|
||||
* 查询任务组实体,如果数据库不存在该实体,则新创建一个新的任务组实体
|
||||
*/
|
||||
private DownloadGroupEntity getDownloadGroupEntity(String groupName, List<String> urls) {
|
||||
DownloadGroupEntity entity =
|
||||
DbEntity.findFirst(DownloadGroupEntity.class, "groupName=?", groupName);
|
||||
if (entity == null) {
|
||||
entity = new DownloadGroupEntity();
|
||||
entity.setGroupName(groupName);
|
||||
entity.setUrls(urls);
|
||||
|
||||
List<DownloadGroupWrapper> wrapper =
|
||||
DbEntity.findRelationData(DownloadGroupWrapper.class, "DownloadGroupEntity.groupName=?",
|
||||
groupName);
|
||||
DownloadGroupEntity groupEntity;
|
||||
if (wrapper != null && !wrapper.isEmpty()) {
|
||||
groupEntity = wrapper.get(0).groupEntity;
|
||||
if (groupEntity == null) {
|
||||
groupEntity = new DownloadGroupEntity();
|
||||
}
|
||||
} else {
|
||||
groupEntity = new DownloadGroupEntity();
|
||||
}
|
||||
return entity;
|
||||
groupEntity.setGroupName(groupName);
|
||||
groupEntity.setUrls(urls);
|
||||
return groupEntity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ package com.arialyy.aria.core.manager;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||
import com.arialyy.aria.core.download.DownloadTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/11/1.
|
||||
@@ -45,19 +47,26 @@ class DTEntityFactory implements ITEntityFactory<DownloadEntity, DownloadTaskEnt
|
||||
/**
|
||||
* 通过下载实体创建任务实体
|
||||
*/
|
||||
@Override public DownloadTaskEntity create(DownloadEntity entity) {
|
||||
DownloadTaskEntity taskEntity =
|
||||
DbEntity.findFirst(DownloadTaskEntity.class, "key=? and isGroupTask='false' and url=?",
|
||||
entity.getDownloadPath(), entity.getUrl());
|
||||
if (taskEntity == null) {
|
||||
taskEntity = new DownloadTaskEntity();
|
||||
taskEntity.save(entity);
|
||||
} else if (taskEntity.entity == null || TextUtils.isEmpty(taskEntity.entity.getUrl())) {
|
||||
taskEntity.save(entity);
|
||||
} else if (!taskEntity.entity.getUrl().equals(entity.getUrl())) { //处理地址切换而保存路径不变
|
||||
taskEntity.save(entity);
|
||||
private DownloadTaskEntity create(DownloadEntity entity) {
|
||||
List<DownloadTaskWrapper> wrapper = DbEntity.findRelationData(DownloadTaskWrapper.class,
|
||||
"DownloadTaskEntity.key=? and DownloadTaskEntity.isGroupTask='false' and DownloadTaskEntity.url=?",
|
||||
entity.getDownloadPath(), entity.getUrl());
|
||||
|
||||
if (wrapper != null && !wrapper.isEmpty()) {
|
||||
DownloadTaskEntity taskEntity = wrapper.get(0).taskEntity;
|
||||
if (taskEntity == null) {
|
||||
taskEntity = new DownloadTaskEntity();
|
||||
taskEntity.entity = entity;
|
||||
} else if (taskEntity.entity == null || TextUtils.isEmpty(taskEntity.entity.getUrl())) {
|
||||
taskEntity.entity = entity;
|
||||
}
|
||||
|
||||
return taskEntity;
|
||||
} else {
|
||||
DownloadTaskEntity taskEntity = new DownloadTaskEntity();
|
||||
taskEntity.entity = entity;
|
||||
return taskEntity;
|
||||
}
|
||||
return taskEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,10 +22,6 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
* Created by Aria.Lao on 2017/11/1.
|
||||
*/
|
||||
interface ITEntityFactory<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> {
|
||||
/**
|
||||
* 通过信息实体创建任务实体
|
||||
*/
|
||||
TASK_ENTITY create(ENTITY entity);
|
||||
|
||||
/**
|
||||
* 通过key创建任务,只适应于单任务
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.arialyy.aria.core.manager;
|
||||
import android.support.v4.util.LruCache;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
|
||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||
import com.arialyy.aria.core.inf.AbsEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.core.upload.UploadTaskEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
@@ -29,7 +28,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/11/1.
|
||||
* 任务实体管理器,负责
|
||||
* 任务实体管理器
|
||||
*/
|
||||
public class TEManager {
|
||||
private static final String TAG = "TaskManager";
|
||||
@@ -102,31 +101,6 @@ public class TEManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过实体创建任务
|
||||
*
|
||||
* @return 如果任务实体创建失败,返回null
|
||||
*/
|
||||
public <TE extends AbsTaskEntity> TE createTEntity(Class<TE> clazz, AbsEntity absEntity) {
|
||||
final Lock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
AbsTaskEntity tEntity = cache.get(convertKey(absEntity.getKey()));
|
||||
if (tEntity == null || tEntity.getClass() != clazz) {
|
||||
ITEntityFactory factory = chooseFactory(clazz);
|
||||
if (factory == null) {
|
||||
ALog.e(TAG, "任务实体创建失败");
|
||||
return null;
|
||||
}
|
||||
tEntity = factory.create(absEntity);
|
||||
cache.put(convertKey(absEntity.getKey()), tEntity);
|
||||
}
|
||||
return (TE) tEntity;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private IGTEntityFactory chooseGroupFactory(Class clazz) {
|
||||
if (clazz == DownloadGroupTaskEntity.class) {
|
||||
return DGTEntityFactory.getInstance();
|
||||
@@ -146,7 +120,9 @@ public class TEManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从任务实体管理器中获取任务实体
|
||||
* 从缓存中获取任务实体,如果任务实体不存在,则创建任务实体
|
||||
*
|
||||
* @return 创建失败,返回null
|
||||
*/
|
||||
public <TE extends AbsTaskEntity> TE getTEntity(Class<TE> clazz, String key) {
|
||||
final Lock lock = this.lock;
|
||||
@@ -154,7 +130,33 @@ public class TEManager {
|
||||
try {
|
||||
AbsTaskEntity tEntity = cache.get(convertKey(key));
|
||||
if (tEntity == null) {
|
||||
return null;
|
||||
return createTEntity(clazz, key);
|
||||
} else {
|
||||
return (TE) tEntity;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获取HTTP任务组的任务实体,如果任务实体不存在,则创建任务实体
|
||||
*
|
||||
* @param urls HTTP任务组的子任务下载地址列表
|
||||
* @return 地址列表为null或创建实体失败,返回null
|
||||
*/
|
||||
public <TE extends AbsTaskEntity> TE getGTEntity(Class<TE> clazz, List<String> urls) {
|
||||
if (urls == null || urls.isEmpty()) {
|
||||
ALog.e(TAG, "获取HTTP任务组实体失败:任务组的子任务下载地址列表为null");
|
||||
return null;
|
||||
}
|
||||
final Lock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
String groupName = CommonUtil.getMd5Code(urls);
|
||||
AbsTaskEntity tEntity = cache.get(convertKey(groupName));
|
||||
if (tEntity == null) {
|
||||
return createGTEntity(clazz, urls);
|
||||
} else {
|
||||
return (TE) tEntity;
|
||||
}
|
||||
@@ -189,7 +191,7 @@ public class TEManager {
|
||||
final Lock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return cache.put(convertKey(te.key), te) != null;
|
||||
return cache.put(convertKey(te.getKey()), te) != null;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.manager;
|
||||
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.inf.AbsTask;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/9/1.
|
||||
* 任务管理器
|
||||
*/
|
||||
class TaskManager {
|
||||
private static final String TAG = "TaskManager";
|
||||
private static volatile TaskManager INSTANCE = null;
|
||||
private Map<String, AbsTask> map = new ConcurrentHashMap<>();
|
||||
|
||||
public static TaskManager getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (TaskManager.class) {
|
||||
INSTANCE = new TaskManager();
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private TaskManager() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理器添加任务
|
||||
*
|
||||
* @param key 任务的key,下载为保存路径,任务组为任务组名,上传为文件上传路径
|
||||
* @param task 任务
|
||||
* @return {@code true}添加成功
|
||||
*/
|
||||
public <T extends AbsTask> boolean addTask(String key, Class<T> clazz, T task) {
|
||||
String hash = CommonUtil.keyToHashKey(key);
|
||||
if (map.keySet().contains(hash)) {
|
||||
ALog.e(TAG, "任务【" + key + "】已存在");
|
||||
return false;
|
||||
}
|
||||
map.put(CommonUtil.keyToHashKey(key), task);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除任务
|
||||
*
|
||||
* @param key 任务的key,下载为保存路径,任务组为任务组名,上传为文件上传路径
|
||||
*/
|
||||
public void removeTask(String key) {
|
||||
String hash = CommonUtil.keyToHashKey(key);
|
||||
for (Iterator<Map.Entry<String, AbsTask>> iter = map.entrySet().iterator(); iter.hasNext(); ) {
|
||||
Map.Entry<String, AbsTask> entry = iter.next();
|
||||
if (entry.getKey().equals(hash)) iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过key获取任务
|
||||
*
|
||||
* @return 如果找不到任务,返回null,否则返回key对应的任务
|
||||
*/
|
||||
public AbsTask getTask(String key) {
|
||||
return map.get(CommonUtil.keyToHashKey(key));
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,13 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.manager;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.upload.UploadTaskEntity;
|
||||
import com.arialyy.aria.core.upload.UploadTaskWrapper;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.Regular;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -41,17 +44,26 @@ class UTEntityFactory implements ITEntityFactory<UploadEntity, UploadTaskEntity>
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override public UploadTaskEntity create(UploadEntity entity) {
|
||||
UploadTaskEntity uTaskEntity =
|
||||
DbEntity.findFirst(UploadTaskEntity.class, "key=?", entity.getFilePath());
|
||||
if (uTaskEntity == null) {
|
||||
uTaskEntity = new UploadTaskEntity();
|
||||
private UploadTaskEntity create(UploadEntity entity) {
|
||||
List<UploadTaskWrapper> wrapper =
|
||||
DbEntity.findRelationData(UploadTaskWrapper.class, "UploadTaskEntity.key=?",
|
||||
entity.getFilePath());
|
||||
|
||||
if (wrapper != null && !wrapper.isEmpty()) {
|
||||
UploadTaskEntity uTaskEntity = wrapper.get(0).taskEntity;
|
||||
if (uTaskEntity == null) {
|
||||
uTaskEntity = new UploadTaskEntity();
|
||||
uTaskEntity.entity = entity;
|
||||
} else if (uTaskEntity.entity == null || TextUtils.isEmpty(
|
||||
uTaskEntity.entity.getFilePath())) {
|
||||
uTaskEntity.entity = entity;
|
||||
}
|
||||
return uTaskEntity;
|
||||
} else {
|
||||
UploadTaskEntity uTaskEntity = new UploadTaskEntity();
|
||||
uTaskEntity.entity = entity;
|
||||
return uTaskEntity;
|
||||
}
|
||||
if (uTaskEntity.entity == null) {
|
||||
uTaskEntity.entity = entity;
|
||||
}
|
||||
return uTaskEntity;
|
||||
}
|
||||
|
||||
@Override public UploadTaskEntity create(String key) {
|
||||
@@ -67,14 +79,12 @@ class UTEntityFactory implements ITEntityFactory<UploadEntity, UploadTaskEntity>
|
||||
UploadEntity entity = UploadEntity.findFirst(UploadEntity.class, "filePath=?", filePath);
|
||||
if (entity == null) {
|
||||
entity = new UploadEntity();
|
||||
//String regex = "[/|\\\\|//]";
|
||||
String regex = Regular.REG_FILE_NAME;
|
||||
Pattern p = Pattern.compile(regex);
|
||||
String[] strs = p.split(filePath);
|
||||
String fileName = strs[strs.length - 1];
|
||||
entity.setFileName(fileName);
|
||||
entity.setFilePath(filePath);
|
||||
entity.insert();
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class DownloadGroupTaskQueue
|
||||
&& mExecutePool.getTask(entity.getEntity().getKey()) == null) {
|
||||
task = (DownloadGroupTask) TaskFactory.getInstance()
|
||||
.createTask(targetName, entity, DownloadGroupSchedulers.getInstance());
|
||||
entity.key = entity.getEntity().getGroupName();
|
||||
entity.setKey(entity.getEntity().getGroupName());
|
||||
mCachePool.putTask(task);
|
||||
} else {
|
||||
ALog.w(TAG, "任务已存在");
|
||||
|
||||
@@ -17,12 +17,9 @@ package com.arialyy.aria.core.upload;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.manager.TEManager;
|
||||
import com.arialyy.aria.core.queue.UploadTaskQueue;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
@@ -30,13 +27,9 @@ import java.io.File;
|
||||
*/
|
||||
abstract class BaseNormalTarget<TARGET extends AbsUploadTarget>
|
||||
extends AbsUploadTarget<TARGET, UploadEntity, UploadTaskEntity> {
|
||||
private static final String TAG = "BaseNormalTarget";
|
||||
|
||||
protected void initTarget(String filePath) {
|
||||
mTaskEntity = TEManager.getInstance().getTEntity(UploadTaskEntity.class, filePath);
|
||||
if (mTaskEntity == null) {
|
||||
mTaskEntity = TEManager.getInstance().createTEntity(UploadTaskEntity.class, filePath);
|
||||
}
|
||||
mEntity = mTaskEntity.entity;
|
||||
File file = new File(filePath);
|
||||
mEntity.setFileName(file.getName());
|
||||
@@ -74,7 +67,11 @@ abstract class BaseNormalTarget<TARGET extends AbsUploadTarget>
|
||||
}
|
||||
|
||||
@Override protected boolean checkEntity() {
|
||||
return checkUrl() && checkFilePath();
|
||||
boolean b = checkUrl() && checkFilePath();
|
||||
if (b) {
|
||||
mTaskEntity.save(mEntity);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,6 @@ import com.arialyy.aria.util.CommonUtil;
|
||||
*/
|
||||
public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
|
||||
implements IFtpTarget<FtpUploadTarget> {
|
||||
private final String TAG = "FtpUploadTarget";
|
||||
private FtpDelegate<FtpUploadTarget, UploadEntity, UploadTaskEntity> mDelegate;
|
||||
|
||||
FtpUploadTarget(String filePath, String targetName) {
|
||||
@@ -51,14 +50,15 @@ public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
|
||||
*/
|
||||
@Override
|
||||
public FtpUploadTarget setUploadUrl(@NonNull String uploadUrl) {
|
||||
uploadUrl = CheckUtil.checkUrl(uploadUrl);
|
||||
if (!CheckUtil.checkUrl(uploadUrl)) {
|
||||
return this;
|
||||
}
|
||||
if (!uploadUrl.endsWith("/")) {
|
||||
uploadUrl += "/";
|
||||
}
|
||||
mTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(uploadUrl);
|
||||
if (mEntity.getUrl().equals(uploadUrl)) return this;
|
||||
mEntity.setUrl(uploadUrl);
|
||||
mEntity.update();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,15 +19,18 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import com.arialyy.aria.core.inf.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.orm.Foreign;
|
||||
import com.arialyy.aria.orm.Primary;
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/2/9.
|
||||
* 上传文件实体
|
||||
*/
|
||||
public class UploadEntity extends AbsNormalEntity implements Parcelable {
|
||||
@Primary @Foreign(table = UploadTaskEntity.class, column = "key") private String filePath; //文件路径
|
||||
/**
|
||||
* 文件上传路径
|
||||
*/
|
||||
@Primary @Foreign(parent = UploadTaskEntity.class, column = "key") private String filePath;
|
||||
|
||||
/**
|
||||
* 上传完成后服务器返回的数据
|
||||
|
||||
@@ -20,9 +20,7 @@ import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.command.ICmd;
|
||||
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
|
||||
import com.arialyy.aria.core.common.ProxyHelper;
|
||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||
import com.arialyy.aria.core.inf.AbsReceiver;
|
||||
import com.arialyy.aria.core.scheduler.ISchedulerListener;
|
||||
import com.arialyy.aria.core.scheduler.UploadSchedulers;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
@@ -92,7 +90,7 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
|
||||
@Override public void removeAllTask(boolean removeFile) {
|
||||
final AriaManager am = AriaManager.getInstance(AriaManager.APP);
|
||||
|
||||
am.setCmd(CommonUtil.createNormalCmd(targetName, new DownloadTaskEntity(),
|
||||
am.setCmd(CommonUtil.createNormalCmd(targetName, new UploadTaskEntity(),
|
||||
NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_UPLOAD)).exe();
|
||||
|
||||
Set<String> keys = am.getReceiver().keySet();
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.util.Map;
|
||||
*/
|
||||
public class UploadTarget extends BaseNormalTarget<UploadTarget>
|
||||
implements IHttpHeaderTarget<UploadTarget> {
|
||||
private static final String TAG = "UploadTarget";
|
||||
private HttpHeaderDelegate<UploadTarget, UploadEntity, UploadTaskEntity> mDelegate;
|
||||
|
||||
UploadTarget(String filePath, String targetName) {
|
||||
@@ -47,12 +46,13 @@ public class UploadTarget extends BaseNormalTarget<UploadTarget>
|
||||
}
|
||||
|
||||
@Override public UploadTarget setUploadUrl(@NonNull String uploadUrl) {
|
||||
uploadUrl = CheckUtil.checkUrl(uploadUrl);
|
||||
if (!CheckUtil.checkUrl(uploadUrl)){
|
||||
return this;
|
||||
}
|
||||
if (mEntity.getUrl().equals(uploadUrl)) {
|
||||
return this;
|
||||
}
|
||||
mEntity.setUrl(uploadUrl);
|
||||
mEntity.update();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.upload;
|
||||
|
||||
import com.arialyy.aria.orm.AbsWrapper;
|
||||
import com.arialyy.aria.orm.annotation.Many;
|
||||
import com.arialyy.aria.orm.annotation.One;
|
||||
import com.arialyy.aria.orm.annotation.Wrapper;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/30.
|
||||
*/
|
||||
@Wrapper
|
||||
public class UploadTaskWrapper extends AbsWrapper {
|
||||
|
||||
@One
|
||||
public UploadEntity entity;
|
||||
|
||||
@Many(parentColumn = "filePath", entityColumn = "key")
|
||||
private List<UploadTaskEntity> taskEntitys = null;
|
||||
|
||||
public UploadTaskEntity taskEntity;
|
||||
|
||||
@Override public void handleConvert() {
|
||||
//taskEntity.entity = (tEntity == null || tEntity.isEmpty()) ? null : tEntity.get(0);
|
||||
taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0);
|
||||
if (taskEntity != null) {
|
||||
taskEntity.entity = entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
162
Aria/src/main/java/com/arialyy/aria/orm/AbsDelegate.java
Normal file
162
Aria/src/main/java/com/arialyy/aria/orm/AbsDelegate.java
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.v4.util.LruCache;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/22.
|
||||
*/
|
||||
abstract class AbsDelegate {
|
||||
static final String TAG = "AbsDelegate";
|
||||
static final int CREATE_TABLE = 0;
|
||||
static final int TABLE_EXISTS = 1;
|
||||
static final int INSERT_DATA = 2;
|
||||
static final int MODIFY_DATA = 3;
|
||||
static final int FIND_DATA = 4;
|
||||
static final int FIND_ALL_DATA = 5;
|
||||
static final int DEL_DATA = 6;
|
||||
static final int ROW_ID = 7;
|
||||
static final int RELATION = 8;
|
||||
static final int DROP_TABLE = 9;
|
||||
|
||||
static LruCache<String, DbEntity> mDataCache = new LruCache<>(1024);
|
||||
|
||||
/**
|
||||
* 打印数据库日志
|
||||
*
|
||||
* @param type {@link DelegateWrapper}
|
||||
*/
|
||||
static void print(int type, String sql) {
|
||||
if (!ALog.DEBUG) {
|
||||
return;
|
||||
}
|
||||
String str = "";
|
||||
switch (type) {
|
||||
case CREATE_TABLE:
|
||||
str = "创建表 >>>> ";
|
||||
break;
|
||||
case TABLE_EXISTS:
|
||||
str = "表是否存在 >>>> ";
|
||||
break;
|
||||
case INSERT_DATA:
|
||||
str = "插入数据 >>>> ";
|
||||
break;
|
||||
case MODIFY_DATA:
|
||||
str = "修改数据 >>>> ";
|
||||
break;
|
||||
case FIND_DATA:
|
||||
str = "查询一行数据 >>>> ";
|
||||
break;
|
||||
case FIND_ALL_DATA:
|
||||
str = "遍历整个数据库 >>>> ";
|
||||
break;
|
||||
case ROW_ID:
|
||||
str = "查询RowId >>> ";
|
||||
break;
|
||||
case RELATION:
|
||||
str = "查询关联表 >>> ";
|
||||
break;
|
||||
case DROP_TABLE:
|
||||
str = "删除表 >>> ";
|
||||
break;
|
||||
}
|
||||
ALog.d(TAG, str.concat(sql));
|
||||
}
|
||||
|
||||
String getCacheKey(DbEntity dbEntity) {
|
||||
return dbEntity.getClass().getName() + "_" + dbEntity.rowID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查list参数是否合法,list只能是{@code List<String>}
|
||||
*
|
||||
* @return {@code true} 合法
|
||||
*/
|
||||
boolean checkList(Field list) {
|
||||
Class t = CommonUtil.getListParamType(list);
|
||||
if (t != null && t == String.class) {
|
||||
return true;
|
||||
} else {
|
||||
ALog.d(TAG, "map参数错误,支持List<String>的参数字段");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查map参数是否合法,map只能是{@code Map<String, String>}
|
||||
*
|
||||
* @return {@code true} 合法
|
||||
*/
|
||||
boolean checkMap(Field map) {
|
||||
Class[] ts = CommonUtil.getMapParamType(map);
|
||||
if (ts != null
|
||||
&& ts[0] != null
|
||||
&& ts[1] != null
|
||||
&& ts[0] == String.class
|
||||
&& ts[1] == String.class) {
|
||||
return true;
|
||||
} else {
|
||||
ALog.d(TAG, "map参数错误,支持Map<String,String>的参数字段");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为了防止特殊字符串导致存储失败,需要使用URL编码保存的字符串
|
||||
*
|
||||
* @param value 需要保存的内容
|
||||
* @return 转换后的内容
|
||||
*/
|
||||
String convertValue(String value) {
|
||||
if (value.contains("'")) {
|
||||
return URLEncoder.encode(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void closeCursor(Cursor cursor) {
|
||||
if (cursor != null && !cursor.isClosed()) {
|
||||
try {
|
||||
cursor.close();
|
||||
} catch (android.database.SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void close(SQLiteDatabase db) {
|
||||
//if (db != null && db.isOpen()) db.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据库是否关闭,已经关闭的话,打开数据库
|
||||
*
|
||||
* @return 返回数据库
|
||||
*/
|
||||
SQLiteDatabase checkDb(SQLiteDatabase db) {
|
||||
if (db == null || !db.isOpen()) {
|
||||
db = SqlHelper.INSTANCE.getWritableDatabase();
|
||||
}
|
||||
return db;
|
||||
}
|
||||
}
|
||||
@@ -13,22 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core;
|
||||
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/10/17.
|
||||
* Url 映射表
|
||||
* Created by laoyuyu on 2018/3/30.
|
||||
*/
|
||||
public class UrlMapping extends DbEntity {
|
||||
/**
|
||||
* 各实体对应的key
|
||||
*/
|
||||
public String key;
|
||||
public abstract class AbsWrapper {
|
||||
|
||||
/**
|
||||
* 链接
|
||||
* 处理转换
|
||||
*/
|
||||
public String url;
|
||||
protected abstract void handleConvert();
|
||||
}
|
||||
62
Aria/src/main/java/com/arialyy/aria/orm/ActionPolicy.java
Normal file
62
Aria/src/main/java/com/arialyy/aria/orm/ActionPolicy.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/22.
|
||||
* on update 或 on delete 都可跟不同action功能
|
||||
*
|
||||
* @see <a href="https://sqlite.org/foreignkeys.html"></a>
|
||||
* {@link Foreign#onDelete()}、{@link Foreign#onUpdate()}
|
||||
*/
|
||||
public enum ActionPolicy {
|
||||
|
||||
/**
|
||||
* 如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
|
||||
*/
|
||||
NO_ACTION("NO ACTION"),
|
||||
|
||||
/**
|
||||
* 和NO ACTION 作用一致,和NO ACTION的区别是:
|
||||
* 主表update/delete执行时,马上就触发约束;
|
||||
* 而NO ACTION 是执行完成语句后才触发约束,
|
||||
*/
|
||||
RESTRICT("RESTRICT"),
|
||||
|
||||
/**
|
||||
* 在父表上update/delete记录时,将子表上匹配记录的列设为null (要注意子表的外键列不能为not null)
|
||||
*/
|
||||
SET_NULL("SET NULL"),
|
||||
|
||||
/**
|
||||
* 父表有变更时,子表将外键列设置成一个默认的值,default配置的值
|
||||
*/
|
||||
SET_DEFAULT("SET DEFAULT"),
|
||||
|
||||
/**
|
||||
* 在父表上update/delete记录时,同步update/delete掉子表的匹配记录
|
||||
*/
|
||||
CASCADE("CASCADE");
|
||||
|
||||
String function;
|
||||
|
||||
ActionPolicy(String function) {
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,6 @@ package com.arialyy.aria.orm;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.ErrorEntity;
|
||||
import com.arialyy.aria.core.UrlMapping;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
|
||||
@@ -34,7 +33,7 @@ import java.util.Map;
|
||||
class DBConfig {
|
||||
static Map<String, Class> mapping = new HashMap<>();
|
||||
static String DB_NAME;
|
||||
static int VERSION = 25;
|
||||
static int VERSION = 31;
|
||||
|
||||
static {
|
||||
if (TextUtils.isEmpty(DB_NAME)) {
|
||||
@@ -46,13 +45,12 @@ class DBConfig {
|
||||
}
|
||||
|
||||
static {
|
||||
mapping.put("DownloadEntity", DownloadEntity.class);
|
||||
mapping.put("DownloadGroupTaskEntity", DownloadGroupTaskEntity.class);
|
||||
mapping.put("DownloadGroupEntity", DownloadGroupEntity.class);
|
||||
mapping.put("DownloadTaskEntity", DownloadTaskEntity.class);
|
||||
mapping.put("DownloadGroupTaskEntity", DownloadGroupTaskEntity.class);
|
||||
mapping.put("UploadEntity", UploadEntity.class);
|
||||
mapping.put("UploadTaskEntity", UploadTaskEntity.class);
|
||||
mapping.put("DownloadEntity", DownloadEntity.class);
|
||||
mapping.put("UploadEntity", UploadEntity.class);
|
||||
mapping.put("ErrorEntity", ErrorEntity.class);
|
||||
//mapping.put("UrlMapping", UrlMapping.class);
|
||||
}
|
||||
}
|
||||
|
||||
110
Aria/src/main/java/com/arialyy/aria/orm/DatabaseContext.java
Normal file
110
Aria/src/main/java/com/arialyy/aria/orm/DatabaseContext.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.database.DatabaseErrorHandler;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Environment;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 保存在sd卡的数据库使用的Context
|
||||
*/
|
||||
class DatabaseContext extends ContextWrapper {
|
||||
public DatabaseContext(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得数据库路径,如果不存在,则创建对象对象
|
||||
*/
|
||||
@Override
|
||||
public File getDatabasePath(String name) {
|
||||
//判断是否存在sd卡
|
||||
boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals(
|
||||
android.os.Environment.getExternalStorageState());
|
||||
if (!sdExist) {
|
||||
return null;
|
||||
} else {
|
||||
//获取sd卡路径
|
||||
File file = getBaseContext().getExternalFilesDir(null);
|
||||
String dbDir;
|
||||
if (file != null) {
|
||||
dbDir = file.getPath() + "/";
|
||||
} else {
|
||||
dbDir = Environment.getExternalStorageDirectory().getPath()
|
||||
+ "/Android/data/"
|
||||
+ getBaseContext().getPackageName()
|
||||
+ "/files/";
|
||||
}
|
||||
|
||||
dbDir += "DB";//数据库所在目录
|
||||
String dbPath = dbDir + "/" + name;//数据库路径
|
||||
//判断目录是否存在,不存在则创建该目录
|
||||
File dirFile = new File(dbDir);
|
||||
if (!dirFile.exists()) {
|
||||
dirFile.mkdirs();
|
||||
}
|
||||
|
||||
//数据库文件是否创建成功
|
||||
boolean isFileCreateSuccess = false;
|
||||
//判断文件是否存在,不存在则创建该文件
|
||||
File dbFile = new File(dbPath);
|
||||
if (!dbFile.exists()) {
|
||||
try {
|
||||
isFileCreateSuccess = dbFile.createNewFile();//创建文件
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
isFileCreateSuccess = true;
|
||||
}
|
||||
|
||||
//返回数据库文件对象
|
||||
if (isFileCreateSuccess) {
|
||||
return dbFile;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载这个方法,是用来打开SD卡上的数据库的,android 2.3及以下会调用这个方法。
|
||||
*/
|
||||
@Override
|
||||
public SQLiteDatabase openOrCreateDatabase(String name, int mode,
|
||||
SQLiteDatabase.CursorFactory factory) {
|
||||
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Android 4.0会调用此方法获取数据库。
|
||||
*
|
||||
* @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int,
|
||||
* android.database.sqlite.SQLiteDatabase.CursorFactory,
|
||||
* android.database.DatabaseErrorHandler)
|
||||
*/
|
||||
@Override
|
||||
public SQLiteDatabase openOrCreateDatabase(String name, int mode,
|
||||
SQLiteDatabase.CursorFactory factory,
|
||||
DatabaseErrorHandler errorHandler) {
|
||||
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import java.util.Map;
|
||||
* Created by lyy on 2015/11/2.
|
||||
* 所有数据库实体父类
|
||||
*/
|
||||
public class DbEntity {
|
||||
public abstract class DbEntity {
|
||||
private static final Object LOCK = new Object();
|
||||
protected int rowID = -1;
|
||||
|
||||
@@ -36,15 +36,14 @@ public class DbEntity {
|
||||
|
||||
}
|
||||
|
||||
///**
|
||||
// * 关键字模糊检索全文
|
||||
// *
|
||||
// * @param column 需要查找的列
|
||||
// * @param mathSql 关键字语法,exsimple “white OR green”、“blue AND red”、“white NOT green”
|
||||
// */
|
||||
//public static <T extends DbEntity> List<T> searchData(Class<T> clazz, String column, String mathSql) {
|
||||
// return DbUtil.getInstance().searchData(clazz, column, mathSql);
|
||||
//}
|
||||
/**
|
||||
* 查询关联数据
|
||||
*
|
||||
* @param expression 查询条件
|
||||
*/
|
||||
public static <T extends AbsWrapper> List<T> findRelationData(Class<T> clazz, String... expression) {
|
||||
return DelegateWrapper.getInstance().findRelationData(clazz, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查某个字段的值是否存在
|
||||
@@ -53,21 +52,21 @@ public class DbEntity {
|
||||
* @return {@code true}该字段的对应的value已存在
|
||||
*/
|
||||
public static boolean checkDataExist(Class clazz, String... expression) {
|
||||
return DbUtil.getInstance().checkDataExist(clazz, expression);
|
||||
return DelegateWrapper.getInstance().checkDataExist(clazz, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空表数据
|
||||
*/
|
||||
public static <T extends DbEntity> void clean(Class<T> clazz) {
|
||||
DbUtil.getInstance().clean(clazz);
|
||||
DelegateWrapper.getInstance().clean(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接执行sql语句
|
||||
*/
|
||||
public static void exeSql(String sql) {
|
||||
DbUtil.getInstance().exeSql(sql);
|
||||
DelegateWrapper.getInstance().exeSql(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +75,7 @@ public class DbEntity {
|
||||
* @return 没有数据返回null
|
||||
*/
|
||||
public static <T extends DbEntity> List<T> findAllData(Class<T> clazz) {
|
||||
DbUtil util = DbUtil.getInstance();
|
||||
DelegateWrapper util = DelegateWrapper.getInstance();
|
||||
return util.findAllData(clazz);
|
||||
}
|
||||
|
||||
@@ -97,7 +96,7 @@ public class DbEntity {
|
||||
* @return 没有数据返回null
|
||||
*/
|
||||
public static <T extends DbEntity> List<T> findDatas(Class<T> clazz, String... expression) {
|
||||
DbUtil util = DbUtil.getInstance();
|
||||
DelegateWrapper util = DelegateWrapper.getInstance();
|
||||
return util.findData(clazz, expression);
|
||||
}
|
||||
|
||||
@@ -110,7 +109,7 @@ public class DbEntity {
|
||||
* @return 没有数据返回null
|
||||
*/
|
||||
public static <T extends DbEntity> T findFirst(Class<T> clazz, String... expression) {
|
||||
DbUtil util = DbUtil.getInstance();
|
||||
DelegateWrapper util = DelegateWrapper.getInstance();
|
||||
List<T> datas = util.findData(clazz, expression);
|
||||
return datas == null ? null : datas.size() > 0 ? datas.get(0) : null;
|
||||
}
|
||||
@@ -119,14 +118,14 @@ public class DbEntity {
|
||||
* 获取所有行的rowid
|
||||
*/
|
||||
public int[] getRowIds() {
|
||||
return DbUtil.getInstance().getRowId(getClass());
|
||||
return DelegateWrapper.getInstance().getRowId(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取rowid
|
||||
*/
|
||||
public int getRowId(@NonNull Object[] wheres, @NonNull Object[] values) {
|
||||
return DbUtil.getInstance().getRowId(getClass(), wheres, values);
|
||||
return DelegateWrapper.getInstance().getRowId(getClass(), wheres, values);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,7 +142,7 @@ public class DbEntity {
|
||||
* </code>
|
||||
*/
|
||||
public static <T extends DbEntity> void deleteData(Class<T> clazz, String... expression) {
|
||||
DbUtil util = DbUtil.getInstance();
|
||||
DelegateWrapper util = DelegateWrapper.getInstance();
|
||||
util.delData(clazz, expression);
|
||||
}
|
||||
|
||||
@@ -151,7 +150,7 @@ public class DbEntity {
|
||||
* 修改数据
|
||||
*/
|
||||
public void update() {
|
||||
DbUtil.getInstance().modifyData(this);
|
||||
DelegateWrapper.getInstance().modifyData(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,7 +170,7 @@ public class DbEntity {
|
||||
* 查找数据在表中是否存在
|
||||
*/
|
||||
private boolean thisIsExist() {
|
||||
DbUtil util = DbUtil.getInstance();
|
||||
DelegateWrapper util = DelegateWrapper.getInstance();
|
||||
return util.isExist(getClass(), rowID);
|
||||
}
|
||||
|
||||
@@ -179,45 +178,38 @@ public class DbEntity {
|
||||
* 插入数据
|
||||
*/
|
||||
public void insert() {
|
||||
DbUtil.getInstance().insertData(this);
|
||||
DelegateWrapper.getInstance().insertData(this);
|
||||
updateRowID();
|
||||
}
|
||||
|
||||
private <T extends DbEntity> T findFirst(Class<T> clazz, @NonNull String[] wheres,
|
||||
@NonNull String[] values) {
|
||||
DbUtil util = DbUtil.getInstance();
|
||||
List<T> list = util.findData(clazz, wheres, values);
|
||||
return list == null ? null : list.get(0);
|
||||
}
|
||||
|
||||
private void updateRowID() {
|
||||
try {
|
||||
List<Field> fields = CommonUtil.getAllFields(getClass());
|
||||
List<String> where = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
List<String> params = new ArrayList<>();
|
||||
List<String> values = new ArrayList<>();
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (SqlUtil.ignoreField(field)) {
|
||||
if (SqlUtil.isIgnore(field)) {
|
||||
continue;
|
||||
}
|
||||
where.add(field.getName());
|
||||
sb.append(field.getName()).append("=? AND ");
|
||||
Type type = field.getType();
|
||||
if (SqlUtil.isOneToOne(field)) {
|
||||
values.add(SqlUtil.getOneToOneParams(field));
|
||||
} else if (type == List.class) {
|
||||
if (SqlUtil.isOneToMany(field)) {
|
||||
values.add(SqlUtil.getOneToManyElementParams(field));
|
||||
} else {
|
||||
values.add(SqlUtil.list2Str(this, field));
|
||||
}
|
||||
if (type == List.class) {
|
||||
values.add(SqlUtil.list2Str(this, field));
|
||||
} else if (type == Map.class) {
|
||||
values.add(SqlUtil.map2Str((Map<String, String>) field.get(this)));
|
||||
} else {
|
||||
values.add(field.get(this) + "");
|
||||
}
|
||||
}
|
||||
DbEntity entity = findFirst(getClass(), where.toArray(new String[where.size()]),
|
||||
values.toArray(new String[values.size()]));
|
||||
|
||||
String temp = sb.toString();
|
||||
String p = temp.substring(0, temp.length() - 5);
|
||||
|
||||
params.add(p);
|
||||
params.addAll(values);
|
||||
DbEntity entity = findFirst(getClass(), params.toArray(new String[params.size()]));
|
||||
if (entity != null) {
|
||||
rowID = entity.rowID;
|
||||
}
|
||||
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.NonNull;
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/2/11.
|
||||
* 数据库操作工具
|
||||
*/
|
||||
public class DbUtil {
|
||||
private static final String TAG = "DbUtil";
|
||||
private volatile static DbUtil INSTANCE = null;
|
||||
private int ROW_ID = 7;
|
||||
private SQLiteDatabase mDb;
|
||||
private SqlHelper mHelper;
|
||||
|
||||
private DbUtil() {
|
||||
|
||||
}
|
||||
|
||||
private DbUtil(Context context) {
|
||||
mHelper = SqlHelper.init(context.getApplicationContext());
|
||||
}
|
||||
|
||||
public static DbUtil init(Context context) {
|
||||
if (context instanceof Application) {
|
||||
synchronized (AriaManager.LOCK) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new DbUtil(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
protected static DbUtil getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
throw new NullPointerException("请在Application中调用init进行数据库工具注册注册");
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
///**
|
||||
// * 关键字模糊检索全文
|
||||
// *
|
||||
// * @param column 需要查找的列
|
||||
// * @param mathSql 关键字语法,exsimple “white OR green”、“blue AND red”、“white NOT green”
|
||||
// */
|
||||
//public <T extends DbEntity> List<T> searchData(Class<T> clazz, String column, String mathSql) {
|
||||
// checkDb();
|
||||
// return SqlHelper.searchData(mDb, clazz, column, mathSql);
|
||||
//}
|
||||
|
||||
/**
|
||||
* 检查某个字段的值是否存在
|
||||
*
|
||||
* @param expression 字段和值"url=xxx"
|
||||
* @return {@code true}该字段的对应的value已存在
|
||||
*/
|
||||
synchronized boolean checkDataExist(Class clazz, String... expression) {
|
||||
checkDb();
|
||||
return SqlHelper.checkDataExist(mDb, clazz, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空表数据
|
||||
*/
|
||||
synchronized <T extends DbEntity> void clean(Class<T> clazz) {
|
||||
checkDb();
|
||||
String tableName = CommonUtil.getClassName(clazz);
|
||||
if (tableExists(clazz)) {
|
||||
String sql = "DELETE FROM " + tableName;
|
||||
exeSql(sql);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行sql语句
|
||||
*/
|
||||
void exeSql(String sql) {
|
||||
mDb.execSQL(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除某条数据
|
||||
*/
|
||||
synchronized <T extends DbEntity> void delData(Class<T> clazz, String... expression) {
|
||||
CheckUtil.checkSqlExpression(expression);
|
||||
checkDb();
|
||||
SqlHelper.delData(mDb, clazz, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改某行数据
|
||||
*/
|
||||
synchronized void modifyData(DbEntity dbEntity) {
|
||||
checkDb();
|
||||
SqlHelper.modifyData(mDb, dbEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历所有数据
|
||||
*/
|
||||
synchronized <T extends DbEntity> List<T> findAllData(Class<T> clazz) {
|
||||
checkDb();
|
||||
return SqlHelper.findAllData(mDb, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件查寻数据
|
||||
*/
|
||||
synchronized <T extends DbEntity> List<T> findData(Class<T> clazz, String... expression) {
|
||||
checkDb();
|
||||
return SqlHelper.findData(mDb, clazz, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过rowId判断数据是否存在
|
||||
*/
|
||||
synchronized <T extends DbEntity> boolean isExist(Class<T> clazz, int rowId) {
|
||||
checkDb();
|
||||
String sql = "SELECT rowid FROM " + CommonUtil.getClassName(clazz) + " WHERE rowid=" + rowId;
|
||||
Cursor cursor = mDb.rawQuery(sql, null);
|
||||
boolean isExist = cursor.getCount() > 0;
|
||||
cursor.close();
|
||||
return isExist;
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件查寻数据
|
||||
*/
|
||||
@Deprecated synchronized <T extends DbEntity> List<T> findData(Class<T> clazz,
|
||||
@NonNull String[] wheres, @NonNull String[] values) {
|
||||
checkDb();
|
||||
return SqlHelper.findData(mDb, clazz, wheres, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
synchronized void insertData(DbEntity dbEntity) {
|
||||
checkDb();
|
||||
SqlHelper.insertData(mDb, dbEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找某张表是否存在
|
||||
*/
|
||||
synchronized boolean tableExists(Class clazz) {
|
||||
checkDb();
|
||||
return SqlHelper.tableExists(mDb, clazz);
|
||||
}
|
||||
|
||||
synchronized void createTable(Class clazz, String tableName) {
|
||||
checkDb();
|
||||
SqlHelper.createTable(mDb, clazz, tableName);
|
||||
}
|
||||
|
||||
private void checkDb() {
|
||||
if (mDb == null || !mDb.isOpen()) {
|
||||
mDb = mHelper.getReadableDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表
|
||||
*/
|
||||
private synchronized void createTable(Class clazz) {
|
||||
createTable(clazz, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭数据库
|
||||
*/
|
||||
private synchronized void close() {
|
||||
if (mDb != null) {
|
||||
mDb.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所在行Id
|
||||
*/
|
||||
synchronized int[] getRowId(Class clazz) {
|
||||
checkDb();
|
||||
Cursor cursor = mDb.rawQuery("SELECT rowid, * FROM " + CommonUtil.getClassName(clazz), null);
|
||||
int[] ids = new int[cursor.getCount()];
|
||||
int i = 0;
|
||||
while (cursor.moveToNext()) {
|
||||
ids[i] = cursor.getInt(cursor.getColumnIndex("rowid"));
|
||||
i++;
|
||||
}
|
||||
cursor.close();
|
||||
close();
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取行Id
|
||||
*/
|
||||
synchronized int getRowId(Class clazz, Object[] wheres, Object[] values) {
|
||||
checkDb();
|
||||
if (wheres.length <= 0 || values.length <= 0) {
|
||||
ALog.e(TAG, "请输入删除条件");
|
||||
return -1;
|
||||
} else if (wheres.length != values.length) {
|
||||
ALog.e(TAG, "groupName 和 vaule 长度不相等");
|
||||
return -1;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT rowid FROM ").append(CommonUtil.getClassName(clazz)).append(" WHERE ");
|
||||
int i = 0;
|
||||
for (Object where : wheres) {
|
||||
sb.append(where).append("=").append("'").append(values[i]).append("'");
|
||||
sb.append(i >= wheres.length - 1 ? "" : ",");
|
||||
i++;
|
||||
}
|
||||
SqlHelper.print(ROW_ID, sb.toString());
|
||||
Cursor c = mDb.rawQuery(sb.toString(), null);
|
||||
int id = c.getColumnIndex("rowid");
|
||||
c.close();
|
||||
close();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
221
Aria/src/main/java/com/arialyy/aria/orm/DelegateCommon.java
Normal file
221
Aria/src/main/java/com/arialyy/aria/orm/DelegateCommon.java
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.orm.annotation.Default;
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/22.
|
||||
* 通用委托,创建表,检查字段
|
||||
*/
|
||||
class DelegateCommon extends AbsDelegate {
|
||||
private DelegateCommon() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定的表
|
||||
*/
|
||||
void dropTable(SQLiteDatabase db, String tableName) {
|
||||
db = checkDb(db);
|
||||
String deleteSQL = "DROP TABLE IF EXISTS ".concat(tableName);
|
||||
print(DROP_TABLE, deleteSQL);
|
||||
//db.beginTransaction();
|
||||
db.execSQL(deleteSQL);
|
||||
//db.setTransactionSuccessful();
|
||||
//db.endTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空表数据
|
||||
*/
|
||||
<T extends DbEntity> void clean(SQLiteDatabase db, Class<T> clazz) {
|
||||
db = checkDb(db);
|
||||
String tableName = CommonUtil.getClassName(clazz);
|
||||
if (tableExists(db, clazz)) {
|
||||
String sql = "DELETE FROM " + tableName;
|
||||
db.execSQL(sql);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找表是否存在
|
||||
*
|
||||
* @param clazz 数据库实体
|
||||
* @return true,该数据库实体对应的表存在;false,不存在
|
||||
*/
|
||||
boolean tableExists(SQLiteDatabase db, Class clazz) {
|
||||
return tableExists(db, CommonUtil.getClassName(clazz));
|
||||
}
|
||||
|
||||
private boolean tableExists(SQLiteDatabase db, String tableName) {
|
||||
db = checkDb(db);
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name='");
|
||||
sb.append(tableName);
|
||||
sb.append("'");
|
||||
print(TABLE_EXISTS, sb.toString());
|
||||
cursor = db.rawQuery(sb.toString(), null);
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
int count = cursor.getInt(0);
|
||||
if (count > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查某个字段的值是否存在
|
||||
*
|
||||
* @param expression 字段和值"url=xxx"
|
||||
* @return {@code true}该字段的对应的value已存在
|
||||
*/
|
||||
boolean checkDataExist(SQLiteDatabase db, Class clazz, String... expression) {
|
||||
db = checkDb(db);
|
||||
CheckUtil.checkSqlExpression(expression);
|
||||
String sql =
|
||||
"SELECT rowid, * FROM " + CommonUtil.getClassName(clazz) + " WHERE " + expression[0] + " ";
|
||||
sql = sql.replace("?", "%s");
|
||||
Object[] params = new String[expression.length - 1];
|
||||
for (int i = 0, len = params.length; i < len; i++) {
|
||||
params[i] = "'" + expression[i + 1] + "'";
|
||||
}
|
||||
sql = String.format(sql, params);
|
||||
print(FIND_DATA, sql);
|
||||
Cursor cursor = db.rawQuery(sql, null);
|
||||
final boolean isExist = cursor.getCount() > 0;
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
return isExist;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表
|
||||
*
|
||||
* @param clazz 数据库实体
|
||||
*/
|
||||
void createTable(SQLiteDatabase db, Class clazz) {
|
||||
db = checkDb(db);
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
if (fields != null && fields.size() > 0) {
|
||||
//外键Map,在Sqlite3中foreign修饰的字段必须放在最后
|
||||
final List<Field> foreignArray = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("CREATE TABLE ")
|
||||
.append(CommonUtil.getClassName(clazz))
|
||||
.append(" (");
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (SqlUtil.isIgnore(field)) {
|
||||
continue;
|
||||
}
|
||||
Class<?> type = field.getType();
|
||||
sb.append(field.getName());
|
||||
if (type == String.class || type.isEnum()) {
|
||||
sb.append(" VARCHAR");
|
||||
} else if (type == int.class || type == Integer.class) {
|
||||
sb.append(" INTEGER");
|
||||
} else if (type == float.class || type == Float.class) {
|
||||
sb.append(" FLOAT");
|
||||
} else if (type == double.class || type == Double.class) {
|
||||
sb.append(" DOUBLE");
|
||||
} else if (type == long.class || type == Long.class) {
|
||||
sb.append(" BIGINT");
|
||||
} else if (type == boolean.class || type == Boolean.class) {
|
||||
sb.append(" BOOLEAN");
|
||||
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
|
||||
sb.append(" DATA");
|
||||
} else if (type == byte.class || type == Byte.class) {
|
||||
sb.append(" BLOB");
|
||||
} else if (type == Map.class || type == List.class) {
|
||||
sb.append(" TEXT");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (SqlUtil.isPrimary(field)) {
|
||||
Primary pk = field.getAnnotation(Primary.class);
|
||||
sb.append(" PRIMARY KEY");
|
||||
if (pk.autoincrement() && (type == int.class || type == Integer.class)) {
|
||||
sb.append(" AUTOINCREMENT");
|
||||
}
|
||||
}
|
||||
|
||||
if (SqlUtil.isForeign(field)) {
|
||||
foreignArray.add(field);
|
||||
}
|
||||
|
||||
if (SqlUtil.isNoNull(field)) {
|
||||
sb.append(" NOT NULL");
|
||||
}
|
||||
|
||||
if (SqlUtil.isDefault(field)) {
|
||||
Default d = field.getAnnotation(Default.class);
|
||||
if (!TextUtils.isEmpty(d.value())) {
|
||||
sb.append(" DEFAULT ").append("'").append(d.value()).append("'");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
for (Field field : foreignArray) {
|
||||
Foreign foreign = field.getAnnotation(Foreign.class);
|
||||
sb.append("FOREIGN KEY (")
|
||||
.append(field.getName())
|
||||
.append(") REFERENCES ")
|
||||
.append(CommonUtil.getClassName(foreign.parent()))
|
||||
.append("(")
|
||||
.append(foreign.column())
|
||||
.append(")");
|
||||
ActionPolicy update = foreign.onUpdate();
|
||||
ActionPolicy delete = foreign.onDelete();
|
||||
if (update != ActionPolicy.NO_ACTION) {
|
||||
sb.append(" ON UPDATE ").append(update.function);
|
||||
}
|
||||
|
||||
if (delete != ActionPolicy.NO_ACTION) {
|
||||
sb.append(" ON DELETE ").append(update.function);
|
||||
}
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
String str = sb.toString();
|
||||
str = str.substring(0, str.length() - 1) + ");";
|
||||
print(CREATE_TABLE, str);
|
||||
db.execSQL(str);
|
||||
}
|
||||
close(db);
|
||||
}
|
||||
}
|
||||
512
Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java
Normal file
512
Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java
Normal file
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.orm.annotation.Many;
|
||||
import com.arialyy.aria.orm.annotation.One;
|
||||
import com.arialyy.aria.orm.annotation.Wrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/22.
|
||||
* 查询数据
|
||||
*/
|
||||
class DelegateFind extends AbsDelegate {
|
||||
private final String PARENT_COLUMN_ALIAS = "p";
|
||||
private final String CHILD_COLUMN_ALIAS = "c";
|
||||
|
||||
private DelegateFind() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找一对多的关联数据
|
||||
* 如果查找不到数据或实体没有被{@link Wrapper}注解,将返回null
|
||||
* 如果实体中没有{@link One}或{@link Many}注解,将返回null
|
||||
* 如果实体中有多个{@link One}或{@link Many}注解,将返回nul
|
||||
*/
|
||||
<T extends AbsWrapper> List<T> findRelationData(SQLiteDatabase db, Class<T> clazz,
|
||||
String... expression) {
|
||||
db = checkDb(db);
|
||||
|
||||
if (SqlUtil.isWrapper(clazz)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
Field one = null, many = null;
|
||||
boolean hasOne = false, hasMany = false;
|
||||
for (Field field : fields) {
|
||||
if (SqlUtil.isOne(field)) {
|
||||
if (hasOne) {
|
||||
ALog.w(TAG, "查询数据失败,实体中有多个@One 注解");
|
||||
return null;
|
||||
}
|
||||
hasOne = true;
|
||||
one = field;
|
||||
}
|
||||
if (SqlUtil.isMany(field)) {
|
||||
if (hasMany) {
|
||||
ALog.w(TAG, "查询数据失败,实体中有多个@Many 注解");
|
||||
return null;
|
||||
}
|
||||
hasMany = true;
|
||||
many = field;
|
||||
}
|
||||
}
|
||||
|
||||
if (one == null || many == null) {
|
||||
ALog.w(TAG, "查询数据失败,实体中没有@One或@Many注解");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (many.getType() != List.class) {
|
||||
ALog.w(TAG, "查询数据失败,@Many注解的字段必须是List");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Many m = many.getAnnotation(Many.class);
|
||||
Class parentClazz = Class.forName(one.getType().getName());
|
||||
Class childClazz = Class.forName(CommonUtil.getListParamType(many).getName());
|
||||
final String pTableName = parentClazz.getSimpleName();
|
||||
final String cTableName = childClazz.getSimpleName();
|
||||
List<Field> pColumn = SqlUtil.getAllNotIgnoreField(parentClazz);
|
||||
List<Field> cColumn = SqlUtil.getAllNotIgnoreField(childClazz);
|
||||
List<String> pColumnAlias = new ArrayList<>();
|
||||
List<String> cColumnAlias = new ArrayList<>();
|
||||
StringBuilder pSb = new StringBuilder();
|
||||
StringBuilder cSb = new StringBuilder();
|
||||
|
||||
if (pColumn != null) {
|
||||
pSb.append(pTableName.concat(".rowid AS ").concat(PARENT_COLUMN_ALIAS).concat("rowid,"));
|
||||
for (Field f : pColumn) {
|
||||
String temp = PARENT_COLUMN_ALIAS.concat(f.getName());
|
||||
pColumnAlias.add(temp);
|
||||
pSb.append(pTableName.concat(".").concat(f.getName()))
|
||||
.append(" AS ")
|
||||
.append(temp)
|
||||
.append(",");
|
||||
}
|
||||
}
|
||||
|
||||
if (cColumn != null) {
|
||||
pSb.append(cTableName.concat(".rowid AS ").concat(CHILD_COLUMN_ALIAS).concat("rowid,"));
|
||||
for (Field f : cColumn) {
|
||||
String temp = CHILD_COLUMN_ALIAS.concat(f.getName());
|
||||
cColumnAlias.add(temp);
|
||||
cSb.append(cTableName.concat(".").concat(f.getName()))
|
||||
.append(" AS ")
|
||||
.append(temp)
|
||||
.append(",");
|
||||
}
|
||||
}
|
||||
|
||||
String pColumnAlia = pSb.toString();
|
||||
String cColumnAlia = cSb.toString();
|
||||
if (!TextUtils.isEmpty(pColumnAlia)) {
|
||||
pColumnAlia = pColumnAlia.substring(0, pColumnAlia.length() - 1);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(cColumnAlia)) {
|
||||
cColumnAlia = cColumnAlia.substring(0, cColumnAlia.length() - 1);
|
||||
}
|
||||
|
||||
sb.append("SELECT ");
|
||||
|
||||
if (!TextUtils.isEmpty(pColumnAlia)) {
|
||||
sb.append(pColumnAlia).append(",");
|
||||
}
|
||||
if (!TextUtils.isEmpty(cColumnAlia)) {
|
||||
sb.append(cColumnAlia);
|
||||
}
|
||||
if (TextUtils.isEmpty(pColumnAlia) && TextUtils.isEmpty(cColumnAlia)) {
|
||||
sb.append(" * ");
|
||||
}
|
||||
|
||||
sb.append(" FROM ")
|
||||
.append(pTableName)
|
||||
.append(" INNER JOIN ")
|
||||
.append(cTableName)
|
||||
.append(" ON ")
|
||||
.append(pTableName.concat(".").concat(m.parentColumn()))
|
||||
.append(" = ")
|
||||
.append(cTableName.concat(".").concat(m.entityColumn()));
|
||||
String sql;
|
||||
if (expression != null && expression.length > 0) {
|
||||
CheckUtil.checkSqlExpression(expression);
|
||||
sb.append(" WHERE ").append(expression[0]).append(" ");
|
||||
sql = sb.toString();
|
||||
sql = sql.replace("?", "%s");
|
||||
Object[] params = new String[expression.length - 1];
|
||||
for (int i = 0, len = params.length; i < len; i++) {
|
||||
params[i] = "'" + convertValue(expression[i + 1]) + "'";
|
||||
}
|
||||
sql = String.format(sql, params);
|
||||
} else {
|
||||
sql = sb.toString();
|
||||
}
|
||||
print(RELATION, sql);
|
||||
Cursor cursor = db.rawQuery(sql, null);
|
||||
List<T> data =
|
||||
(List<T>) newInstanceEntity(clazz, parentClazz, childClazz, cursor, pColumn, cColumn,
|
||||
pColumnAlias, cColumnAlias);
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
return data;
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
ALog.w(TAG, "查询数据失败,实体类没有使用@Wrapper 注解");
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建关联查询的数据
|
||||
*
|
||||
* @param pColumn 父表的所有字段
|
||||
* @param cColumn 字表的所有字段
|
||||
* @param pColumnAlias 关联查询父表别名
|
||||
* @param cColumnAlias 关联查询子表别名
|
||||
*/
|
||||
private <T extends AbsWrapper, P extends DbEntity, C extends DbEntity> List<T> newInstanceEntity(
|
||||
Class<T> clazz, Class<P> parent,
|
||||
Class<C> child,
|
||||
Cursor cursor,
|
||||
List<Field> pColumn, List<Field> cColumn,
|
||||
List<String> pColumnAlias, List<String> cColumnAlias) {
|
||||
try {
|
||||
String parentPrimary = ""; //父表主键别名
|
||||
for (Field f : pColumn) {
|
||||
if (SqlUtil.isPrimary(f)) {
|
||||
parentPrimary = PARENT_COLUMN_ALIAS.concat(f.getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
List<T> wrappers = new ArrayList<>();
|
||||
Map<Object, P> tempParent = new WeakHashMap<>(); // 所有父表元素,key为父表主键的值
|
||||
Map<Object, List<C>> tempChild = new WeakHashMap<>(); // 所有的字表元素,key为父表主键的值
|
||||
|
||||
Object old = null;
|
||||
while (cursor.moveToNext()) {
|
||||
//创建父实体
|
||||
Object ppValue = setPPValue(parentPrimary, cursor);
|
||||
if (old == null || ppValue != old) { //当主键不同时,表示是不同的父表数据
|
||||
old = ppValue;
|
||||
if (tempParent.get(old) == null) {
|
||||
P pEntity = parent.newInstance();
|
||||
String pPrimaryName = "";
|
||||
for (int i = 0, len = pColumnAlias.size(); i < len; i++) {
|
||||
Field pField = pColumn.get(i);
|
||||
pField.setAccessible(true);
|
||||
Class<?> type = pField.getType();
|
||||
int column = cursor.getColumnIndex(pColumnAlias.get(i));
|
||||
if (column == -1) continue;
|
||||
setFieldValue(type, pField, column, cursor, pEntity);
|
||||
|
||||
if (SqlUtil.isPrimary(pField) && (type == int.class || type == Integer.class)) {
|
||||
pPrimaryName = pField.getName();
|
||||
}
|
||||
}
|
||||
|
||||
//当设置了主键,而且主键的类型为integer时,查询RowID等于主键
|
||||
pEntity.rowID = cursor.getInt(
|
||||
cursor.getColumnIndex(
|
||||
TextUtils.isEmpty(pPrimaryName) ? PARENT_COLUMN_ALIAS.concat("rowid")
|
||||
: pPrimaryName));
|
||||
|
||||
tempParent.put(ppValue, pEntity);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建子实体
|
||||
C cEntity = child.newInstance();
|
||||
String cPrimaryName = "";
|
||||
for (int i = 0, len = cColumnAlias.size(); i < len; i++) {
|
||||
Field cField = cColumn.get(i);
|
||||
cField.setAccessible(true);
|
||||
Class<?> type = cField.getType();
|
||||
|
||||
int column = cursor.getColumnIndex(cColumnAlias.get(i));
|
||||
if (column == -1) continue;
|
||||
setFieldValue(type, cField, column, cursor, cEntity);
|
||||
|
||||
if (SqlUtil.isPrimary(cField) && (type == int.class || type == Integer.class)) {
|
||||
cPrimaryName = cField.getName();
|
||||
}
|
||||
}
|
||||
//当设置了主键,而且主键的类型为integer时,查询RowID等于主键
|
||||
cEntity.rowID = cursor.getInt(
|
||||
cursor.getColumnIndex(
|
||||
TextUtils.isEmpty(cPrimaryName) ? CHILD_COLUMN_ALIAS.concat("rowid")
|
||||
: cPrimaryName));
|
||||
if (tempChild.get(old) == null) {
|
||||
tempChild.put(old, new ArrayList<C>());
|
||||
}
|
||||
tempChild.get(old).add(cEntity);
|
||||
}
|
||||
|
||||
List<Field> wFields = SqlUtil.getAllNotIgnoreField(clazz);
|
||||
if (wFields != null && !wFields.isEmpty()) {
|
||||
Set<Object> pKeys = tempParent.keySet();
|
||||
for (Object pk : pKeys) {
|
||||
T wrapper = clazz.newInstance();
|
||||
P p = tempParent.get(pk);
|
||||
boolean isPSet = false, isCSet = false;
|
||||
for (Field f : wFields) {
|
||||
if (!isPSet && f.getAnnotation(One.class) != null) {
|
||||
f.set(wrapper, p);
|
||||
isPSet = true;
|
||||
}
|
||||
if (!isCSet && f.getAnnotation(Many.class) != null) {
|
||||
f.set(wrapper, tempChild.get(pk));
|
||||
isCSet = true;
|
||||
}
|
||||
}
|
||||
wrapper.handleConvert(); //处理下转换
|
||||
wrappers.add(wrapper);
|
||||
}
|
||||
}
|
||||
return wrappers;
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取父表主键数据
|
||||
*
|
||||
* @param parentPrimary 父表主键别名
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB) private Object setPPValue(String parentPrimary,
|
||||
Cursor cursor) {
|
||||
Object ppValue = null;
|
||||
int ppColumn = cursor.getColumnIndex(parentPrimary); //父表主键所在的列
|
||||
int type = cursor.getType(ppColumn);
|
||||
switch (type) {
|
||||
case Cursor.FIELD_TYPE_INTEGER:
|
||||
ppValue = cursor.getLong(ppColumn);
|
||||
break;
|
||||
case Cursor.FIELD_TYPE_FLOAT:
|
||||
ppValue = cursor.getFloat(ppColumn);
|
||||
break;
|
||||
case Cursor.FIELD_TYPE_STRING:
|
||||
ppValue = cursor.getString(ppColumn);
|
||||
break;
|
||||
}
|
||||
return ppValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件查寻数据
|
||||
*/
|
||||
<T extends DbEntity> List<T> findData(SQLiteDatabase db, Class<T> clazz, String... expression) {
|
||||
db = checkDb(db);
|
||||
CheckUtil.checkSqlExpression(expression);
|
||||
String sql =
|
||||
"SELECT rowid, * FROM " + CommonUtil.getClassName(clazz) + " WHERE " + expression[0] + " ";
|
||||
sql = sql.replace("?", "%s");
|
||||
Object[] params = new String[expression.length - 1];
|
||||
for (int i = 0, len = params.length; i < len; i++) {
|
||||
params[i] = "'" + convertValue(expression[i + 1]) + "'";
|
||||
}
|
||||
sql = String.format(sql, params);
|
||||
print(FIND_DATA, sql);
|
||||
Cursor cursor = db.rawQuery(sql, null);
|
||||
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找表的所有数据
|
||||
*/
|
||||
<T extends DbEntity> List<T> findAllData(SQLiteDatabase db, Class<T> clazz) {
|
||||
db = checkDb(db);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT rowid, * FROM ").append(CommonUtil.getClassName(clazz));
|
||||
print(FIND_ALL_DATA, sb.toString());
|
||||
Cursor cursor = db.rawQuery(sb.toString(), null);
|
||||
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据游标创建一个具体的对象
|
||||
*/
|
||||
private <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz, Cursor cursor) {
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
List<T> entitys = new ArrayList<>();
|
||||
if (fields != null && fields.size() > 0) {
|
||||
try {
|
||||
while (cursor.moveToNext()) {
|
||||
T entity = clazz.newInstance();
|
||||
String primaryName = "";
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (SqlUtil.isIgnore(field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<?> type = field.getType();
|
||||
if (SqlUtil.isPrimary(field) && (type == int.class || type == Integer.class)) {
|
||||
primaryName = field.getName();
|
||||
}
|
||||
|
||||
int column = cursor.getColumnIndex(field.getName());
|
||||
if (column == -1) continue;
|
||||
setFieldValue(type, field, column, cursor, entity);
|
||||
}
|
||||
//当设置了主键,而且主键的类型为integer时,查询RowID等于主键
|
||||
entity.rowID = cursor.getInt(
|
||||
cursor.getColumnIndex(TextUtils.isEmpty(primaryName) ? "rowid" : primaryName));
|
||||
mDataCache.put(getCacheKey(entity), entity);
|
||||
entitys.add(entity);
|
||||
}
|
||||
closeCursor(cursor);
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return entitys;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字段的值
|
||||
*
|
||||
* @throws IllegalAccessException
|
||||
*/
|
||||
private void setFieldValue(Class type, Field field, int column, Cursor cursor, Object entity)
|
||||
throws IllegalAccessException {
|
||||
if (type == String.class) {
|
||||
String temp = cursor.getString(column);
|
||||
if (!TextUtils.isEmpty(temp)) {
|
||||
field.set(entity, URLDecoder.decode(temp));
|
||||
}
|
||||
} else if (type == int.class || type == Integer.class) {
|
||||
field.setInt(entity, cursor.getInt(column));
|
||||
} else if (type == float.class || type == Float.class) {
|
||||
field.setFloat(entity, cursor.getFloat(column));
|
||||
} else if (type == double.class || type == Double.class) {
|
||||
field.setDouble(entity, cursor.getDouble(column));
|
||||
} else if (type == long.class || type == Long.class) {
|
||||
field.setLong(entity, cursor.getLong(column));
|
||||
} else if (type == boolean.class || type == Boolean.class) {
|
||||
String temp = cursor.getString(column);
|
||||
if (TextUtils.isEmpty(temp)) {
|
||||
field.setBoolean(entity, false);
|
||||
} else {
|
||||
field.setBoolean(entity, !temp.equalsIgnoreCase("false"));
|
||||
}
|
||||
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
|
||||
field.set(entity, new Date(cursor.getString(column)));
|
||||
} else if (type == byte[].class) {
|
||||
field.set(entity, cursor.getBlob(column));
|
||||
} else if (type == Map.class) {
|
||||
String temp = cursor.getString(column);
|
||||
if (!TextUtils.isEmpty(temp)) {
|
||||
field.set(entity, SqlUtil.str2Map(temp));
|
||||
}
|
||||
} else if (type == List.class) {
|
||||
String value = cursor.getString(column);
|
||||
if (!TextUtils.isEmpty(value)) {
|
||||
field.set(entity, SqlUtil.str2List(value, field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所在行Id
|
||||
*/
|
||||
int[] getRowId(SQLiteDatabase db, Class clazz) {
|
||||
db = checkDb(db);
|
||||
Cursor cursor = db.rawQuery("SELECT rowid, * FROM " + CommonUtil.getClassName(clazz), null);
|
||||
int[] ids = new int[cursor.getCount()];
|
||||
int i = 0;
|
||||
while (cursor.moveToNext()) {
|
||||
ids[i] = cursor.getInt(cursor.getColumnIndex("rowid"));
|
||||
i++;
|
||||
}
|
||||
cursor.close();
|
||||
close(db);
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取行Id
|
||||
*/
|
||||
int getRowId(SQLiteDatabase db, Class clazz, Object[] wheres, Object[] values) {
|
||||
db = checkDb(db);
|
||||
if (wheres.length <= 0 || values.length <= 0) {
|
||||
ALog.e(TAG, "请输入删除条件");
|
||||
return -1;
|
||||
} else if (wheres.length != values.length) {
|
||||
ALog.e(TAG, "groupName 和 vaule 长度不相等");
|
||||
return -1;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT rowid FROM ").append(CommonUtil.getClassName(clazz)).append(" WHERE ");
|
||||
int i = 0;
|
||||
for (Object where : wheres) {
|
||||
sb.append(where).append("=").append("'").append(values[i]).append("'");
|
||||
sb.append(i >= wheres.length - 1 ? "" : ",");
|
||||
i++;
|
||||
}
|
||||
print(ROW_ID, sb.toString());
|
||||
Cursor c = db.rawQuery(sb.toString(), null);
|
||||
int id = c.getColumnIndex("rowid");
|
||||
c.close();
|
||||
close(db);
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过rowId判断数据是否存在
|
||||
*/
|
||||
<T extends DbEntity> boolean itemExist(SQLiteDatabase db, Class<T> clazz,
|
||||
int rowId) {
|
||||
db = checkDb(db);
|
||||
String sql = "SELECT rowid FROM " + CommonUtil.getClassName(clazz) + " WHERE rowid=" + rowId;
|
||||
print(ROW_ID, sql);
|
||||
Cursor cursor = db.rawQuery(sql, null);
|
||||
boolean isExist = cursor.getCount() > 0;
|
||||
cursor.close();
|
||||
return isExist;
|
||||
}
|
||||
}
|
||||
69
Aria/src/main/java/com/arialyy/aria/orm/DelegateManager.java
Normal file
69
Aria/src/main/java/com/arialyy/aria/orm/DelegateManager.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/22.
|
||||
* Delegate管理器
|
||||
*/
|
||||
class DelegateManager {
|
||||
private final String TAG = "ModuleFactory";
|
||||
|
||||
private SparseArray<AbsDelegate> mDelegates = new SparseArray<>();
|
||||
private static volatile DelegateManager INSTANCE = null;
|
||||
|
||||
private DelegateManager() {
|
||||
|
||||
}
|
||||
|
||||
static DelegateManager getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (DelegateManager.class) {
|
||||
INSTANCE = new DelegateManager();
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Module
|
||||
*/
|
||||
<M extends AbsDelegate> M getDelegate(Class<M> clazz) {
|
||||
M delegate = (M) mDelegates.get(clazz.hashCode());
|
||||
try {
|
||||
if (delegate == null) {
|
||||
Constructor c = clazz.getDeclaredConstructor();
|
||||
c.setAccessible(true);
|
||||
delegate = (M) c.newInstance();
|
||||
mDelegates.put(clazz.hashCode(), delegate);
|
||||
return delegate;
|
||||
}
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
186
Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java
Normal file
186
Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/22.
|
||||
* 增加数据、更新数据
|
||||
*/
|
||||
class DelegateUpdate extends AbsDelegate {
|
||||
private DelegateUpdate() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除某条数据
|
||||
*/
|
||||
<T extends DbEntity> void delData(SQLiteDatabase db, Class<T> clazz, String... expression) {
|
||||
db = checkDb(db);
|
||||
CheckUtil.checkSqlExpression(expression);
|
||||
|
||||
String sql = "DELETE FROM " + CommonUtil.getClassName(clazz) + " WHERE " + expression[0] + " ";
|
||||
sql = sql.replace("?", "%s");
|
||||
Object[] params = new String[expression.length - 1];
|
||||
for (int i = 0, len = params.length; i < len; i++) {
|
||||
params[i] = "'" + expression[i + 1] + "'";
|
||||
}
|
||||
sql = String.format(sql, params);
|
||||
print(DEL_DATA, sql);
|
||||
db.execSQL(sql);
|
||||
close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改某行数据
|
||||
*/
|
||||
void modifyData(SQLiteDatabase db, DbEntity dbEntity) {
|
||||
db = checkDb(db);
|
||||
Class<?> clazz = dbEntity.getClass();
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
DbEntity cacheEntity = mDataCache.get(getCacheKey(dbEntity));
|
||||
if (fields != null && fields.size() > 0) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
StringBuilder prams = new StringBuilder();
|
||||
sql.append("UPDATE ").append(CommonUtil.getClassName(dbEntity)).append(" SET ");
|
||||
int i = 0;
|
||||
try {
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (isIgnore(dbEntity, field)) {
|
||||
continue;
|
||||
}
|
||||
if (cacheEntity != null
|
||||
&& field.get(dbEntity) == field.get(cacheEntity)
|
||||
&& !field.getName().equals("state")) { //在LruCache中 state字段总是不能重新赋值...
|
||||
continue;
|
||||
}
|
||||
|
||||
String value;
|
||||
prams.append(i > 0 ? ", " : "");
|
||||
prams.append(field.getName()).append("='");
|
||||
Type type = field.getType();
|
||||
if (type == Map.class && checkMap(field)) {
|
||||
value = SqlUtil.map2Str((Map<String, String>) field.get(dbEntity));
|
||||
} else if (type == List.class && checkList(field)) {
|
||||
value = SqlUtil.list2Str(dbEntity, field);
|
||||
} else {
|
||||
Object obj = field.get(dbEntity);
|
||||
value = obj == null ? "" : convertValue(obj.toString());
|
||||
}
|
||||
|
||||
prams.append(TextUtils.isEmpty(value) ? "" : value);
|
||||
prams.append("'");
|
||||
i++;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!TextUtils.isEmpty(prams.toString())) {
|
||||
sql.append(prams.toString());
|
||||
sql.append(" where rowid=").append(dbEntity.rowID);
|
||||
print(MODIFY_DATA, sql.toString());
|
||||
db.execSQL(sql.toString());
|
||||
}
|
||||
}
|
||||
mDataCache.put(getCacheKey(dbEntity), dbEntity);
|
||||
close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
void insertData(SQLiteDatabase db, DbEntity dbEntity) {
|
||||
db = checkDb(db);
|
||||
Class<?> clazz = dbEntity.getClass();
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
if (fields != null && fields.size() > 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("INSERT INTO ").append(CommonUtil.getClassName(dbEntity)).append("(");
|
||||
int i = 0;
|
||||
try {
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (isIgnore(dbEntity, field)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(i > 0 ? ", " : "");
|
||||
sb.append(field.getName());
|
||||
i++;
|
||||
}
|
||||
sb.append(") VALUES (");
|
||||
i = 0;
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (isIgnore(dbEntity, field)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(i > 0 ? ", " : "");
|
||||
sb.append("'");
|
||||
Type type = field.getType();
|
||||
if (type == Map.class && checkMap(field)) {
|
||||
sb.append(SqlUtil.map2Str((Map<String, String>) field.get(dbEntity)));
|
||||
} else if (type == List.class && checkList(field)) {
|
||||
sb.append(SqlUtil.list2Str(dbEntity, field));
|
||||
} else {
|
||||
Object obj = field.get(dbEntity);
|
||||
if (obj != null) {
|
||||
sb.append(convertValue(field.get(dbEntity).toString()));
|
||||
}
|
||||
}
|
||||
sb.append("'");
|
||||
i++;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
sb.append(")");
|
||||
print(INSERT_DATA, sb.toString());
|
||||
db.execSQL(sb.toString());
|
||||
}
|
||||
close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code true}自动增长的主键和需要忽略的字段
|
||||
*/
|
||||
private boolean isIgnore(Object obj, Field field) throws IllegalAccessException {
|
||||
if (SqlUtil.isIgnore(field)) {
|
||||
return true;
|
||||
}
|
||||
if (SqlUtil.isPrimary(field)) { //忽略自动增长的主键
|
||||
Primary p = field.getAnnotation(Primary.class);
|
||||
if (p.autoincrement()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (SqlUtil.isForeign(field)) { //忽略外键为null的字段
|
||||
Object value = field.get(obj);
|
||||
if (value == null || (value instanceof String && TextUtils.isEmpty(String.valueOf(value)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
155
Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java
Normal file
155
Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/2/11.
|
||||
* 数据库操作工具
|
||||
*/
|
||||
public class DelegateWrapper {
|
||||
private static final String TAG = "DelegateWrapper";
|
||||
private volatile static DelegateWrapper INSTANCE = null;
|
||||
|
||||
private SQLiteDatabase mDb;
|
||||
private DelegateManager mDManager;
|
||||
|
||||
private DelegateWrapper() {
|
||||
|
||||
}
|
||||
|
||||
private DelegateWrapper(Context context) {
|
||||
SqlHelper helper = SqlHelper.init(context.getApplicationContext());
|
||||
mDb = helper.getWritableDatabase();
|
||||
mDManager = DelegateManager.getInstance();
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
synchronized (DelegateWrapper.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new DelegateWrapper(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DelegateWrapper getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
throw new NullPointerException("请在Application中调用init进行数据库工具注册注册");
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询关联表数据
|
||||
*
|
||||
* @param expression 查询条件
|
||||
*/
|
||||
<T extends AbsWrapper> List<T> findRelationData(Class<T> clazz, String... expression) {
|
||||
return mDManager.getDelegate(DelegateFind.class).findRelationData(mDb, clazz, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查某个字段的值是否存在
|
||||
*
|
||||
* @param expression 字段和值"url=xxx"
|
||||
* @return {@code true}该字段的对应的value已存在
|
||||
*/
|
||||
boolean checkDataExist(Class clazz, String... expression) {
|
||||
return mDManager.getDelegate(DelegateCommon.class)
|
||||
.checkDataExist(mDb, clazz, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空表数据
|
||||
*/
|
||||
<T extends DbEntity> void clean(Class<T> clazz) {
|
||||
mDManager.getDelegate(DelegateCommon.class).clean(mDb, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行sql语句
|
||||
*/
|
||||
void exeSql(String sql) {
|
||||
mDb.execSQL(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除某条数据
|
||||
*/
|
||||
<T extends DbEntity> void delData(Class<T> clazz, String... expression) {
|
||||
mDManager.getDelegate(DelegateUpdate.class).delData(mDb, clazz, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改某行数据
|
||||
*/
|
||||
void modifyData(DbEntity dbEntity) {
|
||||
mDManager.getDelegate(DelegateUpdate.class).modifyData(mDb, dbEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历所有数据
|
||||
*/
|
||||
<T extends DbEntity> List<T> findAllData(Class<T> clazz) {
|
||||
return mDManager.getDelegate(DelegateFind.class).findAllData(mDb, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件查寻数据
|
||||
*/
|
||||
<T extends DbEntity> List<T> findData(Class<T> clazz, String... expression) {
|
||||
return mDManager.getDelegate(DelegateFind.class).findData(mDb, clazz, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过rowId判断数据是否存在
|
||||
*/
|
||||
<T extends DbEntity> boolean isExist(Class<T> clazz, int rowId) {
|
||||
return mDManager.getDelegate(DelegateFind.class).itemExist(mDb, clazz, rowId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
void insertData(DbEntity dbEntity) {
|
||||
mDManager.getDelegate(DelegateUpdate.class).insertData(mDb, dbEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找某张表是否存在
|
||||
*/
|
||||
boolean tableExists(Class clazz) {
|
||||
return mDManager.getDelegate(DelegateCommon.class).tableExists(mDb, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所在行Id
|
||||
*/
|
||||
int[] getRowId(Class clazz) {
|
||||
return mDManager.getDelegate(DelegateFind.class).getRowId(mDb, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取行Id
|
||||
*/
|
||||
int getRowId(Class clazz, Object[] wheres, Object[] values) {
|
||||
return mDManager.getDelegate(DelegateFind.class).getRowId(mDb, clazz, wheres, values);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/7/4.
|
||||
* 基本类型的List,只能用于常见的数据类型,如果是一对多的复杂数据结构,需要使用{@link OneToMany}
|
||||
*/
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface NormalList {
|
||||
/**
|
||||
* 数据类型
|
||||
*/
|
||||
Class clazz();
|
||||
}
|
||||
@@ -20,21 +20,11 @@ import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.util.LruCache;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -43,31 +33,34 @@ import java.util.Set;
|
||||
*/
|
||||
final class SqlHelper extends SQLiteOpenHelper {
|
||||
private static final String TAG = "SqlHelper";
|
||||
private static final int CREATE_TABLE = 0;
|
||||
private static final int TABLE_EXISTS = 1;
|
||||
private static final int INSERT_DATA = 2;
|
||||
private static final int MODIFY_DATA = 3;
|
||||
private static final int FIND_DATA = 4;
|
||||
private static final int FIND_ALL_DATA = 5;
|
||||
private static final int DEL_DATA = 6;
|
||||
/**
|
||||
* 是否将数据库保存在Sd卡,{@code true} 是
|
||||
*/
|
||||
private static final boolean SAVE_IN_SDCARD = false;
|
||||
|
||||
private static volatile SqlHelper INSTANCE = null;
|
||||
private static LruCache<String, DbEntity> mDataCache = new LruCache<>(1024);
|
||||
//private static Map<String, DbEntity> mDataCache = new ConcurrentHashMap<>();
|
||||
static volatile SqlHelper INSTANCE = null;
|
||||
|
||||
private DelegateCommon mDelegate;
|
||||
|
||||
static SqlHelper init(Context context) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (AriaManager.LOCK) {
|
||||
INSTANCE = new SqlHelper(context.getApplicationContext());
|
||||
synchronized (SqlHelper.class) {
|
||||
DelegateCommon delegate = DelegateManager.getInstance().getDelegate(DelegateCommon.class);
|
||||
INSTANCE = new SqlHelper(context.getApplicationContext(), delegate);
|
||||
SQLiteDatabase db = INSTANCE.getWritableDatabase();
|
||||
db = checkDb(db);
|
||||
db = delegate.checkDb(db);
|
||||
// SQLite在3.6.19版本中开始支持外键约束,
|
||||
// 而在Android中 2.1以前的版本使用的SQLite版本是3.5.9, 在2.2版本中使用的是3.6.22.
|
||||
// 但是为了兼容以前的程序,默认并没有启用该功能,如果要启用该功能
|
||||
// 需要使用如下语句:
|
||||
db.execSQL("PRAGMA foreign_keys=ON;");
|
||||
Set<String> tables = DBConfig.mapping.keySet();
|
||||
for (String tableName : tables) {
|
||||
Class clazz = null;
|
||||
clazz = DBConfig.mapping.get(tableName);
|
||||
|
||||
if (!tableExists(db, clazz)) {
|
||||
createTable(db, clazz, null);
|
||||
if (!delegate.tableExists(db, clazz)) {
|
||||
delegate.createTable(db, clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,8 +68,10 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private SqlHelper(Context context) {
|
||||
super(context, DBConfig.DB_NAME, null, DBConfig.VERSION);
|
||||
private SqlHelper(Context context, DelegateCommon delegate) {
|
||||
super(SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null,
|
||||
DBConfig.VERSION);
|
||||
mDelegate = delegate;
|
||||
}
|
||||
|
||||
@Override public void onCreate(SQLiteDatabase db) {
|
||||
@@ -85,7 +80,11 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
|
||||
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion < newVersion) {
|
||||
handleDbUpdate(db);
|
||||
if (oldVersion < 31) {
|
||||
handle314AriaUpdate(db);
|
||||
} else {
|
||||
handleDbUpdate(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,635 +109,98 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
Set<String> tables = DBConfig.mapping.keySet();
|
||||
for (String tableName : tables) {
|
||||
Class clazz = DBConfig.mapping.get(tableName);
|
||||
if (tableExists(db, clazz)) {
|
||||
if (mDelegate.tableExists(db, clazz)) {
|
||||
String countColumnSql = "SELECT rowid FROM " + tableName;
|
||||
Cursor cursor = db.rawQuery(countColumnSql, null);
|
||||
int dbColumnNum = cursor.getColumnCount();
|
||||
int newEntityColumnNum = getEntityAttr(clazz);
|
||||
List<Field> fields = SqlUtil.getAllNotIgnoreField(clazz);
|
||||
int newEntityColumnNum = (fields == null || fields.isEmpty()) ? 0 : fields.size();
|
||||
if (dbColumnNum != newEntityColumnNum) {
|
||||
back(db, clazz);
|
||||
db = mDelegate.checkDb(db);
|
||||
//备份数据
|
||||
List<DbEntity> list =
|
||||
DelegateManager.getInstance().getDelegate(DelegateFind.class).findAllData(db, clazz);
|
||||
//修改表名为中介表名
|
||||
String alertSql = "ALTER TABLE " + tableName + " RENAME TO " + tableName + "_temp";
|
||||
//db.beginTransaction();
|
||||
db.execSQL(alertSql);
|
||||
|
||||
//创建一个原本的表
|
||||
mDelegate.createTable(db, clazz);
|
||||
//传入原来的数据
|
||||
if (list != null && list.size() > 0) {
|
||||
DelegateUpdate update = DelegateManager.getInstance().getDelegate(DelegateUpdate.class);
|
||||
for (DbEntity entity : list) {
|
||||
update.insertData(db, entity);
|
||||
}
|
||||
}
|
||||
//删除中介表
|
||||
mDelegate.dropTable(db, tableName + "_temp");
|
||||
}
|
||||
}
|
||||
}
|
||||
//db.setTransactionSuccessful();
|
||||
//db.endTransaction();
|
||||
mDelegate.close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* 备份
|
||||
* 处理3.4版本之前数据库迁移,主要是修改子表外键字段对应的值
|
||||
*/
|
||||
private void back(SQLiteDatabase db, Class clazz) {
|
||||
db = checkDb(db);
|
||||
String oldTableName = CommonUtil.getClassName(clazz);
|
||||
//备份数据
|
||||
List<DbEntity> list = findAllData(db, clazz);
|
||||
//修改原来表名字
|
||||
String alertSql = "alter table " + oldTableName + " rename to " + oldTableName + "_temp";
|
||||
db.beginTransaction();
|
||||
db.execSQL(alertSql);
|
||||
//创建一个原来新表
|
||||
createTable(db, clazz, null);
|
||||
if (list != null && list.size() > 0) {
|
||||
for (DbEntity entity : list) {
|
||||
insertData(db, entity);
|
||||
private void handle314AriaUpdate(SQLiteDatabase db) {
|
||||
Set<String> tables = DBConfig.mapping.keySet();
|
||||
for (String tableName : tables) {
|
||||
Class clazz = DBConfig.mapping.get(tableName);
|
||||
|
||||
String pColumn = SqlUtil.getPrimaryName(clazz);
|
||||
if (!TextUtils.isEmpty(pColumn)) {
|
||||
//删除所有主键为null的数据
|
||||
String nullSql =
|
||||
"DELETE FROM " + tableName + " WHERE " + pColumn + " = '' OR " + pColumn + " IS NULL";
|
||||
ALog.d(TAG, nullSql);
|
||||
db.execSQL(nullSql);
|
||||
|
||||
//删除所有主键重复的数据
|
||||
String repeatSql = "DELETE FROM "
|
||||
+ tableName
|
||||
+ " WHERE "
|
||||
+ pColumn
|
||||
+ " in (SELECT "
|
||||
+ pColumn
|
||||
+ " FROM "
|
||||
+ tableName
|
||||
+ " GROUP BY " + pColumn + " having count(" + pColumn + ") > 1)";
|
||||
|
||||
ALog.d(TAG, repeatSql);
|
||||
db.execSQL(repeatSql);
|
||||
}
|
||||
}
|
||||
//删除原来的表
|
||||
String deleteSQL = "drop table IF EXISTS " + oldTableName + "_temp";
|
||||
db.execSQL(deleteSQL);
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体的字段数
|
||||
*/
|
||||
private int getEntityAttr(Class clazz) {
|
||||
int count = 1;
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
if (fields != null && fields.size() > 0) {
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (SqlUtil.ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
//备份数据
|
||||
List<DbEntity> list =
|
||||
DelegateManager.getInstance().getDelegate(DelegateFind.class).findAllData(db, clazz);
|
||||
|
||||
///**
|
||||
// * 关键字模糊检索全文
|
||||
// *
|
||||
// * @param column 需要查找的列
|
||||
// * @param mathSql 关键字语法,exsimple “white OR green”、“blue AND red”、“white NOT green”
|
||||
// */
|
||||
//public static <T extends DbEntity> List<T> searchData(SQLiteDatabase db, Class<T> clazz,
|
||||
// String column, String mathSql) {
|
||||
// String sql = "SELECT * FROM "
|
||||
// + CommonUtil.getClassName(clazz)
|
||||
// + " WHERE "
|
||||
// + column
|
||||
// + " MATCH '"
|
||||
// + mathSql
|
||||
// + "'";
|
||||
//
|
||||
// Cursor cursor = db.rawQuery(sql, null);
|
||||
// List<T> data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
|
||||
// closeCursor(cursor);
|
||||
// return data;
|
||||
//}
|
||||
//修改表名为中介表名
|
||||
String alertSql = "ALTER TABLE " + tableName + " RENAME TO " + tableName + "_temp";
|
||||
db.execSQL(alertSql);
|
||||
|
||||
/**
|
||||
* 检查某个字段的值是否存在
|
||||
*
|
||||
* @param expression 字段和值"url=xxx"
|
||||
* @return {@code true}该字段的对应的value已存在
|
||||
*/
|
||||
static synchronized boolean checkDataExist(SQLiteDatabase db, Class clazz, String... expression) {
|
||||
db = checkDb(db);
|
||||
CheckUtil.checkSqlExpression(expression);
|
||||
String sql =
|
||||
"SELECT rowid, * FROM " + CommonUtil.getClassName(clazz) + " WHERE " + expression[0] + " ";
|
||||
sql = sql.replace("?", "%s");
|
||||
Object[] params = new String[expression.length - 1];
|
||||
for (int i = 0, len = params.length; i < len; i++) {
|
||||
params[i] = "'" + expression[i + 1] + "'";
|
||||
}
|
||||
sql = String.format(sql, params);
|
||||
print(FIND_DATA, sql);
|
||||
Cursor cursor = db.rawQuery(sql, null);
|
||||
final boolean isExist = cursor.getCount() > 0;
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
return isExist;
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件查寻数据
|
||||
*/
|
||||
static synchronized <T extends DbEntity> List<T> findData(SQLiteDatabase db, Class<T> clazz,
|
||||
String... expression) {
|
||||
db = checkDb(db);
|
||||
CheckUtil.checkSqlExpression(expression);
|
||||
String sql =
|
||||
"SELECT rowid, * FROM " + CommonUtil.getClassName(clazz) + " WHERE " + expression[0] + " ";
|
||||
sql = sql.replace("?", "%s");
|
||||
Object[] params = new String[expression.length - 1];
|
||||
for (int i = 0, len = params.length; i < len; i++) {
|
||||
params[i] = "'" + checkValue(expression[i + 1]) + "'";
|
||||
}
|
||||
sql = String.format(sql, params);
|
||||
print(FIND_DATA, sql);
|
||||
Cursor cursor = db.rawQuery(sql, null);
|
||||
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件查寻数据
|
||||
*/
|
||||
static synchronized <T extends DbEntity> List<T> findData(SQLiteDatabase db, String tableName,
|
||||
String... expression) {
|
||||
Class<T> clazz = null;
|
||||
try {
|
||||
clazz = (Class<T>) Class.forName(tableName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return findData(db, clazz, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件查寻数据
|
||||
*/
|
||||
@Deprecated static synchronized <T extends DbEntity> List<T> findData(SQLiteDatabase db,
|
||||
Class<T> clazz, @NonNull String[] wheres, @NonNull String[] values) {
|
||||
db = checkDb(db);
|
||||
if (wheres.length <= 0 || values.length <= 0) {
|
||||
ALog.e(TAG, "请输入查询条件");
|
||||
return null;
|
||||
} else if (wheres.length != values.length) {
|
||||
ALog.e(TAG, "groupName 和 vaule 长度不相等");
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT rowid, * FROM ").append(CommonUtil.getClassName(clazz)).append(" where ");
|
||||
int i = 0;
|
||||
for (Object where : wheres) {
|
||||
sb.append(where).append("=").append("'").append(checkValue(values[i])).append("'");
|
||||
sb.append(i >= wheres.length - 1 ? "" : " AND ");
|
||||
i++;
|
||||
}
|
||||
print(FIND_DATA, sb.toString());
|
||||
Cursor cursor = db.rawQuery(sb.toString(), null);
|
||||
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
return data;
|
||||
}
|
||||
|
||||
private static String checkValue(String value) {
|
||||
if (value.contains("'")) {
|
||||
return URLEncoder.encode(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找表的所有数据
|
||||
*/
|
||||
static synchronized <T extends DbEntity> List<T> findAllData(SQLiteDatabase db, Class<T> clazz) {
|
||||
db = checkDb(db);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT rowid, * FROM ").append(CommonUtil.getClassName(clazz));
|
||||
print(FIND_ALL_DATA, sb.toString());
|
||||
Cursor cursor = db.rawQuery(sb.toString(), null);
|
||||
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除某条数据
|
||||
*/
|
||||
static synchronized <T extends DbEntity> void delData(SQLiteDatabase db, Class<T> clazz,
|
||||
String... expression) {
|
||||
db = checkDb(db);
|
||||
CheckUtil.checkSqlExpression(expression);
|
||||
|
||||
//List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
//for (Field field : fields) {
|
||||
// if (SqlUtil.isOneToOne(field)) {
|
||||
// OneToOne oto = field.getAnnotation(OneToOne.class);
|
||||
// delData(db, oto.table(), oto.key() + "=?", );
|
||||
// } else if (SqlUtil.isOneToMany(field)) {
|
||||
// OneToMany otm = field.getAnnotation(OneToMany.class);
|
||||
// delData(db, otm.table(), otm.key() + "=?", otm.key());
|
||||
// }
|
||||
//}
|
||||
|
||||
String sql = "DELETE FROM " + CommonUtil.getClassName(clazz) + " WHERE " + expression[0] + " ";
|
||||
sql = sql.replace("?", "%s");
|
||||
Object[] params = new String[expression.length - 1];
|
||||
for (int i = 0, len = params.length; i < len; i++) {
|
||||
params[i] = "'" + expression[i + 1] + "'";
|
||||
}
|
||||
sql = String.format(sql, params);
|
||||
SqlHelper.print(DEL_DATA, sql);
|
||||
db.execSQL(sql);
|
||||
close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改某行数据
|
||||
*/
|
||||
static synchronized void modifyData(SQLiteDatabase db, DbEntity dbEntity) {
|
||||
db = checkDb(db);
|
||||
Class<?> clazz = dbEntity.getClass();
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
DbEntity cacheEntity = mDataCache.get(getCacheKey(dbEntity));
|
||||
if (fields != null && fields.size() > 0) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
StringBuilder prams = new StringBuilder();
|
||||
sql.append("UPDATE ").append(CommonUtil.getClassName(dbEntity)).append(" SET ");
|
||||
int i = 0;
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (SqlUtil.ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
//创建一个原本的表
|
||||
mDelegate.createTable(db, clazz);
|
||||
//插入数据
|
||||
if (list != null && list.size() > 0) {
|
||||
DelegateUpdate update = DelegateManager.getInstance().getDelegate(DelegateUpdate.class);
|
||||
try {
|
||||
if (cacheEntity != null
|
||||
&& field.get(dbEntity) == field.get(cacheEntity)
|
||||
&& !field.getName().equals("state")) { //在LruCache中 state字段总是不能重新赋值...
|
||||
//if (dbEntity instanceof DownloadEntity && field.getName().equals("state")) {
|
||||
// Log.i(TAG, "cacheState => "
|
||||
// + ((DownloadEntity) cacheEntity).getState()
|
||||
// + ", newState => "
|
||||
// + ((DownloadEntity) dbEntity).getState());
|
||||
//}
|
||||
continue;
|
||||
for (DbEntity entity : list) {
|
||||
update.insertData(db, entity);
|
||||
}
|
||||
|
||||
//sb.append(i > 0 ? ", " : "");
|
||||
//sb.append(field.getName()).append("='");
|
||||
String value;
|
||||
prams.append(i > 0 ? ", " : "");
|
||||
prams.append(field.getName()).append("='");
|
||||
Type type = field.getType();
|
||||
if (type == Map.class) {
|
||||
value = SqlUtil.map2Str((Map<String, String>) field.get(dbEntity));
|
||||
} else if (type == List.class) {
|
||||
if (SqlUtil.isOneToMany(field)) {
|
||||
value = SqlUtil.getOneToManyElementParams(field);
|
||||
} else {
|
||||
value = SqlUtil.list2Str(dbEntity, field);
|
||||
}
|
||||
} else if (SqlUtil.isOneToOne(field)) {
|
||||
value = SqlUtil.getOneToOneParams(field);
|
||||
} else {
|
||||
Object obj = field.get(dbEntity);
|
||||
value = obj == null ? "" : checkValue(obj.toString());
|
||||
}
|
||||
|
||||
//sb.append(value == null ? "" : value);
|
||||
//sb.append("'");
|
||||
prams.append(TextUtils.isEmpty(value) ? "" : value);
|
||||
prams.append("'");
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!TextUtils.isEmpty(prams.toString())) {
|
||||
sql.append(prams.toString());
|
||||
sql.append(" where rowid=").append(dbEntity.rowID);
|
||||
print(MODIFY_DATA, sql.toString());
|
||||
db.execSQL(sql.toString());
|
||||
}
|
||||
}
|
||||
mDataCache.put(getCacheKey(dbEntity), dbEntity);
|
||||
close(db);
|
||||
}
|
||||
|
||||
private static String getCacheKey(DbEntity dbEntity) {
|
||||
return dbEntity.getClass().getName() + "_" + dbEntity.rowID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
static synchronized void insertData(SQLiteDatabase db, DbEntity dbEntity) {
|
||||
db = checkDb(db);
|
||||
Class<?> clazz = dbEntity.getClass();
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
if (fields != null && fields.size() > 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("INSERT INTO ").append(CommonUtil.getClassName(dbEntity)).append("(");
|
||||
int i = 0;
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (SqlUtil.ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(i > 0 ? ", " : "");
|
||||
sb.append(field.getName());
|
||||
i++;
|
||||
}
|
||||
sb.append(") VALUES (");
|
||||
i = 0;
|
||||
try {
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (SqlUtil.ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(i > 0 ? ", " : "");
|
||||
sb.append("'");
|
||||
Type type = field.getType();
|
||||
if (type == Map.class) {
|
||||
sb.append(SqlUtil.map2Str((Map<String, String>) field.get(dbEntity)));
|
||||
} else if (type == List.class) {
|
||||
if (SqlUtil.isOneToMany(field)) {
|
||||
sb.append(SqlUtil.getOneToManyElementParams(field));
|
||||
} else {
|
||||
sb.append(SqlUtil.list2Str(dbEntity, field));
|
||||
}
|
||||
} else if (SqlUtil.isOneToOne(field)) {
|
||||
sb.append(SqlUtil.getOneToOneParams(field));
|
||||
} else {
|
||||
sb.append(checkValue(field.get(dbEntity).toString()));
|
||||
}
|
||||
sb.append("'");
|
||||
i++;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
sb.append(")");
|
||||
print(INSERT_DATA, sb.toString());
|
||||
db.execSQL(sb.toString());
|
||||
}
|
||||
close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找表是否存在
|
||||
*
|
||||
* @param clazz 数据库实体
|
||||
* @return true,该数据库实体对应的表存在;false,不存在
|
||||
*/
|
||||
static synchronized boolean tableExists(SQLiteDatabase db, Class clazz) {
|
||||
return tableExists(db, CommonUtil.getClassName(clazz));
|
||||
}
|
||||
|
||||
static synchronized boolean tableExists(SQLiteDatabase db, String tableName) {
|
||||
db = checkDb(db);
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name='");
|
||||
sb.append(tableName);
|
||||
sb.append("'");
|
||||
print(TABLE_EXISTS, sb.toString());
|
||||
cursor = db.rawQuery(sb.toString(), null);
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
int count = cursor.getInt(0);
|
||||
if (count > 0) {
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
ALog.e(TAG, CommonUtil.getPrintException(e));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
|
||||
//删除中介表
|
||||
mDelegate.dropTable(db, tableName + "_temp");
|
||||
|
||||
mDelegate.close(db);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表
|
||||
*
|
||||
* @param clazz 数据库实体
|
||||
* @param tableName 数据库实体的类名
|
||||
*/
|
||||
static synchronized void createTable(SQLiteDatabase db, Class clazz, String tableName) {
|
||||
db = checkDb(db);
|
||||
createFTSTable(db);
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
if (fields != null && fields.size() > 0) {
|
||||
//外键Map,在Sqlite3中foreign修饰的字段必须放在最后
|
||||
final List<Field> foreignArray = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
//sb.append("create VIRTUAL table ")
|
||||
sb.append("create table ")
|
||||
.append(TextUtils.isEmpty(tableName) ? CommonUtil.getClassName(clazz) : tableName)
|
||||
//.append(" USING fts4(");
|
||||
.append(" (");
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (SqlUtil.ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
Class<?> type = field.getType();
|
||||
sb.append(field.getName());
|
||||
if (type == String.class || SqlUtil.isOneToOne(field) || type.isEnum()) {
|
||||
sb.append(" varchar");
|
||||
} else if (type == int.class || type == Integer.class) {
|
||||
sb.append(" interger");
|
||||
} else if (type == float.class || type == Float.class) {
|
||||
sb.append(" float");
|
||||
} else if (type == double.class || type == Double.class) {
|
||||
sb.append(" double");
|
||||
} else if (type == long.class || type == Long.class) {
|
||||
sb.append(" bigint");
|
||||
} else if (type == boolean.class || type == Boolean.class) {
|
||||
sb.append(" boolean");
|
||||
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
|
||||
sb.append(" data");
|
||||
} else if (type == byte.class || type == Byte.class) {
|
||||
sb.append(" blob");
|
||||
} else if (type == Map.class || type == List.class) {
|
||||
sb.append(" text");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (SqlUtil.isPrimary(field)) {
|
||||
//sb.append(" PRIMARY KEY");
|
||||
|
||||
}
|
||||
if (SqlUtil.isForeign(field)) {
|
||||
//foreignArray.add(field);
|
||||
}
|
||||
|
||||
if (SqlUtil.isNoNull(field)) {
|
||||
sb.append(" NOT NULL");
|
||||
}
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
for (Field field : foreignArray) {
|
||||
Foreign foreign = field.getAnnotation(Foreign.class);
|
||||
sb.append("FOREIGN KEY (")
|
||||
.append(field.getName())
|
||||
.append(") REFERENCES ")
|
||||
.append(CommonUtil.getClassName(foreign.table()))
|
||||
.append("(")
|
||||
.append(foreign.column())
|
||||
.append("),");
|
||||
}
|
||||
|
||||
String str = sb.toString();
|
||||
str = str.substring(0, str.length() - 1) + ");";
|
||||
print(CREATE_TABLE, str);
|
||||
db.execSQL(str);
|
||||
}
|
||||
close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建分词表
|
||||
*/
|
||||
private static void createFTSTable(SQLiteDatabase db) {
|
||||
String tableName = "ariaFts";
|
||||
String sql = "CREATE VIRTUAL TABLE " + tableName + " USING fts4(tokenize= porter)";
|
||||
if (!tableExists(db, tableName)) {
|
||||
db.execSQL(sql);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印数据库日志
|
||||
*
|
||||
* @param type {@link DbUtil}
|
||||
*/
|
||||
static void print(int type, String sql) {
|
||||
if (true) {
|
||||
return;
|
||||
}
|
||||
String str = "";
|
||||
switch (type) {
|
||||
case CREATE_TABLE:
|
||||
str = "创建表 >>>> ";
|
||||
break;
|
||||
case TABLE_EXISTS:
|
||||
str = "表是否存在 >>>> ";
|
||||
break;
|
||||
case INSERT_DATA:
|
||||
str = "插入数据 >>>> ";
|
||||
break;
|
||||
case MODIFY_DATA:
|
||||
str = "修改数据 >>>> ";
|
||||
break;
|
||||
case FIND_DATA:
|
||||
str = "查询一行数据 >>>> ";
|
||||
break;
|
||||
case FIND_ALL_DATA:
|
||||
str = "遍历整个数据库 >>>> ";
|
||||
break;
|
||||
}
|
||||
ALog.v(TAG, str + sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据游标创建一个具体的对象
|
||||
*/
|
||||
private static synchronized <T extends DbEntity> List<T> newInstanceEntity(SQLiteDatabase db,
|
||||
Class<T> clazz, Cursor cursor) {
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
List<T> entitys = new ArrayList<>();
|
||||
if (fields != null && fields.size() > 0) {
|
||||
try {
|
||||
while (cursor.moveToNext()) {
|
||||
T entity = clazz.newInstance();
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (SqlUtil.ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
Class<?> type = field.getType();
|
||||
int column = cursor.getColumnIndex(field.getName());
|
||||
if (column == -1) continue;
|
||||
if (type == String.class) {
|
||||
field.set(entity, URLDecoder.decode(cursor.getString(column)));
|
||||
} else if (type == int.class || type == Integer.class) {
|
||||
field.setInt(entity, cursor.getInt(column));
|
||||
} else if (type == float.class || type == Float.class) {
|
||||
field.setFloat(entity, cursor.getFloat(column));
|
||||
} else if (type == double.class || type == Double.class) {
|
||||
field.setDouble(entity, cursor.getDouble(column));
|
||||
} else if (type == long.class || type == Long.class) {
|
||||
field.setLong(entity, cursor.getLong(column));
|
||||
} else if (type == boolean.class || type == Boolean.class) {
|
||||
field.setBoolean(entity, !cursor.getString(column).equalsIgnoreCase("false"));
|
||||
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
|
||||
field.set(entity, new Date(cursor.getString(column)));
|
||||
} else if (type == byte[].class) {
|
||||
field.set(entity, cursor.getBlob(column));
|
||||
} else if (type == Map.class) {
|
||||
field.set(entity, SqlUtil.str2Map(cursor.getString(column)));
|
||||
} else if (type == List.class) {
|
||||
String value = cursor.getString(column);
|
||||
if (SqlUtil.isOneToMany(field)) {
|
||||
//主键字段
|
||||
String primaryKey = SqlUtil.getPrimaryName(clazz);
|
||||
if (TextUtils.isEmpty(primaryKey)) {
|
||||
throw new IllegalArgumentException("List中的元素对象必须需要@Primary注解的字段");
|
||||
}
|
||||
//list字段保存的数据
|
||||
int kc = cursor.getColumnIndex(primaryKey);
|
||||
String primaryData = cursor.getString(kc);
|
||||
if (TextUtils.isEmpty(primaryData)) continue;
|
||||
List<T> list = findForeignData(db, primaryData, value);
|
||||
if (list == null) continue;
|
||||
field.set(entity, findForeignData(db, primaryData, value));
|
||||
} else {
|
||||
field.set(entity, SqlUtil.str2List(value, field));
|
||||
}
|
||||
} else if (SqlUtil.isOneToOne(field)) {
|
||||
String primaryKey = SqlUtil.getPrimaryName(clazz);
|
||||
if (TextUtils.isEmpty(primaryKey)) {
|
||||
throw new IllegalArgumentException("@OneToOne的注解对象必须需要@Primary注解的字段");
|
||||
}
|
||||
int kc = cursor.getColumnIndex(primaryKey);
|
||||
String params = cursor.getString(column);
|
||||
String primaryData = cursor.getString(kc);
|
||||
if (TextUtils.isEmpty(primaryData) || primaryData.equalsIgnoreCase("null")) continue;
|
||||
List<T> list = findForeignData(db, primaryData, params);
|
||||
if (list != null && list.size() > 0) {
|
||||
field.set(entity, list.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid"));
|
||||
mDataCache.put(getCacheKey(entity), entity);
|
||||
entitys.add(entity);
|
||||
}
|
||||
closeCursor(cursor);
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return entitys;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找一对多、一对一的关联数据
|
||||
*
|
||||
* @param primary 当前表的主键
|
||||
* @param childParams 当前表关联数据的类名 $$ 主键名
|
||||
*/
|
||||
private static <T extends DbEntity> List<T> findForeignData(SQLiteDatabase db, String primary,
|
||||
String childParams) {
|
||||
String[] params = childParams.split("\\$\\$");
|
||||
return findData(db, params[0], params[1] + "=?", primary);
|
||||
}
|
||||
|
||||
private static void closeCursor(Cursor cursor) {
|
||||
if (cursor != null && !cursor.isClosed()) {
|
||||
try {
|
||||
cursor.close();
|
||||
} catch (android.database.SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void close(SQLiteDatabase db) {
|
||||
//if (db != null && db.isOpen()) db.close();
|
||||
}
|
||||
|
||||
private static SQLiteDatabase checkDb(SQLiteDatabase db) {
|
||||
if (db == null || !db.isOpen()) {
|
||||
db = INSTANCE.getWritableDatabase();
|
||||
}
|
||||
return db;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,14 @@
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.orm.annotation.Default;
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
import com.arialyy.aria.orm.annotation.Ignore;
|
||||
import com.arialyy.aria.orm.annotation.Many;
|
||||
import com.arialyy.aria.orm.annotation.NoNull;
|
||||
import com.arialyy.aria.orm.annotation.One;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
import com.arialyy.aria.orm.annotation.Wrapper;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
@@ -32,31 +40,41 @@ import java.util.Set;
|
||||
final class SqlUtil {
|
||||
|
||||
/**
|
||||
* 获取一对一参数
|
||||
* 获取主键字段名
|
||||
*/
|
||||
static String getOneToOneParams(Field field) {
|
||||
OneToOne oneToOne = field.getAnnotation(OneToOne.class);
|
||||
if (oneToOne == null) {
|
||||
throw new IllegalArgumentException("@OneToOne注解的对象必须要有@Primary注解的字段");
|
||||
static String getPrimaryName(Class clazz) {
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
String column;
|
||||
if (fields != null && !fields.isEmpty()) {
|
||||
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (isPrimary(field)) {
|
||||
column = field.getName();
|
||||
return column;
|
||||
}
|
||||
}
|
||||
}
|
||||
return oneToOne.table().getName() + "$$" + oneToOne.key();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取List一对多参数
|
||||
*
|
||||
* @param field list反射字段
|
||||
* 获取类中所有不被忽略的字段
|
||||
*/
|
||||
static String getOneToManyElementParams(Field field) {
|
||||
OneToMany oneToMany = field.getAnnotation(OneToMany.class);
|
||||
if (oneToMany == null) {
|
||||
throw new IllegalArgumentException("一对多元素必须被@OneToMany注解");
|
||||
static List<Field> getAllNotIgnoreField(Class clazz) {
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
List<Field> temp = new ArrayList<>();
|
||||
if (fields != null && fields.size() > 0) {
|
||||
for (Field f : fields) {
|
||||
f.setAccessible(true);
|
||||
if (!isIgnore(f)) {
|
||||
temp.add(f);
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
//关联的表名
|
||||
String tableName = oneToMany.table().getName();
|
||||
//关联的字段
|
||||
String key = oneToMany.key();
|
||||
return tableName + "$$" + key;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,10 +83,6 @@ final class SqlUtil {
|
||||
* @param field list反射字段
|
||||
*/
|
||||
static String list2Str(DbEntity dbEntity, Field field) throws IllegalAccessException {
|
||||
NormalList normalList = field.getAnnotation(NormalList.class);
|
||||
if (normalList == null) {
|
||||
throw new IllegalArgumentException("List中元素必须被@NormalList注解");
|
||||
}
|
||||
List list = (List) field.get(dbEntity);
|
||||
if (list == null || list.isEmpty()) return "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -85,17 +99,17 @@ final class SqlUtil {
|
||||
* @return 如果str为null,则返回null
|
||||
*/
|
||||
static List str2List(String str, Field field) {
|
||||
NormalList normalList = field.getAnnotation(NormalList.class);
|
||||
if (normalList == null) {
|
||||
throw new IllegalArgumentException("List中元素必须被@NormalList注解");
|
||||
}
|
||||
if (TextUtils.isEmpty(str)) return null;
|
||||
String[] datas = str.split("\\$\\$");
|
||||
List list = new ArrayList();
|
||||
String type = normalList.clazz().getName();
|
||||
for (String data : datas) {
|
||||
list.add(checkData(type, data));
|
||||
Class clazz = CommonUtil.getListParamType(field);
|
||||
if (clazz != null) {
|
||||
String type = clazz.getName();
|
||||
for (String data : datas) {
|
||||
list.add(checkData(type, data));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -152,9 +166,12 @@ final class SqlUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* shadow$_klass_、shadow$_monitor_、{@link Ignore}、rowID、{@link Field#isSynthetic()}、{@link
|
||||
* Modifier#isFinal(int)}、{@link Modifier#isStatic(int)}将被忽略
|
||||
*
|
||||
* @return true 忽略该字段
|
||||
*/
|
||||
static boolean ignoreField(Field field) {
|
||||
static boolean isIgnore(Field field) {
|
||||
// field.isSynthetic(), 使用as热启动App时,AS会自动给你的class添加change字段
|
||||
Ignore ignore = field.getAnnotation(Ignore.class);
|
||||
int modifiers = field.getModifiers();
|
||||
@@ -164,19 +181,29 @@ final class SqlUtil {
|
||||
.isStatic(modifiers) || Modifier.isFinal(modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是Wrapper注解
|
||||
*
|
||||
* @return {@code true} 是
|
||||
*/
|
||||
static boolean isWrapper(Class clazz) {
|
||||
Wrapper w = (Wrapper) clazz.getAnnotation(Wrapper.class);
|
||||
return w != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否一对多注解
|
||||
*/
|
||||
static boolean isOneToMany(Field field) {
|
||||
OneToMany oneToMany = field.getAnnotation(OneToMany.class);
|
||||
static boolean isMany(Field field) {
|
||||
Many oneToMany = field.getAnnotation(Many.class);
|
||||
return oneToMany != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是一对一注解
|
||||
*/
|
||||
static boolean isOneToOne(Field field) {
|
||||
OneToOne oneToOne = field.getAnnotation(OneToOne.class);
|
||||
static boolean isOne(Field field) {
|
||||
One oneToOne = field.getAnnotation(One.class);
|
||||
return oneToOne != null;
|
||||
}
|
||||
|
||||
@@ -210,6 +237,16 @@ final class SqlUtil {
|
||||
return nn != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是default
|
||||
*
|
||||
* @return {@code true}为default
|
||||
*/
|
||||
static boolean isDefault(Field field) {
|
||||
Default nn = field.getAnnotation(Default.class);
|
||||
return nn != null;
|
||||
}
|
||||
|
||||
private static Object checkData(String type, String data) {
|
||||
if (type.equalsIgnoreCase("java.lang.String")) {
|
||||
return data;
|
||||
@@ -222,17 +259,4 @@ final class SqlUtil {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找class的主键字段
|
||||
*
|
||||
* @return 返回主键字段名
|
||||
*/
|
||||
static String getPrimaryName(Class<? extends DbEntity> clazz) {
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
for (Field field : fields) {
|
||||
if (isPrimary(field)) return field.getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
package com.arialyy.aria.orm.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -21,16 +22,9 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/7/4.
|
||||
* 外键约束
|
||||
* Created by lyy on 2015/11/2.
|
||||
* 默认数据
|
||||
*/
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Foreign {
|
||||
/**
|
||||
* 关联的表
|
||||
*/
|
||||
Class<? extends DbEntity> table();
|
||||
/**
|
||||
* 关联的列
|
||||
*/
|
||||
String column();
|
||||
}
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Default {
|
||||
String value() default "";
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm.annotation;
|
||||
|
||||
import com.arialyy.aria.orm.ActionPolicy;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/7/4.
|
||||
* 外键约束
|
||||
*/
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Foreign {
|
||||
|
||||
/**
|
||||
* 关联的表
|
||||
*/
|
||||
Class<? extends DbEntity> parent();
|
||||
|
||||
/**
|
||||
* 父表对应的列名
|
||||
*/
|
||||
String column();
|
||||
|
||||
/**
|
||||
* ON UPDATE 约束
|
||||
*/
|
||||
ActionPolicy onUpdate() default ActionPolicy.NO_ACTION;
|
||||
|
||||
/**
|
||||
* ON DELETE 约束
|
||||
*/
|
||||
ActionPolicy onDelete() default ActionPolicy.NO_ACTION;
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.aria.orm;
|
||||
package com.arialyy.aria.orm.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
package com.arialyy.aria.orm.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -24,13 +24,14 @@ import java.lang.annotation.Target;
|
||||
* Created by AriaL on 2017/7/4.
|
||||
* 一对多
|
||||
*/
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface OneToMany {
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Many {
|
||||
/**
|
||||
* 关联的表
|
||||
* 父表对应的字段名
|
||||
*/
|
||||
Class<? extends DbEntity> table();
|
||||
String parentColumn();
|
||||
|
||||
/**
|
||||
* 关联的主键
|
||||
* 父表在子表对应的字段
|
||||
*/
|
||||
String key();
|
||||
String entityColumn();
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.aria.orm;
|
||||
package com.arialyy.aria.orm.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
package com.arialyy.aria.orm.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -22,17 +22,8 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/7/4.
|
||||
* 一对一
|
||||
* 一
|
||||
*/
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface OneToOne {
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface One {
|
||||
|
||||
/**
|
||||
* 关联的表
|
||||
*/
|
||||
Class<? extends DbEntity> table();
|
||||
|
||||
/**
|
||||
* 关联的主键
|
||||
*/
|
||||
String key();
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.aria.orm;
|
||||
package com.arialyy.aria.orm.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -27,4 +27,9 @@ import java.lang.annotation.Target;
|
||||
*/
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Primary {
|
||||
int value() default -1;
|
||||
|
||||
/**
|
||||
* 字段需要int类型才可以自增
|
||||
*/
|
||||
boolean autoincrement() default false;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.aria.orm.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/11/2.
|
||||
* 设置表名,如果不是使用该注解,默认为类名
|
||||
*/
|
||||
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table {
|
||||
String tableName();
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
package com.arialyy.aria.orm.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -21,16 +21,9 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/7/4.
|
||||
* 主键和外键约束
|
||||
* Created by laoyuyu on 2018/3/21.
|
||||
* 关系包裹
|
||||
*/
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface PrimaryAndForeign {
|
||||
/**
|
||||
* 关联的表
|
||||
*/
|
||||
Class<? extends DbEntity> table();
|
||||
/**
|
||||
* 关联的列
|
||||
*/
|
||||
String column();
|
||||
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Wrapper {
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import android.util.Log;
|
||||
* Aria日志工具
|
||||
*/
|
||||
public class ALog {
|
||||
|
||||
public static final boolean DEBUG = true;
|
||||
public static final int LOG_LEVEL_VERBOSE = 2;
|
||||
public static final int LOG_LEVEL_DEBUG = 3;
|
||||
public static final int LOG_LEVEL_INFO = 4;
|
||||
|
||||
@@ -74,7 +74,8 @@ public class CheckUtil {
|
||||
* 检查下载实体
|
||||
*/
|
||||
public static void checkDownloadEntity(DownloadEntity entity) {
|
||||
entity.setUrl(checkUrl(entity.getUrl()));
|
||||
checkUrlInvalidThrow(entity.getUrl());
|
||||
entity.setUrl(entity.getUrl());
|
||||
checkPath(entity.getDownloadPath());
|
||||
}
|
||||
|
||||
@@ -88,9 +89,9 @@ public class CheckUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测下载链接是否合法,如果地址中path是"//"而不是"/"将会改为"/";
|
||||
* 检测url是否合法,如果url不合法,将抛异常
|
||||
*/
|
||||
public static String checkUrl(String url) {
|
||||
public static void checkUrlInvalidThrow(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
throw new IllegalArgumentException("url不能为null");
|
||||
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
|
||||
@@ -100,7 +101,26 @@ public class CheckUtil {
|
||||
if (index == -1) {
|
||||
throw new IllegalArgumentException("url不合法");
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测url是否合法
|
||||
*
|
||||
* @return {@code true} 合法,{@code false} 非法
|
||||
*/
|
||||
public static boolean checkUrl(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
ALog.e(TAG, "url不能为null");
|
||||
return false;
|
||||
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
|
||||
ALog.e(TAG, "url【" + url + "】错误");
|
||||
return false;
|
||||
}
|
||||
int index = url.indexOf("://");
|
||||
if (index == -1) {
|
||||
ALog.e(TAG, "url【" + url + "】不合法");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,13 +30,10 @@ import com.arialyy.aria.core.command.group.GroupCmdFactory;
|
||||
import com.arialyy.aria.core.command.normal.AbsNormalCmd;
|
||||
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
|
||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.upload.UploadTaskEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
@@ -46,11 +43,8 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URLEncoder;
|
||||
@@ -62,6 +56,7 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -73,6 +68,64 @@ import java.util.regex.Pattern;
|
||||
public class CommonUtil {
|
||||
private static final String TAG = "CommonUtil";
|
||||
|
||||
/**
|
||||
* 获取map泛型类型
|
||||
*
|
||||
* @param map list类型字段
|
||||
* @return 泛型类型
|
||||
*/
|
||||
public static Class[] getMapParamType(Field map) {
|
||||
Class type = map.getType();
|
||||
if (!type.isAssignableFrom(Map.class)) {
|
||||
ALog.d(TAG, "字段类型不是Map");
|
||||
return null;
|
||||
}
|
||||
|
||||
Type fc = map.getGenericType();
|
||||
|
||||
if (fc == null) {
|
||||
ALog.d(TAG, "该字段没有泛型参数");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (fc instanceof ParameterizedType) {
|
||||
ParameterizedType pt = (ParameterizedType) fc;
|
||||
Type[] types = pt.getActualTypeArguments();
|
||||
Class[] clazz = new Class[2];
|
||||
clazz[0] = (Class) types[0];
|
||||
clazz[1] = (Class) types[1];
|
||||
return clazz;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取list泛型类型
|
||||
*
|
||||
* @param list list类型字段
|
||||
* @return 泛型类型
|
||||
*/
|
||||
public static Class getListParamType(Field list) {
|
||||
Class type = list.getType();
|
||||
if (!type.isAssignableFrom(List.class)) {
|
||||
ALog.d(TAG, "字段类型不是List");
|
||||
return null;
|
||||
}
|
||||
|
||||
Type fc = list.getGenericType(); // 关键的地方,如果是List类型,得到其Generic的类型
|
||||
|
||||
if (fc == null) {
|
||||
ALog.d(TAG, "该字段没有泛型参数");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (fc instanceof ParameterizedType) { //如果是泛型参数的类型
|
||||
ParameterizedType pt = (ParameterizedType) fc;
|
||||
return (Class) pt.getActualTypeArguments()[0]; //得到泛型里的class类型对象。
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文件名,如果url链接有后缀名,则使用url中的后缀名
|
||||
*
|
||||
@@ -230,55 +283,6 @@ public class CommonUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化泛型的实际类型参数
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void typeCheck(Type type) throws Exception {
|
||||
System.out.println("该类型是" + type);
|
||||
// 参数化类型
|
||||
if (type instanceof ParameterizedType) {
|
||||
Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
|
||||
for (int i = 0; i < typeArguments.length; i++) {
|
||||
// 类型变量
|
||||
if (typeArguments[i] instanceof TypeVariable) {
|
||||
System.out.println("第" + (i + 1) + "个泛型参数类型是类型变量" + typeArguments[i] + ",无法实例化。");
|
||||
}
|
||||
// 通配符表达式
|
||||
else if (typeArguments[i] instanceof WildcardType) {
|
||||
System.out.println("第" + (i + 1) + "个泛型参数类型是通配符表达式" + typeArguments[i] + ",无法实例化。");
|
||||
}
|
||||
// 泛型的实际类型,即实际存在的类型
|
||||
else if (typeArguments[i] instanceof Class) {
|
||||
System.out.println("第" + (i + 1) + "个泛型参数类型是:" + typeArguments[i] + ",可以直接实例化对象");
|
||||
}
|
||||
}
|
||||
// 参数化类型数组或类型变量数组
|
||||
} else if (type instanceof GenericArrayType) {
|
||||
System.out.println("该泛型类型是参数化类型数组或类型变量数组,可以获取其原始类型。");
|
||||
Type componentType = ((GenericArrayType) type).getGenericComponentType();
|
||||
// 类型变量
|
||||
if (componentType instanceof TypeVariable) {
|
||||
System.out.println("该类型变量数组的原始类型是类型变量" + componentType + ",无法实例化。");
|
||||
}
|
||||
// 参数化类型,参数化类型数组或类型变量数组
|
||||
// 参数化类型数组或类型变量数组也可以是多维的数组,getGenericComponentType()方法仅仅是去掉最右边的[]
|
||||
else {
|
||||
// 递归调用方法自身
|
||||
typeCheck(componentType);
|
||||
}
|
||||
} else if (type instanceof TypeVariable) {
|
||||
System.out.println("该类型是类型变量");
|
||||
} else if (type instanceof WildcardType) {
|
||||
System.out.println("该类型是通配符表达式");
|
||||
} else if (type instanceof Class) {
|
||||
System.out.println("该类型不是泛型类型");
|
||||
} else {
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据下载任务组的url创建key
|
||||
*
|
||||
@@ -308,28 +312,27 @@ public class CommonUtil {
|
||||
* {@code false}如果任务已经完成,只删除任务数据库记录
|
||||
*/
|
||||
public static void delDownloadGroupTaskConfig(boolean removeFile,
|
||||
DownloadGroupTaskEntity tEntity) {
|
||||
List<DownloadTaskEntity> tasks =
|
||||
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", tEntity.key);
|
||||
if (tasks != null && !tasks.isEmpty()) {
|
||||
for (DownloadTaskEntity taskEntity : tasks) {
|
||||
delDownloadTaskConfig(removeFile, taskEntity);
|
||||
}
|
||||
DownloadGroupEntity groupEntity) {
|
||||
if (groupEntity == null) {
|
||||
ALog.e(TAG, "删除下载任务组记录失败,任务组实体为null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tEntity.getEntity() != null) {
|
||||
File dir = new File(tEntity.getEntity().getDirPath());
|
||||
if (removeFile) {
|
||||
if (dir.exists()) {
|
||||
dir.delete();
|
||||
}
|
||||
} else {
|
||||
if (!tEntity.getEntity().isComplete()) {
|
||||
dir.delete();
|
||||
}
|
||||
}
|
||||
tEntity.deleteData();
|
||||
for (DownloadEntity taskEntity : groupEntity.getSubTask()) {
|
||||
delDownloadTaskConfig(removeFile, taskEntity);
|
||||
}
|
||||
|
||||
File dir = new File(groupEntity.getDirPath());
|
||||
if (removeFile) {
|
||||
if (dir.exists()) {
|
||||
dir.delete();
|
||||
}
|
||||
} else {
|
||||
if (!groupEntity.isComplete()) {
|
||||
dir.delete();
|
||||
}
|
||||
}
|
||||
groupEntity.deleteData();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,8 +341,7 @@ public class CommonUtil {
|
||||
* @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经删除完成的文件
|
||||
* {@code false}如果任务已经完成,只删除任务数据库记录
|
||||
*/
|
||||
public static void delUploadTaskConfig(boolean removeFile, UploadTaskEntity tEntity) {
|
||||
UploadEntity uEntity = tEntity.getEntity();
|
||||
public static void delUploadTaskConfig(boolean removeFile, UploadEntity uEntity) {
|
||||
if (uEntity == null) {
|
||||
return;
|
||||
}
|
||||
@@ -353,8 +355,8 @@ public class CommonUtil {
|
||||
if (config.exists()) {
|
||||
config.delete();
|
||||
}
|
||||
//uEntity.deleteData();
|
||||
tEntity.deleteData();
|
||||
//下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除
|
||||
uEntity.deleteData();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,8 +365,7 @@ public class CommonUtil {
|
||||
* @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经下载完成的文件
|
||||
* {@code false}如果任务已经完成,只删除任务数据库记录
|
||||
*/
|
||||
public static void delDownloadTaskConfig(boolean removeFile, DownloadTaskEntity tEntity) {
|
||||
DownloadEntity dEntity = tEntity.getEntity();
|
||||
public static void delDownloadTaskConfig(boolean removeFile, DownloadEntity dEntity) {
|
||||
if (dEntity == null) return;
|
||||
File file = new File(dEntity.getDownloadPath());
|
||||
if (removeFile) {
|
||||
@@ -383,9 +384,8 @@ public class CommonUtil {
|
||||
if (config.exists()) {
|
||||
config.delete();
|
||||
}
|
||||
//dEntity.deleteData();
|
||||
//tEntity.deleteData();
|
||||
tEntity.deleteData();
|
||||
//下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除
|
||||
dEntity.deleteData();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,6 +35,8 @@ public class ErrorHelp {
|
||||
* @param msg 错误提示
|
||||
* @param ex 异常
|
||||
*/
|
||||
// TODO: 2018/4/4 错误应该写在文件中
|
||||
@Deprecated
|
||||
public static void saveError(String taskType, AbsEntity entity, String msg, String ex) {
|
||||
ErrorEntity errorEntity = new ErrorEntity();
|
||||
errorEntity.insertTime = System.currentTimeMillis();
|
||||
|
||||
@@ -45,7 +45,7 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
|
||||
Aria.download(this).register();
|
||||
setTitle("任务组");
|
||||
mUrls = getModule(GroupModule.class).getUrls();
|
||||
DownloadGroupTaskEntity entity = Aria.download(this).getDownloadGroupTask(mUrls);
|
||||
DownloadGroupTaskEntity entity = Aria.download(this).getGroupTask(mUrls);
|
||||
if (entity != null && entity.getEntity() != null) {
|
||||
DownloadGroupEntity groupEntity = entity.getEntity();
|
||||
mChildList.addData(groupEntity.getSubTask());
|
||||
@@ -84,7 +84,7 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
|
||||
Environment.getExternalStorageDirectory().getPath() + "/Download/group_test_3")
|
||||
.setGroupAlias("任务组测试")
|
||||
.setSubFileName(getModule(GroupModule.class).getSubName())
|
||||
//.setFileSize(32895492)
|
||||
.setFileSize(32895492)
|
||||
.start();
|
||||
break;
|
||||
case R.id.stop:
|
||||
|
||||
@@ -43,7 +43,7 @@ public class FTPDirDownloadActivity extends BaseActivity<ActivityDownloadGroupBi
|
||||
super.init(savedInstanceState);
|
||||
Aria.download(this).register();
|
||||
setTitle("FTP文件夹下载");
|
||||
DownloadGroupTaskEntity entity = Aria.download(this).getDownloadGroupTask(dir);
|
||||
DownloadGroupTaskEntity entity = Aria.download(this).getFtpDirTask(dir);
|
||||
if (entity != null && entity.getEntity() != null) {
|
||||
DownloadGroupEntity groupEntity = entity.getEntity();
|
||||
mChildList.addData(groupEntity.getSubTask());
|
||||
|
||||
@@ -26,16 +26,12 @@ import butterknife.Bind;
|
||||
import com.arialyy.annotations.Download;
|
||||
import com.arialyy.annotations.DownloadGroup;
|
||||
import com.arialyy.aria.core.Aria;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTask;
|
||||
import com.arialyy.aria.core.download.DownloadTask;
|
||||
import com.arialyy.aria.core.inf.AbsEntity;
|
||||
import com.arialyy.frame.util.FileUtil;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
import com.arialyy.simple.R;
|
||||
import com.arialyy.simple.base.BaseActivity;
|
||||
import com.arialyy.simple.databinding.ActivityMultiDownloadBinding;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -55,7 +51,7 @@ public class MultiDownloadActivity extends BaseActivity<ActivityMultiDownloadBin
|
||||
super.init(savedInstanceState);
|
||||
Aria.download(this).register();
|
||||
setTitle("下载列表");
|
||||
List<AbsEntity> temps = Aria.download(this).getTotleTaskList();
|
||||
List<AbsEntity> temps = Aria.download(this).getTotalTaskList();
|
||||
if (temps != null && !temps.isEmpty()) {
|
||||
mData.addAll(temps);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
package com.arialyy.aria.core.upload;
|
||||
|
||||
import com.arialyy.aria.core.inf.AbsNormalTaskEntity;
|
||||
import com.arialyy.aria.orm.OneToOne;
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
import com.arialyy.aria.orm.annotation.Ignore;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -28,9 +30,16 @@ public class UploadTaskEntity extends AbsNormalTaskEntity<UploadEntity> {
|
||||
public String attachment; //文件上传需要的key
|
||||
public String contentType = "multipart/form-data"; //上传的文件类型
|
||||
public String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)";
|
||||
@OneToOne(table = UploadEntity.class, key = "filePath") public UploadEntity entity;
|
||||
|
||||
//@OneToOne(table = UploadEntity.class, key = "filePath") public UploadEntity entity;
|
||||
|
||||
@Ignore public UploadEntity entity;
|
||||
|
||||
public String filePath = "";
|
||||
|
||||
@Primary @Foreign(parent = UploadEntity.class, column = "filePath")
|
||||
public String key;
|
||||
|
||||
/**
|
||||
* 文件上传表单
|
||||
*/
|
||||
@@ -43,11 +52,17 @@ public class UploadTaskEntity extends AbsNormalTaskEntity<UploadEntity> {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void save(UploadEntity entity) {
|
||||
filePath = entity.getFilePath();
|
||||
key = entity.getKey();
|
||||
this.entity = entity;
|
||||
entity.save();
|
||||
if (entity != null) {
|
||||
filePath = entity.getFilePath();
|
||||
key = entity.getKey();
|
||||
this.entity = entity;
|
||||
entity.save();
|
||||
}
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user