2025-06-09 22:12:42.286 31140-31140 getEndpoint com.example.kucun2 D getEndpoint: url_add_Dingdan
2025-06-09 22:12:42.290 31140-31140 System.err com.example.kucun2 W R绫绘湭鎵惧埌: com.example.kucun2.R$String
2025-06-09 22:12:42.324 31140-31140 getEndpoint com.example.kucun2 D endpoint: nullpackage com.example.kucun2.entity.data;
import android.util.Log;
import com.example.kucun2.function.MyAppFnction;
public abstract class SynchronizableEntity implements EntityClassGrassrootsid {
/**
* 添加url
* @param type 操作增删改查
* @return 返回相对url
*/
public String getEndpoint(String type){
//从String.xml获取url
Log.d("getEndpoint", "getEndpoint: "+"url_"+type+"_"+this.getClass().getSimpleName());
return MyAppFnction.getStringResource("String","url_"+type+"_"+this.getClass().getSimpleName());
}
}
package com.example.kucun2.entity.data;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.gson.Gson;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
支持数据变更自动同步的泛型集合类
@param <T> 继承自 SynchronizableEntity 的实体类型
*/
public class SynchronizedList<T extends EntityClassGrassrootsid> implements List<T> {
private final List<T> list = new ArrayList<>();
private final OkHttpClient client = new OkHttpClient();
private static final Gson gson = new Gson();
private static final MediaType JSON = MediaType.get(“application/json; charset=utf-8”);
private final Class<T> entityClass; // 类型标记
// 添加批量操作模式标志
private boolean batchMode = false;
// 属性变更监听器
private final List<PropertyChangeListener<T>> listeners = new ArrayList<>();
// 直接接受Class参数的构造函数
public SynchronizedList(Class<T> entityClass) {
this.entityClass = entityClass;
}
// 安全的类型转换方法
private T safeCast(Object o) {
if (o != null && entityClass.isInstance(o)) {
return entityClass.cast(o);
}
return null;
}
public interface PropertyChangeListener<T> {
void onPropertyChange(T entity, String propertyName, Object oldValue, Object newValue);
}
public void addPropertyChangeListener(PropertyChangeListener<T> listener) {
listeners.add(listener);
}
public void removePropertyChangeListener(PropertyChangeListener<T> listener) {
listeners.remove(listener);
}
// 添加方法来获取原始对象
@SuppressWarnings(“unchecked”)
public T getOriginal(T proxy) {
if (proxy == null) return null;
// 检查是否为代理对象
if (java.lang.reflect.Proxy.isProxyClass(proxy.getClass())) {
try {
java.lang.reflect.InvocationHandler handler =
java.lang.reflect.Proxy.getInvocationHandler(proxy);
if (handler instanceof IProxyHandler) {
Object original = ((IProxyHandler) handler).getOriginal();
// 安全类型检查
if (entityClass.isInstance(original)) {
return (T) original;
}
}
} catch (Exception e) {
Log.e("SynchronizedList", "Failed to get proxy handler", e);
}
}
return proxy;
}
/**
同步实体到后端
@param entity 要同步的实体
*/
private void syncEntity(T entity) {
if (batchMode) return;
String operation = “add”;
T originalEntity = getOriginal(entity);
String endpoint = originalEntity.getEndpoint(operation);
String json = gson.toJson(originalEntity);
Log.d(“getEndpoint”, "endpoint: "+endpoint);
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url(endpoint)
.method(getHttpMethod(operation), body)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.e(“SynchronizedList”, "同步失败: " + entity.getClass().getSimpleName(), e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
if (!response.isSuccessful()) {
Log.e("SynchronizedList", "同步失败: " +
response.code() + " - " + response.message());
}
response.close();
}
});
}
// 添加用于批量操作的方法
public void beginBatch() {
this.batchMode = true;
}
public void endBatch() {
this.batchMode = false;
// 批量结束后触发一次全量同步
syncAllEntities();
}
private void syncAllEntities() {
for (T entity : list) {
syncEntity(entity);
}
}
private String getHttpMethod(String operation) {
switch (operation) {
case “add”:
return “POST”;
case “update”:
return “PUT”;
case “delete”:
return “DELETE”;
default:
return “POST”;
}
}
// 获取类实现的所有接口(包括父类接口)
private Class<?>[] getInterfaces(Class<?> clazz) {
Set<Class<?>> interfaces = new HashSet<>();
while (clazz != null) {
interfaces.addAll(Arrays.asList(clazz.getInterfaces()));
clazz = clazz.getSuperclass();
}
return interfaces.toArray(new Class<?>[0]);
}
/**
创建代理对象,用于监听属性变更 */
// 优化 createProxy 方法
private T createProxy(T original) {
if (original == null) return null;
// 获取实体类实现的所有接口
Set<Class<?>> interfaces = new HashSet<>();
Class<?> clazz = original.getClass();
// 收集所有接口,包括继承链中的接口
while (clazz != null) {
interfaces.addAll(Arrays.asList(clazz.getInterfaces()));
clazz = clazz.getSuperclass();
}
// 创建代理对象
return (T) Proxy.newProxyInstance(
original.getClass().getClassLoader(),
interfaces.toArray(new Class<?>[0]),
new EntityProxyHandler(original)
);
// if (!entityClass.isInstance(original)) {
// throw new IllegalArgumentException(“Invalid entity type”);
// }
// // 这里使用动态代理模式监听setter方法调用
// return (T) java.lang.reflect.Proxy.newProxyInstance(
// original.getClass().getClassLoader(),
// original.getClass().getInterfaces(),
// (proxy, method, args) -> {
// // 只拦截setter方法
// if (method.getName().startsWith(“set”) && args.length == 1) {
// String propertyName = method.getName().substring(3);
// propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1);
//
// // 获取旧值
// Object oldValue = original.getClass()
// .getMethod(“get” + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1))
// .invoke(original);
//
// // 调用原始方法
// Object result = method.invoke(original, args);
//
// // 触发监听器
// for (PropertyChangeListener<T> listener : listeners) {
// listener.onPropertyChange(original, propertyName, oldValue, args[0]);
// }
//
// // 自动同步到后端
// syncEntity(original);
// return result;
// }
// return method.invoke(original, args);
// }
// );
}
// 以下是List接口的实现
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@NonNull
@Override
public Iterator<T> iterator() {
return list.iterator();
}
@NonNull
@Override
public Object[] toArray() {
return list.toArray();
}
@NonNull
@Override
public <T1> T1[] toArray(@NonNull T1[] a) {
return list.toArray(a);
}
@Override
public boolean add(T t) {
T proxy = createProxy(t);
boolean result = list.add(proxy);
if (!batchMode) {
syncEntity(proxy);
}
return result; // 添加时创建代理
}
@Override
public boolean remove(Object o) {
T entity = safeCast(o);
if (entity != null) {
syncEntity((T) entity); // 删除前同步
}
return list.remove(o);
}
@Override
public boolean containsAll(@NonNull Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(@NonNull Collection<? extends T> c) {
boolean modified = false;
for (T t : c) {
modified |= add(t);
}
return modified;
}
@Override
public boolean addAll(int index, @NonNull Collection<? extends T> c) {
for (T t : c) {
add(index++, t);
}
return true;
}
@Override
public boolean removeAll(@NonNull Collection<?> c) {
for (Object o : c) {
T entity = safeCast(o);
if (entity != null) {
syncEntity(entity);
}
}
return list.removeAll(c);
}
@Override
public boolean retainAll(@NonNull Collection<?> c) {
List<T> toRemove = new ArrayList<>();
for (T t : list) {
if (!c.contains(t)) {
toRemove.add(t);
}
}
// 使用安全转换
for (T entity : toRemove) {
syncEntity(entity);
}
return list.retainAll(c);
}
@Override
public void clear() {
for (T t : list) {
syncEntity(t); // 清空前同步
}
list.clear();
}
@Override
public T get(int index) {
return list.get(index);
}
@Override
public T set(int index, T element) {
T old = list.set(index, createProxy(element));
if (old != null) {
syncEntity(old); // 替换旧元素前同步
}
return old;
}
@Override
public void add(int index, T element) {
list.add(index, createProxy(element));
}
@Override
public T remove(int index) {
T removed = list.remove(index);
if (removed != null) {
syncEntity(removed); // 删除前同步
}
return removed;
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@NonNull
@Override
public ListIterator<T> listIterator() {
return list.listIterator();
}
@NonNull
@Override
public ListIterator<T> listIterator(int index) {
return list.listIterator(index);
}
@NonNull
@Override
public List<T> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
// 触发属性变更通知
// 添加类型安全的属性监听
private void firePropertyChange(T entity, String propertyName, Object oldValue, Object newValue) {
if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
return; // 值未变化时不触发监听
}
for (PropertyChangeListener<T> listener : listeners) {
try {
listener.onPropertyChange(entity, propertyName, oldValue, newValue);
} catch (Exception e) {
Log.e("SynchronizedList", "Listener error", e);
}
}
}
// 修改代理处理器以支持获取原始对象
/*
完整的 EntityProxyHandler
实现
*/
private class EntityProxyHandler implements IProxyHandler, java.lang.reflect.InvocationHandler {
private final T original;
private final Map<String, Object> propertyValues = new HashMap<>();
public EntityProxyHandler(T original) {
this.original = original;
cachePropertyValues();
}
private void cachePropertyValues() {
// 获取类信息
Class<?> clazz = original.getClass();
// 遍历所有getter方法
for (Method method : clazz.getMethods()) {
String methodName = method.getName();
// 只处理getter方法
if (methodName.startsWith("get") && !methodName.equals("getClass")
&& method.getParameterTypes().length == 0) {
try {
// 获取属性名(去掉"get"并将首字母小写)
String propertyName = methodName.substring(3);
propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
// 调用getter获取值
Object value = method.invoke(original);
propertyValues.put(propertyName, value);
} catch (Exception e) {
Log.e("Wrapper", "Failed to cache property " + methodName, e);
}
}
}
}
@Override
public T getOriginal() {
return original;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
// 只拦截setter方法
if (methodName.startsWith("set") && args != null && args.length == 1) {
String propertyName = methodName.substring(3);
propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
Object oldValue = propertyValues.get(propertyName);
Object newValue = args[0];
// 如果值未改变,不触发同步
if (Objects.equals(oldValue, newValue)) {
return null;
}
// 调用原始对象的setter方法
Method setter = original.getClass().getMethod(methodName, newValue.getClass());
setter.invoke(original, newValue);
// 更新属性缓存
propertyValues.put(propertyName, newValue);
// 触发属性变更监听
firePropertyChange(original, propertyName, oldValue, newValue);
// 非批量模式下自动同步
if (!batchMode) {
syncEntity(original);
}
}
// 其他接口方法直接调用原始对象
return method.invoke(original, args);
}
private Object getPropertyValue(String propertyName) {
String getterName = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
try {
Method getter = original.getClass().getMethod(getterName);
return getter.invoke(original);
} catch (Exception e) {
Log.e("ProxyHandler", "Failed to get property value: " + propertyName, e);
return null;
}
}
}
// 在 SynchronizedList 类中添加
private interface IProxyHandler {
Object getOriginal();
}
}package com.example.kucun2.entity.data;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.example.kucun2.entity.;
import com.example.kucun2.entity.data.SynchronizableEntity;
import com.example.kucun2.entity.data.SynchronizedList;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import okhttp3.;
import org.json.JSONObject;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class AppDataManager {
private final Context context;
private final OkHttpClient httpClient;
private final Gson gson;
private Map<String, SynchronizedList<? extends SynchronizableEntity>> dataCache;
private static final String BASE_URL = “https://tian.sef/Kucun2”;
private static final String API_ALL = “/app/all”;
public AppDataManager(Context context) {
this.context = context;
this.gson = new Gson();
this.dataCache = new HashMap<>();
this.httpClient = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
}
/**
* 从服务器加载完整数据集
*/
public void loadFullDataset(DataCallback callback) {
Request request = new Request.Builder()
.url(BASE_URL + API_ALL)
.build();
httpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.e("AppDataManager", "Failed to load full dataset", e);
callback.onFailure("Network error: " + e.getMessage());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (!response.isSuccessful()) {
callback.onFailure("HTTP error: " + response.code());
return;
}
try {
String jsonData = response.body().string();
JSONObject jsonObject = new JSONObject(jsonData);
JSONObject data = jsonObject.getJSONObject("data");
// 解析各实体列表
parseEntityList(data, "bancais", Bancai.class);
parseEntityList(data, "dingdans", Dingdan.class);
parseEntityList(data, "mupis", Mupi.class);
parseEntityList(data, "chanpins", Chanpin.class);
parseEntityList(data, "kucuns", Kucun.class);
parseEntityList(data, "chanpin_zujians", Chanpin_Zujian.class);
parseEntityList(data, "zujians", Zujian.class);
parseEntityList(data, "caizhis", Caizhi.class);
parseEntityList(data, "users", User.class);
callback.onSuccess();
} catch (Exception e) {
Log.e("AppDataManager", "Error parsing response", e);
callback.onFailure("Parsing error: " + e.getMessage());
}
}
});
}
/**
* 解析实体列表
*/
private <T extends SynchronizableEntity> void parseEntityList(JSONObject data, String key, Class<T> clazz) {
try {
Type listType = TypeToken.getParameterized(SynchronizedList.class, clazz).getType();
SynchronizedList<T> list = gson.fromJson(data.getString(key), listType);
dataCache.put(key, list);
} catch (Exception e) {
Log.e("AppDataManager", "Failed to parse " + key, e);
}
}
/**
* 添加实体到特定集合
*/
public <T extends SynchronizableEntity> void addEntity(T entity, Class<T> clazz, DataCallback callback) {
String endpoint = BASE_URL + getAddEndpointForClass(clazz);
RequestBody body = RequestBody.create(
gson.toJson(entity),
MediaType.parse("application/json")
);
Request request = new Request.Builder()
.url(endpoint)
.post(body)
.build();
httpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.e("AppDataManager", "Add entity failed", e);
callback.onFailure("Network error: " + e.getMessage());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.isSuccessful()) {
try {
T newEntity = gson.fromJson(response.body().string(), clazz);
SynchronizedList<T> list = (SynchronizedList<T>) dataCache.get(getCacheKeyForClass(clazz));
if (list != null) {
list.add(newEntity);
}
callback.onSuccess();
} catch (Exception e) {
callback.onFailure("Parsing error: " + e.getMessage());
}
} else {
callback.onFailure("API error: " + response.code());
}
}
});
}
/**
* 获取添加操作的API端点
*/
private <T> String getAddEndpointForClass(Class<T> clazz) {
// 基于简单的命名约定生成端点
String className = clazz.getSimpleName().toLowerCase();
return "/app/" + className + "/add";
}
/**
* 获取缓存键名
*/
private <T> String getCacheKeyForClass(Class<T> clazz) {
return clazz.getSimpleName().toLowerCase() + "s";
}
/**
* 从缓存获取实体列表
*/
@SuppressWarnings("unchecked")
public <T extends SynchronizableEntity> SynchronizedList<T> getEntityList(Class<T> clazz) {
String key = getCacheKeyForClass(clazz);
return (SynchronizedList<T>) dataCache.get(key);
}
/**
* 类型安全的实体更新方法
* @param entity 要更新的实体
* @param callback 操作回调
*/
@SuppressWarnings("unchecked")
public <T extends SynchronizableEntity> void updateEntity(T entity, DataCallback callback) {
// 使用实体类的实际类型
Class<T> entityClass = (Class<T>) entity.getClass();
updateEntity(entity, entityClass, callback);
}
/**
* 更新实体
*/
public <T extends SynchronizableEntity> void updateEntity(T entity, Class<T> clazz, DataCallback callback) {
String endpoint = BASE_URL + getUpdateEndpointForClass(clazz);
RequestBody body = RequestBody.create(
gson.toJson(entity),
MediaType.parse("application/json")
);
Request request = new Request.Builder()
.url(endpoint)
.put(body)
.build();
httpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure("Network error: " + e.getMessage());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.isSuccessful()) {
callback.onSuccess();
} else {
callback.onFailure("API error: " + response.code());
}
}
});
}
/**
* 获取更新操作的API端点
*/
private <T> String getUpdateEndpointForClass(Class<T> clazz) {
// 基于简单命名约定生成端点
String className = clazz.getSimpleName().toLowerCase();
return "/app/" + className + "/update";
}
/**
* 获取用户认证令牌
*/
public void authenticateUser(String username, String password, AuthCallback callback) {
JSONObject authJson = new JSONObject();
try {
authJson.put("username", username);
authJson.put("password", password);
} catch (Exception e) {
callback.onFailure("Auth parameter error");
return;
}
RequestBody body = RequestBody.create(
authJson.toString(),
MediaType.parse("application/json")
);
Request request = new Request.Builder()
.url(BASE_URL + "/user/login")
.post(body)
.build();
httpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure("Network error: " + e.getMessage());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.isSuccessful()) {
try {
JSONObject authResponse = new JSONObject(response.body().string());
String token = authResponse.getString("token");
callback.onSuccess(token);
} catch (Exception e) {
callback.onFailure("Token parsing error");
}
} else {
callback.onFailure("Authentication failed");
}
}
});
}
/**
* 数据加载回调接口
*/
public interface DataCallback {
void onSuccess();
void onFailure(String error);
}
/**
* 认证回调接口
*/
public interface AuthCallback {
void onSuccess(String token);
void onFailure(String error);
}
} E FATAL EXCEPTION: main
Process: com.example.kucun2, PID: 31140
java.lang.NullPointerException: Parameter specified as non-null is null: method okhttp3.Request$Builder.url, parameter url
at okhttp3.Request$Builder.url(Unknown Source:2)
at com.example.kucun2.entity.data.SynchronizedList.syncEntity(SynchronizedList.java:114)
at com.example.kucun2.entity.data.SynchronizedList.add(SynchronizedList.java:272)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment.createAndSaveDingdan(AddInventoryFragment.java:445)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment.lambda$showNewDingdanDialog$8(AddInventoryFragment.java:423)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment.$r8$lambda$viLBw5kNmkDSVG17JoXzuH5G85E(Unknown Source:0)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment$$ExternalSyntheticLambda20.onClick(D8$$SyntheticClass:0)
at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:250)
at android.os.Handler.dispatchMessage(Handler.java:109)
at android.os.Looper.loopOnce(Looper.java:250)
at android.os.Looper.loop(Looper.java:340)