活动介绍
file-type

实用Android判空工具类的实现与应用

下载需积分: 50 | 964B | 更新于2025-05-25 | 95 浏览量 | 1 下载量 举报 收藏
download 立即下载
在Android开发中,判空是一项经常进行的操作,其目的是为了避免空指针异常(NullPointerException)。空指针异常是在Java语言中最常见的运行时错误之一,通常发生在尝试使用一个尚未分配的内存地址时。为了提高代码的健壮性和稳定性,开发者往往会编写一些工具类来统一处理空值判断的问题。这类工具类通常包含了各种静态方法,可以方便地对各种可能为空的数据类型进行检查,例如字符串(String)、集合(Collection)、数组(Array)、Map等。 在给定的文件信息中,我们可以看出要生成的知识点应该围绕着一个名为“Android判空工具类”的工具类进行。这个工具类提供了两个基本的方法:“isEmpty”和“isNotEmpty”,用于判断传入对象是否为空或者非空。下面将详细介绍这两个方法,以及它们可能使用的场景和相关的编程实践。 ### isEmpty方法 isEmpty方法的用途是判断一个对象是否为null,或者是否为空字符串""(对于字符串对象)、空集合(对于集合对象)、空数组(对于数组对象)、空Map(对于Map对象)。这个方法在实际开发中非常实用,因为开发者经常会忘记检查这些情况。 - **对于字符串:** 检查字符串是否为null或者长度为0。 - **对于集合:** 检查集合是否为null或者集合中元素的个数为0。 - **对于数组:** 检查数组是否为null或者数组的长度为0。 - **对于Map:** 检查Map是否为null或者Map中不包含任何键值对。 ### isNotEmpty方法 与isEmpty方法相对应,isNotEmpty方法用来判断一个对象是否非空,即判断对象既不为null也不为空字符串、空集合、空数组或空Map。 ### 实际使用示例 ```java // 判断字符串是否为空 if (!StringUtils.isEmpty(text)) { // 字符串非空时的操作 } // 判断集合是否为空 if (!CollectionUtils.isNotEmpty(list)) { // 集合为空时的操作 } // 判断数组是否为空 if (!ArrayUtils.isNotEmpty(array)) { // 数组为空时的操作 } // 判断Map是否为空 if (!MapUtils.isNotEmpty(map)) { // Map为空时的操作 } ``` ### 注意事项 在使用判空工具类时,需要注意以下几点: 1. **不要过度使用判空:** 如果在方法开始时进行了大量的判空操作,可能会降低代码的可读性。应当在设计良好的程序结构中,尽量在数据被赋值时就保证其非空。 2. **明确空值的定义:** 有时候对象可能为null,但不代表它没有内容。例如,数据库查询时,可能得到的值为null,但这个null对于业务来说是有意义的,需要特殊处理,而不是直接认为其为空。 3. **使用合适的库:** 在Android开发中,可以使用Google的Guava库或者Apache Commons库中的相关工具类来简化判空操作。例如,Guava库中的`Strings.isNullOrEmpty(String)`方法可以直接用来判断字符串是否为空。 4. **空安全编程:** 随着Kotlin语言的流行,空安全(Null Safety)编程受到了越来越多的关注。Kotlin通过引入可空类型(Nullable types)和非空断言(Non-null assertions)来帮助开发者在编译时就避免空指针异常。 5. **避免空指针异常:** 要全面地考虑到各种可能为空的情况,确保代码在运行时不会因为空值而导致崩溃。比如在访问对象的属性或者调用对象的方法之前,都要进行判空操作。 ### 结语 一个好的编程习惯是尽量避免空值的产生,减少空值的传播。一个典型的例子是在数据传输过程中,尽可能地将数据初始化为有意义的默认值,而不是简单地传null值。这样可以在很大程度上减少空值判断的需要,使代码更加简洁和安全。 通过理解并掌握判空工具类的使用,可以有效提高Android应用的稳定性,避免空指针异常的发生,从而提升用户体验和应用的可靠性。同时,对于开发过程中的最佳实践要有清晰的认识,这样才能编写出高效且健壮的代码。

相关推荐

filetype
filetype

FATAL EXCEPTION: main Process: com.example.juble, PID: 7576 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.juble/com.example.juble.DataExchangeActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4112) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4263) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:114) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:144) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:101) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2724) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:255) at android.os.Looper.loop(Looper.java:364) at android.app.ActivityThread.main(ActivityThread.java:8979) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:572) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1053) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference at com.example.juble.DataExchangeActivity.onCreate(DataExchangeActivity.java:105) at android.app.Activity.performCreate(Activity.java:8780) at android.app.Activity.performCreate(Activity.java:8752) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1475) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4086) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4263)  at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:114)  at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:144)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:101)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2724)  at android.os.Handler.dispatchMessage(Handler.java:106)  at android.os.Looper.loopOnce(Looper.java:255)  at android.os.Looper.loop(Looper.java:364)  at android.app.ActivityThread.main(ActivityThread.java:8979)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:572)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1053)  2025-07-24 16:24:28.218 7576-7576 Process com.example.juble I Sending signal. PID: 7576 SIG: 9 ---------------------------- PROCESS ENDED (7576) for package com.example.juble ---------------------------- 2025-07-24 16:24:28.255 1692-1692 qspmHal vendor.qti.qspmhal-service E setAppInfoH atPid = 7576, gpuFname:com.example.juble, gpuFver:10解释并解决该错误

filetype

分析以下报错信息: E Failed to execute the transaction: tId:46941937 ClientTransaction{ tId:46941937 transactionItems=[ tId:46941937 LaunchActivityItem{activityToken=android.os.BinderProxy@2352e32,intent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 xflg=0x4 cmp=com.example.myapplication/.PhoneActivity },ident=86533630,info=ActivityInfo{4de83a1 com.example.myapplication.PhoneActivity},curConfig={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h866dp 420dpi nrml long port finger qwerty/v/v dpad/v winConfig={ mBounds=Rect(0, 0 - 1080, 2400) mAppBounds=Rect(0, 0 - 1080, 2337) mMaxBounds=Rect(0, 0 - 1080, 2400) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} s.44 fontWeightAdjustment=0},overrideConfig={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h866dp 420dpi nrml long port finger qwerty/v/v dpad/v winConfig={ mBounds=Rect(0, 0 - 1080, 2400) mAppBounds=Rect(0, 0 - 1080, 2337) mMaxBounds=Rect(0, 0 - 1080, 2400) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_0} s.2 fontWeightAdjustment=0},deviceId=0,referrer=com.android.shell,procState=2,state=null,persistentState=null,pendingResults=null,pendingNewIntents=null,sceneTransitionInfo=null,profilerInfo=null,assistToken=android.os.BinderProxy@8dea7fa,shareableActivityToken=android.os.BinderProxy@357e1ab,activityWindowInfo=ActivityWindowInfo{isEmbedded=false, taskBounds=Rect(0, 0 - 1080, 2400), taskFragmentBounds=Rect(0, 0 - 1080, 2400)}} tId:46941937 ResumeActivityItem{mActivityToken=android.os.BinderProxy@2352e32,procState=-1,isForward=true,shouldSendCompatFakeFocus=false} tId:46941937 Target activity: com.example.myapplication.PhoneActivity tId:46941937 ] tId:46941937 } 2025-07-21 11:13:23.118 5188-5188 AndroidRuntime com.example.myapplication D Shutting down VM 2025-07-21 11:13:23.119 5188-5188 AndroidRuntime com.example.myapplication E FATAL EXCEPTION: main Process: com.example.myapplication, PID: 5188 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myapplication/com.example.myapplication.PhoneActivity}: java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4280) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4467) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:222) at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:133) at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:103) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:80) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2823) at android.os.Handler.dispatchMessage(Handler.java:110) at android.os.Looper.loopOnce(Looper.java:248) at android.os.Looper.loop(Looper.java:338) at android.app.ActivityThread.main(ActivityThread.java:9067) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932) Caused by: java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0 at jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64) at jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70) at jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266) at java.util.Objects.checkIndex(Objects.java:385) at java.util.ArrayList.get(ArrayList.java:434) at com.example.myapplication.PhoneActivity.initview(PhoneActivity.java:96) at com.example.myapplication.PhoneActivity.onCreate(PhoneActivity.java:37) at android.app.Activity.performCreate(Activity.java:9155) at android.app.Activity.performCreate(Activity.java:9133) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1521) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4262) ... 13 more

filetype

package com.example.kucun2.entity.data; import android.util.Log; import com.example.kucun2.function.MyAppFunction; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 可同步实体基类 * 提供实体到服务端的同步功能,包含自动重试机制和线程管理 */ public abstract class SynchronizableEntity implements EntityClassGrassrootsid { private static final String TAG = "SynchronizableEntity"; // 双重缓存结构:外层缓存类名,内层缓存字段名->Field对象 private static final Map<Class<?>, Map<String, Field>> CLASS_FIELD_CACHE = new HashMap<>(); // 网络请求线程池(静态共享) private static final ExecutorService NETWORK_EXECUTOR = Executors.newFixedThreadPool(4); /** * 获取指定类型操作的端点URL * * @param type 操作类型(如"create", "update", "delete"等) * @return 完整的端点URL路径 * * @apiNote 该方法通过资源键名拼接规则查找对应的URL资源 * @example 对于Product类的create操作,查找键为:"url_create_product" */ public String getEndpoint(String type) { // 构建资源键名:url_操作类型_类名小写 String key = "url_" + type + "_" + this.getClass().getSimpleName().toLowerCase(); return MyAppFunction.getStringResource("string", key); } //================ 核心同步方法 ================// /** * 同步实体到服务端(公开接口) * * @param type 操作类型(如"create", "update"等) * @param callback 同步结果回调接口 * * @implNote 内部调用私有方法实现带重试机制的同步 * @see #sync(String, SyncCallback, int) */ public void sync(String type, SyncCallback callback) { sync(type, callback, 0); // 初始重试次数为0 } private <T extends SynchronizableEntity> ApiClient.ApiCallback<T> getApiCallback(String type,SyncCallback callback,int retryCount,Class<T > thistype){ return new ApiClient.ApiCallback<T>() { @Override public void onSuccess(T responseData) { handleSyncSuccess(responseData, callback); } @Override public void onError(int statusCode, String error) { handleSyncError(type, statusCode, error, callback, retryCount); } }; } /** * 带重试机制的同步实现(私有方法) * * @param type 操作类型 * @param callback 同步结果回调 * @param retryCount 当前重试次数 * * @implSpec 1. 构建完整端点URL * 2. 通过线程池提交网络请求 * 3. 处理成功/失败回调 */ private void sync(String type, SyncCallback callback, int retryCount) { // 构建完整端点URL String baseUrl = MyAppFunction.getStringResource("string", "url"); String endpoint = baseUrl + getEndpoint(type); Log.d(TAG, "同步端点: " + endpoint + ", 重试次数: " + retryCount); // 提交到线程池执行网络请求 NETWORK_EXECUTOR.execute(() -> { ApiClient.postJson(endpoint, this, getApiCallback(type,callback,retryCount,this.getClass())); }); } /** * 处理同步成功结果 * * @param responseData 服务端返回的实体数据 * @param callback 同步结果回调 * * @implNote 1. 更新实体ID * 2. 记录成功日志 * 3. 触发成功回调 */ private void handleSyncSuccess(SynchronizableEntity responseData, SyncCallback callback) { // 更新实体ID(如果服务端返回了新ID) if (responseData != null) { setId(responseData.getId()); Log.i(TAG, "同步成功, 新ID: " + responseData.getId()); } // 触发成功回调 if (callback != null) callback.onSyncSuccess(this); } /** * 处理同步错误(含重试逻辑) * * @param type 操作类型 * @param statusCode HTTP状态码(-1表示网络错误) * @param error 错误信息 * @param callback 同步结果回调 * @param retryCount 当前重试次数 * * @implSpec 1. 判断错误是否可重试(网络错误或5xx服务错误) * 2. 满足条件时进行指数退避重试 * 3. 达到最大重试次数后触发失败回调 * * @algorithm 使用指数退避算法:延迟时间 = 1000ms * 2^重试次数 */ private void handleSyncError(String type, int statusCode, String error, SyncCallback callback, int retryCount) { Log.e(TAG, "同步失败: " + error + ", 状态码: " + statusCode); // 判断是否可重试(网络错误或服务端5xx错误) boolean canRetry = statusCode == -1 || (statusCode >= 500 && statusCode < 600); // 满足重试条件(可重试错误且未达到最大重试次数) if (canRetry && retryCount < 3) { // 计算指数退避延迟时间 long delay = (long) (1000 * Math.pow(2, retryCount)); Log.w(TAG, "将在 " + delay + "ms 后重试"); try { // 当前线程休眠指定时间 Thread.sleep(delay); } catch (InterruptedException e) { // 恢复中断状态 Thread.currentThread().interrupt(); } // 递归调用进行重试(重试次数+1) sync(type, callback, retryCount + 1); } else { // 不可重试或达到最大重试次数,触发失败回调 if (callback != null) { String finalError = "同步失败: " + error; if (canRetry) finalError += " (重试失败)"; callback.onSyncFailure(finalError); } } } // 线程安全的对象复制方法 public void updateFrom(Object source) { if ( source == null) return; Class<?> targetClass = this.getClass(); Class<?> sourceClass = source.getClass(); // 获取或创建字段缓存 Map<String, Field> targetFields = getOrCreateFieldCache(targetClass); Map<String, Field> sourceFields = getOrCreateFieldCache(sourceClass); // 遍历源对象字段 for (Map.Entry<String, Field> entry : sourceFields.entrySet()) { String fieldName = entry.getKey(); Field sourceField = entry.getValue(); // 查找目标对象对应字段 Field targetField = targetFields.get(fieldName); if (targetField != null) { // 类型兼容性检查 if (isCompatibleTypes(sourceField.getType(), targetField.getType())) { try { // 复制字段值 Object value = sourceField.get(source); targetField.set(this, value); } catch (IllegalAccessException e) { // 处理异常,记录日志 } } } } } // 获取或创建类的字段缓存 private static Map<String, Field> getOrCreateFieldCache(Class<?> clazz) { // 双重检查锁确保线程安全 if (!CLASS_FIELD_CACHE.containsKey(clazz)) { synchronized (clazz) { if (!CLASS_FIELD_CACHE.containsKey(clazz)) { Map<String, Field> fieldMap = new HashMap<>(); // 递归获取所有字段(包括父类) for (Class<?> current = clazz; current != null; current = current.getSuperclass()) { for (Field field : current.getDeclaredFields()) { field.setAccessible(true); // 突破访问限制 fieldMap.put(field.getName(), field); } } CLASS_FIELD_CACHE.put(clazz, fieldMap); } } } return CLASS_FIELD_CACHE.get(clazz); } // 类型兼容性检查(支持自动装箱/拆箱) private static boolean isCompatibleTypes(Class<?> sourceType, Class<?> targetType) { // 处理基本类型和包装类的兼容性 if (sourceType.isPrimitive()) { sourceType = primitiveToWrapper(sourceType); } if (targetType.isPrimitive()) { targetType = primitiveToWrapper(targetType); } return targetType.isAssignableFrom(sourceType); } // 基本类型转包装类 private static Class<?> primitiveToWrapper(Class<?> primitiveType) { if (boolean.class.equals(primitiveType)) return Boolean.class; if (byte.class.equals(primitiveType)) return Byte.class; if (char.class.equals(primitiveType)) return Character.class; if (double.class.equals(primitiveType)) return Double.class; if (float.class.equals(primitiveType)) return Float.class; if (int.class.equals(primitiveType)) return Integer.class; if (long.class.equals(primitiveType)) return Long.class; if (short.class.equals(primitiveType)) return Short.class; if (void.class.equals(primitiveType)) return Void.class; return primitiveType; } //================ 回调接口 ================// /** * 同步操作回调接口 * * @implNote 使用方需实现此接口处理同步结果 */ public interface SyncCallback { /** * 同步成功回调 * * @param entity 同步后的实体对象(已更新ID) */ void onSyncSuccess(SynchronizableEntity entity); /** * 同步失败回调 * * @param error 失败原因描述 */ void onSyncFailure(String error); } } package com.example.kucun2.entity.data; import android.os.Handler; import android.os.Looper; import android.util.Log; import com.example.kucun2.entity.Information; import com.example.kucun2.entity.User; import com.example.kucun2.function.MyAppFunction; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import okhttp3.*; import java.io.IOException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Map; /** * 重构版API客户端 - 更灵活的类型处理 * 主要改进: * 1. 分离请求参数类型和响应类型 * 2. 支持多种请求方法(GET/POST/PUT/DELETE) * 3. 支持表单和JSON两种请求格式 * 4. 自动推导响应类型 * 5. 统一的请求执行流程 */ public class ApiClient { private static final Gson gson = GsonFactory.createGson(); private static final String TAG = "ApiClient"; private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private static final int MAX_RETRY = 3; private static final Handler MAIN_HANDLER = new Handler(Looper.getMainLooper()); // ====================== 核心请求方法 ====================== /** * 执行API请求(核心方法) * @param request 构建好的OkHttp请求 * @param responseType 期望的响应类型 * @param callback 回调接口 * @param <R> 响应数据类型 */ public static <R> void executeRequest(Request request, Type responseType, ApiCallback<R> callback) { OkHttpClient client = MyAppFunction.getClient(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { handleFailure(call, e, callback, 0); } @Override public void onResponse(Call call, Response response) throws IOException { handleResponse(response, responseType, callback); } }); } // ====================== 请求构建方法 ====================== /** * 构建JSON请求 * @param url API地址 * @param method 请求方法("POST", "PUT", "DELETE") * @param requestData 请求数据对象 * @return 构建好的Request对象 */ public static Request buildJsonRequest(String url, String method, Object requestData) { String jsonRequest = ReflectionJsonUtils.toJson(requestData); Log.d(TAG, method + " URL: " + url); Log.d(TAG, "请求数据: " + jsonRequest); RequestBody body = RequestBody.create(JSON, jsonRequest); return new Request.Builder() .url(url) .method(method, body) .build(); } /** * 构建表单请求 * @param url API地址 * @param method 请求方法 * @param formData 表单数据 * @return 构建好的Request对象 */ public static Request buildFormRequest(String url, String method, Map<String, String> formData) { FormBody.Builder builder = new FormBody.Builder(); for (Map.Entry<String, String> entry : formData.entrySet()) { builder.add(entry.getKey(), entry.getValue()); } Log.d(TAG, method + " URL: " + url); Log.d(TAG, "表单数据: " + formData); return new Request.Builder() .url(url) .method(method, builder.build()) .build(); } // ====================== 响应处理方法 ====================== private static <R> void handleResponse(Response response, Type responseType, ApiCallback<R> callback) throws IOException { try (ResponseBody responseBody = response.body()) { if (!response.isSuccessful()) { String error = "HTTP " + response.code() + ": " + response.message(); Log.e(TAG, error); notifyError(callback, response.code(), error); return; } String jsonResponse = responseBody.string(); Log.d(TAG, "服务器响应: " + jsonResponse); // 解析服务端的Information包装 Information<R> wrapper = gson.fromJson(jsonResponse, responseType); if (wrapper != null && wrapper.getStatus() == 200) { notifySuccess(callback, wrapper.getData()); } else { String errorMsg = wrapper != null ? "服务端错误: " + wrapper.getStatus() + " - " + wrapper.getText() : "无效的响应格式"; Log.e(TAG, errorMsg); notifyError(callback, wrapper != null ? wrapper.getStatus() : -1, errorMsg); } } catch (Exception e) { Log.e(TAG, "响应处理异常: " + e.getMessage()); notifyError(callback, -2, "数据处理异常: " + e.getMessage()); } } // ====================== 失败处理与重试 ====================== private static <R> void handleFailure(Call call, IOException e, ApiCallback<R> callback, int retryCount) { if (retryCount < MAX_RETRY) { Log.w(TAG, "请求失败,第" + (retryCount + 1) + "次重试: " + e.getMessage()); MAIN_HANDLER.postDelayed(() -> { call.clone().enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { handleFailure(call, e, callback, retryCount + 1); } @Override public void onResponse(Call call, Response response) throws IOException { handleResponse(response, getResponseType(callback), callback); } }); }, 2000); } else { Log.e(TAG, "最终请求失败: " + e.getMessage()); notifyError(callback, -1, "网络请求失败: " + e.getMessage()); } } // ====================== 类型处理工具 ====================== /** * 获取响应类型(通过回调接口的泛型参数) */ private static <R> Type getResponseType(ApiCallback<R> callback) { if (callback == null) { return new TypeToken<Information<Object>>(){}.getType(); } // 尝试获取泛型类型 Type[] genericInterfaces = callback.getClass().getGenericInterfaces(); for (Type type : genericInterfaces) { if (type instanceof ParameterizedType) { ParameterizedType pType = (ParameterizedType) type; if (pType.getRawType().equals(ApiCallback.class)) { Type dataType = pType.getActualTypeArguments()[0]; return TypeToken.getParameterized(Information.class, dataType).getType(); } } } // 默认返回Object类型 Log.w(TAG, "无法确定响应类型,使用默认Object类型"); return new TypeToken<Information<Object>>(){}.getType(); } // ====================== 回调通知方法 ====================== private static <R> void notifySuccess(ApiCallback<R> callback, R data) { if (callback != null) { MAIN_HANDLER.post(() -> callback.onSuccess(data)); } } private static <R> void notifyError(ApiCallback<R> callback, int code, String error) { if (callback != null) { MAIN_HANDLER.post(() -> callback.onError(code, error)); } } // ====================== 专用API方法 ====================== /** * 执行JSON API请求 * @param url API地址 * @param method 请求方法 * @param requestData 请求数据 * @param callback 回调接口 * @param <T> 请求数据类型 * @param <R> 响应数据类型 */ public static <T, R> void jsonRequest(String url, String method, T requestData, ApiCallback<R> callback) { Request request = buildJsonRequest(url, method, requestData); executeRequest(request, getResponseType(callback), callback); } /** * 执行表单API请求 * @param url API地址 * @param method 请求方法 * @param formData 表单数据 * @param callback 回调接口 * @param <R> 响应数据类型 */ public static <R> void formRequest(String url, String method, Map<String, String> formData, ApiCallback<R> callback) { Request request = buildFormRequest(url, method, formData); executeRequest(request, getResponseType(callback), callback); } // ====================== 便捷方法 ====================== public static <T, R> void postJson(String url, T data, ApiCallback<R> callback) { jsonRequest(url, "POST", data, callback); } public static <T, R> void putJson(String url, T data, ApiCallback<R> callback) { jsonRequest(url, "PUT", data, callback); } public static <T, R> void deleteJson(String url, T data, ApiCallback<R> callback) { jsonRequest(url, "DELETE", data, callback); } public static <R> void get(String url, ApiCallback<R> callback) { Request request = new Request.Builder().url(url).get().build(); executeRequest(request, getResponseType(callback), callback); } // ====================== 登录专用方法 ====================== public static void login(String username, String password, LoginCallback callback) { String url = MyAppFunction.getApiUrl("url_login"); Log.d(TAG, "login: " + url); formRequest(url, "POST", Map.of( "andy", username, "pass", password ), new ApiCallback<User>() { @Override public void onSuccess(User user) { if (callback != null) callback.onSuccess(user); } @Override public void onError(int statusCode, String error) { if (callback != null) callback.onFailure(error); } }); } // ====================== 回调接口定义 ====================== public interface ApiCallback<T> { void onSuccess(T data); void onError(int statusCode, String error); } public interface LoginCallback { void onSuccess(User user); void onFailure(String error); } } getApiCallback方法是否可行

YinJson
  • 粉丝: 1
上传资源 快速赚钱