添加日志,文件,BaseBean类,未调试。
This commit is contained in:
		| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Thu Feb 06 07:12:44 HKT 2025 | ||||
| #Fri Feb 07 09:04:42 GMT 2025 | ||||
| stageCount=1 | ||||
| libraryProject=libappbase | ||||
| baseVersion=1.2 | ||||
| publishVersion=1.2.0 | ||||
| buildCount=0 | ||||
| buildCount=172 | ||||
| baseBetaVersion=1.2.1 | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Thu Feb 06 07:12:30 HKT 2025 | ||||
| #Fri Feb 07 09:04:42 GMT 2025 | ||||
| stageCount=1 | ||||
| libraryProject=libappbase | ||||
| baseVersion=1.2 | ||||
| publishVersion=1.2.0 | ||||
| buildCount=0 | ||||
| buildCount=172 | ||||
| baseBetaVersion=1.2.1 | ||||
|   | ||||
| @@ -7,6 +7,10 @@ | ||||
|             android:name=".CrashHandler$CrashActiviy" | ||||
|             android:label="CrashActiviy" | ||||
|             android:launchMode="standard"/> | ||||
|         <activity | ||||
|             android:name=".CrashHandler$GlobalCrashActiviy" | ||||
|             android:label="GlobalCrashActiviy" | ||||
|             android:launchMode="standard"/> | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|   | ||||
| @@ -0,0 +1,283 @@ | ||||
| package cc.winboll.studio.libappbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2025/01/15 11:11:52 | ||||
|  * @Describe Json Bean 基础类。 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.StringReader; | ||||
| import java.io.StringWriter; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public abstract class BaseBean<T extends BaseBean> { | ||||
|  | ||||
|     public static final String TAG = "BaseBean"; | ||||
|     static final String BEAN_NAME = "BeanName"; | ||||
|  | ||||
|     public BaseBean() {} | ||||
|  | ||||
|     public abstract String getName(); | ||||
|  | ||||
|     public String getBeanJsonFilePath(Context context) { | ||||
|  | ||||
|         return context.getExternalFilesDir(TAG) + "/" + getName() + ".json"; | ||||
|     } | ||||
|  | ||||
|     public String getBeanListJsonFilePath(Context context) { | ||||
|  | ||||
|         return context.getExternalFilesDir(TAG) + "/" + getName() + "_List.json"; | ||||
|     } | ||||
|  | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         jsonWriter.name(BEAN_NAME).value(getName()); | ||||
|     } | ||||
|  | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     abstract public T readBeanFromJsonReader(JsonReader jsonReader) throws IOException; | ||||
|  | ||||
|     public static <T extends BaseBean> String checkIsTheSameBeanListAndFile(String szFilePath, Class<T> clazz) { | ||||
|         StringBuilder sbResult = new StringBuilder(); | ||||
|         String szErrorInfo = "Check Is The Same Bean List And File Error : "; | ||||
|  | ||||
|         try { | ||||
|             int nSameCount = 0; | ||||
|             int nBeanListCout = 0; | ||||
|  | ||||
|             T beanTemp = clazz.newInstance(); | ||||
|             String szBeanSimpleName = beanTemp.getName(); | ||||
|             String szListJson = FileUtils.readStringFromFile(szFilePath); | ||||
|             StringReader stringReader = new StringReader(szListJson); | ||||
|             JsonReader jsonReader = new JsonReader(stringReader); | ||||
|             jsonReader.beginArray(); | ||||
|             while (jsonReader.hasNext()) { | ||||
|                 nBeanListCout++; | ||||
|                 jsonReader.beginObject(); | ||||
|                 while (jsonReader.hasNext()) { | ||||
|                     String name = jsonReader.nextName(); | ||||
|                     if (name.equals(BEAN_NAME)) { | ||||
|                         if (szBeanSimpleName.equals(jsonReader.nextString())) { | ||||
|                             nSameCount++; | ||||
|                         } | ||||
|                     } else { | ||||
|                         jsonReader.skipValue(); | ||||
|                     } | ||||
|                 } | ||||
|                 jsonReader.endObject(); | ||||
|             } | ||||
|             jsonReader.endArray(); | ||||
|  | ||||
|             // 返回检查结果 | ||||
|             if (nSameCount == nBeanListCout) { | ||||
|                 // 检查一致直接返回空串 | ||||
|                 return ""; | ||||
|             } else { | ||||
|                 // 检查不一致返回对比信息 | ||||
|                 sbResult.append("Total : "); | ||||
|                 sbResult.append(nBeanListCout); | ||||
|                 sbResult.append(" Diff : "); | ||||
|                 sbResult.append(nBeanListCout - nSameCount); | ||||
|             } | ||||
|         } catch (InstantiationException e) { | ||||
|             sbResult.append(szErrorInfo); | ||||
|             sbResult.append(e); | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } catch (IllegalAccessException e) { | ||||
|             sbResult.append(szErrorInfo); | ||||
|             sbResult.append(e); | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } catch (IOException e) { | ||||
|             sbResult.append(szErrorInfo); | ||||
|             sbResult.append(e); | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return sbResult.toString(); | ||||
|     } | ||||
|  | ||||
|     public static <T extends BaseBean> T parseStringToBean(String szBean, Class<T> clazz) throws IOException { | ||||
|         // 创建 JsonWriter 对象 | ||||
|         StringReader stringReader = new StringReader(szBean); | ||||
|         JsonReader jsonReader = new JsonReader(stringReader); | ||||
|         try { | ||||
|             T beanTemp = clazz.newInstance(); | ||||
|             return (T)beanTemp.readBeanFromJsonReader(jsonReader); | ||||
|         } catch (InstantiationException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } catch (IllegalAccessException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static <T extends BaseBean> boolean parseStringToBeanList(String szBeanList, ArrayList<T> beanList, Class<T> clazz) { | ||||
|         try { | ||||
|             beanList.clear(); | ||||
|             StringReader stringReader = new StringReader(szBeanList); | ||||
|             JsonReader jsonReader = new JsonReader(stringReader); | ||||
|             jsonReader.beginArray(); | ||||
|             while (jsonReader.hasNext()) { | ||||
|                 T beanTemp = clazz.newInstance(); | ||||
|                 T bean = (T)beanTemp.readBeanFromJsonReader(jsonReader); | ||||
|                 if (bean != null) { | ||||
|                     beanList.add(bean); | ||||
|                     //LogUtils.d(TAG, "beanList.add(bean)"); | ||||
|                 } | ||||
|             } | ||||
|             jsonReader.endArray(); | ||||
|             return true; | ||||
|             //LogUtils.d(TAG, "beanList.size() is " + Integer.toString(beanList.size())); | ||||
|         } catch (InstantiationException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } catch (IllegalAccessException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         // 创建 JsonWriter 对象 | ||||
|         StringWriter stringWriter = new StringWriter(); | ||||
|         JsonWriter jsonWriter = new JsonWriter(stringWriter); | ||||
|         jsonWriter.setIndent("  "); | ||||
|         try {// 开始 JSON 对象 | ||||
|             jsonWriter.beginObject(); | ||||
|             // 写入键值对 | ||||
|             writeThisToJsonWriter(jsonWriter); | ||||
|             // 结束 JSON 对象 | ||||
|             jsonWriter.endObject(); | ||||
|             return stringWriter.toString(); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         // 获取 JSON 字符串 | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     public static <T extends BaseBean> String toStringByBeanList(ArrayList<T> beanList) { | ||||
|         try { | ||||
|             StringWriter stringWriter = new StringWriter(); | ||||
|             JsonWriter jsonWriter = new JsonWriter(stringWriter); | ||||
|             jsonWriter.setIndent("  "); | ||||
|             jsonWriter.beginArray(); | ||||
|             for (int i = 0; i < beanList.size(); i++) { | ||||
|                 // 开始 JSON 对象 | ||||
|                 jsonWriter.beginObject(); | ||||
|                 // 写入键值对 | ||||
|                 beanList.get(i).writeThisToJsonWriter(jsonWriter); | ||||
|                 // 结束 JSON 对象 | ||||
|                 jsonWriter.endObject(); | ||||
|             } | ||||
|             jsonWriter.endArray(); | ||||
|             jsonWriter.close(); | ||||
|             return stringWriter.toString(); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static <T extends BaseBean> T loadBean(Context context, Class<T> clazz) { | ||||
|         try { | ||||
|             T beanTemp = clazz.newInstance(); | ||||
|             return loadBeanFromFile(beanTemp.getBeanJsonFilePath(context), clazz); | ||||
|         } catch (InstantiationException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } catch (IllegalAccessException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static <T extends BaseBean> T loadBeanFromFile(String szFilePath, Class<T> clazz) { | ||||
|         try { | ||||
|             try { | ||||
|                 File fTemp = new File(szFilePath); | ||||
|                 if (fTemp.exists()) { | ||||
|                     T beanTemp = clazz.newInstance();String szJson = FileUtils.readStringFromFile(szFilePath); | ||||
|                     return beanTemp.parseStringToBean(szJson, clazz); | ||||
|                 } | ||||
|             } catch (InstantiationException e) { | ||||
|                 LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|             } catch (IllegalAccessException e) { | ||||
|                 LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|             } | ||||
|  | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static <T extends BaseBean> boolean saveBean(Context context, T bean) { | ||||
|         return saveBeanToFile(bean.getBeanJsonFilePath(context), bean); | ||||
|     } | ||||
|  | ||||
|     public static <T extends BaseBean> boolean saveBeanToFile(String szFilePath, T bean) { | ||||
|         try { | ||||
|             String szJson = bean.toString(); | ||||
|             FileUtils.writeStringToFile(szFilePath, szJson); | ||||
|             return true; | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public static <T extends BaseBean> boolean loadBeanList(Context context, ArrayList<T> beanListDst, Class<T> clazz) { | ||||
|         try { | ||||
|             T beanTemp = clazz.newInstance(); | ||||
|             return loadBeanListFromFile(beanTemp.getBeanListJsonFilePath(context), beanListDst, clazz); | ||||
|         } catch (InstantiationException e) {} catch (IllegalAccessException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public static <T extends BaseBean> boolean loadBeanListFromFile(String szFilePath, ArrayList<T> beanList, Class<T> clazz) { | ||||
|         try { | ||||
|             File fTemp = new File(szFilePath); | ||||
|             if (fTemp.exists()) { | ||||
|                 String szListJson = FileUtils.readStringFromFile(szFilePath); | ||||
|                 return parseStringToBeanList(szListJson, beanList, clazz); | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public static <T extends BaseBean> boolean saveBeanList(Context context, ArrayList<T> beanList, Class<T> clazz) { | ||||
|         try { | ||||
|             T beanTemp = clazz.newInstance(); | ||||
|             return saveBeanListToFile(beanTemp.getBeanListJsonFilePath(context), beanList); | ||||
|         } catch (InstantiationException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } catch (IllegalAccessException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public static <T extends BaseBean> boolean saveBeanListToFile(String szFilePath, ArrayList<T> beanList) { | ||||
|         try { | ||||
|             String szJson = toStringByBeanList(beanList); | ||||
|             FileUtils.writeStringToFile(szFilePath, szJson); | ||||
|             //LogUtils.d(TAG, "FileUtil.writeFile beanList.size() is " + Integer.toString(beanList.size())); | ||||
|             return true; | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @@ -18,17 +18,24 @@ import android.content.res.Resources; | ||||
| import android.graphics.Color; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.Looper; | ||||
| import android.text.TextUtils; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.HorizontalScrollView; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.ScrollView; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.ObjectInputStream; | ||||
| import java.io.ObjectOutputStream; | ||||
| import java.io.PrintWriter; | ||||
| import java.io.StringWriter; | ||||
| import java.lang.Thread.UncaughtExceptionHandler; | ||||
| @@ -37,11 +44,22 @@ import java.util.Date; | ||||
| import java.util.Locale; | ||||
|  | ||||
| public final class CrashHandler { | ||||
|     public static final String TAG = "CrashHandler"; | ||||
|      | ||||
|     final static String PREFS = CrashHandler.class.getName() + "PREFS"; | ||||
|     final static String PREFS_CRASHHANDLER_ISCRASHHAPPEN = "PREFS_CRASHHANDLER_ISCRASHHAPPEN"; | ||||
|  | ||||
|     public static String _CrashCountFilePath; | ||||
|  | ||||
|     public static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler(); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     public static void init(Application app) { | ||||
|         _CrashCountFilePath = app.getExternalFilesDir("CrashHandler") + "/IsCrashHandlerCrashHappen.dat"; | ||||
|         init(app, null); | ||||
|         LogUtils.d(TAG, "init"); | ||||
|     } | ||||
|  | ||||
|     public static void init(final Application app, final String crashDir) { | ||||
| @@ -90,6 +108,7 @@ public final class CrashHandler { | ||||
|                     sb.append("App VersionName                      : ").append(versionName).append("\n"); | ||||
|                     sb.append("App VersionCode                      : ").append(versionCode).append("\n"); | ||||
|                     sb.append("AppBase GlobalApplication Debug Mode : ").append(GlobalApplication.isDebuging).append("\n"); | ||||
|                     sb.append("CrashHandler CurrentSafeLevel        : ").append(String.format("%d", AppCrashSafetyWire.getInstance().getCurrentSafetyLevel())).append("\n"); | ||||
|                     sb.append("************* Crash Head ****************\n"); | ||||
|                     sb.append("\n").append(fullStackTrace); | ||||
|  | ||||
| @@ -100,12 +119,31 @@ public final class CrashHandler { | ||||
|                     } catch (IOException ignored) {} | ||||
|  | ||||
|                     gotoCrashActiviy: { | ||||
|                         Intent intent = new Intent(app, CrashActiviy.class); | ||||
|                         Intent intent = new Intent(); | ||||
|  | ||||
|                         if (AppCrashSafetyWire.getInstance().isAppCrashSafetyWireOK() && AppCrashSafetyWire.getInstance().postCrashSafetyWire(app)) { | ||||
|                             AppCrashSafetyWire.getInstance().reset(); | ||||
|                             intent.setClass(app, GlobalCrashActiviy.class); | ||||
|                             intent.putExtra(GlobalCrashActiviy.EXTRA_CRASH_INFO, errorLog); | ||||
|                             // 如果发生了 CrashHandler 内部崩溃, 就调用基础的应用崩溃显示类 | ||||
| //                            intent.setClass(app, GlobalCrashActiviy.class); | ||||
| //                            intent.putExtra(GlobalCrashActiviy.EXTRA_CRASH_INFO, errorLog); | ||||
|                         } else { | ||||
|                             AppCrashSafetyWire.getInstance().reset(); | ||||
|                             // 正常状态调用进阶的应用崩溃显示页 | ||||
|                             intent.setClass(app, CrashActiviy.class); | ||||
|                             intent.putExtra(CrashActiviy.EXTRA_CRASH_INFO, errorLog); | ||||
|                         }  | ||||
|  | ||||
| //                        intent.setClass(app, CrashActiviy.class); | ||||
| //                        intent.putExtra(CrashActiviy.EXTRA_CRASH_INFO, errorLog); | ||||
|  | ||||
|  | ||||
|                         intent.addFlags( | ||||
|                             Intent.FLAG_ACTIVITY_NEW_TASK | ||||
|                             | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | ||||
|                         ); | ||||
|                         intent.putExtra(CrashActiviy.EXTRA_CRASH_INFO, errorLog); | ||||
|  | ||||
|                         try { | ||||
|                             app.startActivity(intent); | ||||
|                             android.os.Process.killProcess(android.os.Process.myPid()); | ||||
| @@ -114,6 +152,10 @@ public final class CrashHandler { | ||||
|                             e.printStackTrace(); | ||||
|                             if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) | ||||
|                                 DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(thread, throwable); | ||||
|                         } catch (Exception e) { | ||||
|                             e.printStackTrace(); | ||||
|                             if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) | ||||
|                                 DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(thread, throwable); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
| @@ -135,6 +177,113 @@ public final class CrashHandler { | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 应用崩溃保险丝 | ||||
|     // | ||||
|     public static final class AppCrashSafetyWire { | ||||
|  | ||||
|         volatile static AppCrashSafetyWire _AppCrashSafetyWire; | ||||
|  | ||||
|         volatile int currentSafetyLevel; // 熔断值,为 0 表示熔断了。 | ||||
|         private static final int _MINI = 1; | ||||
|         private static final int _MAX = 5; | ||||
|  | ||||
|         AppCrashSafetyWire() { | ||||
|             currentSafetyLevel = loadCurrentSafetyLevel(); | ||||
|         } | ||||
|  | ||||
|         public static synchronized AppCrashSafetyWire getInstance() { | ||||
|             if (_AppCrashSafetyWire == null) { | ||||
|                 _AppCrashSafetyWire = new AppCrashSafetyWire(); | ||||
|             } | ||||
|             return _AppCrashSafetyWire; | ||||
|         } | ||||
|  | ||||
|         public void setCurrentSafetyLevel(int currentSafetyLevel) { | ||||
|             this.currentSafetyLevel = currentSafetyLevel; | ||||
|         } | ||||
|  | ||||
|         public int getCurrentSafetyLevel() { | ||||
|             return currentSafetyLevel; | ||||
|         } | ||||
|  | ||||
|         public void saveCurrentSafetyLevel(int currentSafetyLevel) { | ||||
|             this.currentSafetyLevel = currentSafetyLevel; | ||||
|             try { | ||||
|                 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(_CrashCountFilePath)); | ||||
|                 oos.writeInt(currentSafetyLevel); | ||||
|             } catch (IOException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public int loadCurrentSafetyLevel() { | ||||
|             try { | ||||
|                 File f = new File(_CrashCountFilePath); | ||||
|                 if (f.exists()) { | ||||
|                     ObjectInputStream ois = new ObjectInputStream(new FileInputStream(_CrashCountFilePath)); | ||||
|                     currentSafetyLevel = ois.readInt(); | ||||
|                 } else { | ||||
|                     currentSafetyLevel = _MAX; | ||||
|                     saveCurrentSafetyLevel(currentSafetyLevel); | ||||
|                 } | ||||
|             } catch (IOException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|             return currentSafetyLevel; | ||||
|         } | ||||
|  | ||||
|         boolean putOnSafetyWire() { | ||||
|             // 崩溃计数进入崩溃保险值 | ||||
|             int safeLevel = loadCurrentSafetyLevel(); | ||||
|             if (isSafetyWireOK(safeLevel)) { | ||||
|                 // 如果保险丝未熔断, 就减少一次熔断值 | ||||
|                 saveCurrentSafetyLevel(safeLevel - 1); | ||||
|                 return true; | ||||
|             } | ||||
|  | ||||
|  | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         boolean isSafetyWireOK(int safetyLevel) { | ||||
|             if (safetyLevel >= _MINI && safetyLevel <= _MAX) { | ||||
|                 // 如果在保险值之内 | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         void reset() { | ||||
|             saveCurrentSafetyLevel(_MAX); | ||||
|         } | ||||
|  | ||||
|         void off() { | ||||
|             saveCurrentSafetyLevel(_MINI); | ||||
|         } | ||||
|  | ||||
|         boolean isAppCrashSafetyWireOK() { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // 调用函数以启用持续崩溃保险,从而调用 CrashHandler 内部崩溃处理窗口 | ||||
|         boolean postCrashSafetyWire(final Context context) { | ||||
|             if (AppCrashSafetyWire.getInstance().putOnSafetyWire()) { | ||||
|                 // 设置内部崩溃处理模块失效 | ||||
|                 new Handler(Looper.getMainLooper()).postDelayed(new Runnable(){ | ||||
|                         @Override | ||||
|                         public void run() { | ||||
|                             // 进程持续运行时重置保险丝 | ||||
|                             //AppCrashSafetyWire.getInstance().reset(); | ||||
|                         } | ||||
|                     }, 1000); | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public static final class CrashActiviy extends Activity implements MenuItem.OnMenuItemClickListener { | ||||
|  | ||||
|         private static final String EXTRA_CRASH_INFO = "crashInfo"; | ||||
| @@ -147,11 +296,13 @@ public final class CrashHandler { | ||||
|         @Override | ||||
|         protected void onCreate(Bundle savedInstanceState) { | ||||
|             super.onCreate(savedInstanceState); | ||||
|  | ||||
|             mLog = getIntent().getStringExtra(EXTRA_CRASH_INFO); | ||||
|             setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar); | ||||
|             setContentView: { | ||||
|                 ScrollView contentView = new ScrollView(this); | ||||
|                 contentView.setFillViewport(true); | ||||
|  | ||||
|                 HorizontalScrollView hw = new HorizontalScrollView(this); | ||||
|                 hw.setBackgroundColor(Color.GRAY); | ||||
|                 TextView message = new TextView(this); { | ||||
| @@ -161,6 +312,7 @@ public final class CrashHandler { | ||||
|                     message.setTextIsSelectable(true); | ||||
|                 } | ||||
|                 hw.addView(message); | ||||
|  | ||||
|                 contentView.addView(hw, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); | ||||
|                 setContentView(contentView); | ||||
|             } | ||||
| @@ -215,5 +367,99 @@ public final class CrashHandler { | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static final class GlobalCrashActiviy extends Activity implements MenuItem.OnMenuItemClickListener { | ||||
|  | ||||
|         private static final String EXTRA_CRASH_INFO = "crashInfo"; | ||||
|  | ||||
|         private static final int MENUITEM_COPY = 0; | ||||
|         private static final int MENUITEM_RESTART = 1; | ||||
|  | ||||
|         private String mLog; | ||||
|  | ||||
|         @Override | ||||
|         protected void onCreate(Bundle savedInstanceState) { | ||||
|             super.onCreate(savedInstanceState); | ||||
|             mLog = getIntent().getStringExtra(EXTRA_CRASH_INFO); | ||||
|             setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar); | ||||
|             setContentView: { | ||||
|                 ScrollView contentView = new ScrollView(this); | ||||
|                 contentView.setFillViewport(true); | ||||
|  | ||||
|                 LinearLayout llTitle = new LinearLayout(this); | ||||
|                 TextView title = new TextView(this); { | ||||
|                     int padding = dp2px(16); | ||||
|                     title.setPadding(padding, padding, padding, padding); | ||||
|                     title.setText("GlobalCrashActiviy"); | ||||
|                 } | ||||
|                 llTitle.addView(title, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); | ||||
|                 contentView.addView(llTitle, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); | ||||
|  | ||||
|                 HorizontalScrollView hw = new HorizontalScrollView(this); | ||||
|                 hw.setBackgroundColor(Color.GRAY); | ||||
|                 TextView message = new TextView(this); { | ||||
|                     int padding = dp2px(16); | ||||
|                     message.setPadding(padding, padding, padding, padding); | ||||
|                     message.setText(mLog); | ||||
|                     message.setTextIsSelectable(true); | ||||
|                 } | ||||
|                 hw.addView(message); | ||||
|  | ||||
|                 contentView.addView(hw, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.FILL_PARENT); | ||||
|                 setContentView(contentView); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onBackPressed() { | ||||
|             restart(); | ||||
|         } | ||||
|  | ||||
|         private void restart() { | ||||
|             PackageManager pm = getPackageManager(); | ||||
|             Intent intent = pm.getLaunchIntentForPackage(getPackageName()); | ||||
|             if (intent != null) { | ||||
|                 intent.addFlags( | ||||
|                     Intent.FLAG_ACTIVITY_NEW_TASK | ||||
|                     | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | ||||
|                 ); | ||||
|                 startActivity(intent); | ||||
|             } | ||||
|             finish(); | ||||
|             android.os.Process.killProcess(android.os.Process.myPid()); | ||||
|             System.exit(0); | ||||
|         } | ||||
|  | ||||
|         private int dp2px(final float dpValue) { | ||||
|             final float scale = Resources.getSystem().getDisplayMetrics().density; | ||||
|             return (int) (dpValue * scale + 0.5f); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean onMenuItemClick(MenuItem item) { | ||||
|             switch (item.getItemId()) { | ||||
|                 case MENUITEM_COPY:  | ||||
|                     ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); | ||||
|                     cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog)); | ||||
|                     Toast.makeText(getApplication(), "The text is copied.", Toast.LENGTH_SHORT).show(); | ||||
|                     break; | ||||
|                 case MENUITEM_RESTART:  | ||||
|                     restart(); | ||||
|                     break; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean onCreateOptionsMenu(Menu menu) { | ||||
|             menu.add(0, MENUITEM_COPY, 0, "Copy").setOnMenuItemClickListener(this) | ||||
|                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); | ||||
|             menu.add(0, MENUITEM_RESTART, 0, "Restart").setOnMenuItemClickListener(this) | ||||
|                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,120 @@ | ||||
| package cc.winboll.studio.libappbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe 文件工具类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.res.AssetManager; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.OutputStream; | ||||
| import java.io.OutputStreamWriter; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.nio.file.Paths; | ||||
|  | ||||
| public class FileUtils { | ||||
|  | ||||
|     public static final String TAG = "FileUtils"; | ||||
|  | ||||
|     public static void copyAssetsToSD(Context context, String szSrcAssets, String szDstSD) { | ||||
|         LogUtils.d(TAG, "copyAssetsToSD [" + szSrcAssets + "] to [" + szDstSD + "]"); | ||||
|         AssetManager assetManager = context.getAssets(); | ||||
|         InputStream inputStream = null; | ||||
|         OutputStream outputStream = null; | ||||
|         try { | ||||
|             inputStream = assetManager.open(szSrcAssets); | ||||
|             File outputFile = new File(szDstSD); | ||||
|             outputStream = new FileOutputStream(outputFile); | ||||
|             byte[] buffer = new byte[1024]; | ||||
|             int length = 0; | ||||
|             while ((length = inputStream.read(buffer)) > 0) { | ||||
|                 outputStream.write(buffer, 0, length); | ||||
|             } | ||||
|             outputStream.flush(); | ||||
|             LogUtils.d(TAG, "copyAssetsToSD done."); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } finally { | ||||
|             if (inputStream != null) { | ||||
|                 try { | ||||
|                     inputStream.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|             } | ||||
|             if (outputStream != null) { | ||||
|                 try { | ||||
|                     outputStream.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 把字符串写入文件,指定 UTF-8 编码 | ||||
|     // | ||||
|     public static void writeStringToFile(String szFilePath, String szContent) throws IOException { | ||||
|         File file = new File(szFilePath); | ||||
|         if (!file.getParentFile().exists()) { | ||||
|             file.getParentFile().mkdirs(); | ||||
|         } | ||||
|         FileOutputStream outputStream = new FileOutputStream(file); | ||||
|         OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); | ||||
|         writer.write(szContent); | ||||
|         writer.close(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 读取文件到字符串,指定 UTF-8 编码 | ||||
|     // | ||||
|     public static String readStringFromFile(String szFilePath) throws IOException { | ||||
|         File file = new File(szFilePath); | ||||
|         FileInputStream inputStream = new FileInputStream(file); | ||||
|         InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); | ||||
|         StringBuilder content = new StringBuilder(); | ||||
|         int character; | ||||
|         while ((character = reader.read()) != -1) { | ||||
|             content.append((char) character); | ||||
|         } | ||||
|         reader.close(); | ||||
|         return content.toString(); | ||||
|     } | ||||
|  | ||||
|     public static boolean copyFile(File srcFile, File dstFile) { | ||||
|         if (!srcFile.exists()) { | ||||
|             LogUtils.d(TAG, "The original file does not exist."); | ||||
|         } else { | ||||
|             try { | ||||
|                 // 源文件路径 | ||||
|                 Path sourcePath = Paths.get(srcFile.getPath()); | ||||
|                 // 目标文件路径 | ||||
|                 Path destPath = Paths.get(dstFile.getPath()); | ||||
|                 // 建立目标父级文件夹 | ||||
|                 if (!dstFile.getParentFile().exists()) { | ||||
|                     dstFile.getParentFile().mkdirs(); | ||||
|                 } | ||||
|                 // 删除旧的目标文件 | ||||
|                 if (dstFile.exists()) { | ||||
|                     dstFile.delete(); | ||||
|                 } | ||||
|                 // 拷贝文件 | ||||
|                 Files.copy(sourcePath, destPath); | ||||
|                 LogUtils.d(TAG, "File copy successfully."); | ||||
|                 return true; | ||||
|             } catch (Exception e) { | ||||
|                 LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @@ -20,10 +20,13 @@ import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| public class GlobalApplication extends Application { | ||||
|  | ||||
|      | ||||
|     public static final String TAG = "GlobalApplication"; | ||||
|      | ||||
|     final static String PREFS = GlobalApplication.class.getName() + "PREFS"; | ||||
|     final static String PREFS_ISDEBUGING = "PREFS_ISDEBUGING"; | ||||
|  | ||||
|  | ||||
|     private static Handler MAIN_HANDLER = new Handler(Looper.getMainLooper()); | ||||
|  | ||||
|     // 是否处于调试状态 | ||||
| @@ -57,13 +60,15 @@ public class GlobalApplication extends Application { | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|  | ||||
|         // 设置应用异常处理窗口 | ||||
|         CrashHandler.init(this); | ||||
|  | ||||
|          | ||||
|         // 设置应用调试状态 | ||||
|         SharedPreferences sharedPreferences = getSharedPreferences(PREFS, Context.MODE_PRIVATE); | ||||
|         GlobalApplication.isDebuging = sharedPreferences.getBoolean(PREFS_ISDEBUGING, GlobalApplication.isDebuging); | ||||
|  | ||||
|         LogUtils.init(this); | ||||
|         LogUtils.d(TAG, "onCreate"); | ||||
|     } | ||||
|  | ||||
|     public static void write(InputStream input, OutputStream output) throws IOException { | ||||
|   | ||||
| @@ -0,0 +1,369 @@ | ||||
| package cc.winboll.studio.libappbase; | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/08/12 13:44:06 | ||||
|  * @Describe LogUtils | ||||
|  * @Describe 应用日志类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import dalvik.system.DexFile; | ||||
| import java.io.BufferedReader; | ||||
| import java.io.BufferedWriter; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.OutputStreamWriter; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Modifier; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Enumeration; | ||||
| import java.util.HashMap; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
| import java.util.Map; | ||||
|  | ||||
|  | ||||
| public class LogUtils { | ||||
|  | ||||
|     public static final String TAG = "LogUtils"; | ||||
|  | ||||
|     public static enum LOG_LEVEL { Off, Error, Warn, Info, Debug, Verbose } | ||||
|  | ||||
|     static volatile boolean _IsInited = false; | ||||
|     static Context _mContext; | ||||
|     // 日志显示时间格式 | ||||
|     static SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("[yyyyMMdd_HHmmSS]", Locale.getDefault()); | ||||
|     // 应用日志文件夹 | ||||
|     static File _mfLogCacheDir; | ||||
|     static File _mfLogDataDir; | ||||
|     // 应用日志文件 | ||||
|     static File _mfLogCatchFile; | ||||
|     static File _mfLogUtilsBeanFile; | ||||
|     static LogUtilsBean _mLogUtilsBean; | ||||
|     public static Map<String, Boolean> mapTAGList = new HashMap<String, Boolean>(); | ||||
|  | ||||
|     // | ||||
|     // 初始化函数 | ||||
|     // | ||||
|     public static void init(Context context) { | ||||
|         _mContext = context; | ||||
|         init(context, LOG_LEVEL.Off); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 初始化函数 | ||||
|     // | ||||
|     public static void init(Context context, LOG_LEVEL logLevel) { | ||||
|         if (GlobalApplication.isDebuging()) { | ||||
|             // 初始化日志缓存文件路径 | ||||
|             _mfLogCacheDir = new File(context.getApplicationContext().getExternalCacheDir(), TAG); | ||||
|             if (!_mfLogCacheDir.exists()) { | ||||
|                 _mfLogCacheDir.mkdirs(); | ||||
|             } | ||||
|             _mfLogCatchFile = new File(_mfLogCacheDir, "log.txt"); | ||||
|  | ||||
|             // 初始化日志配置文件路径 | ||||
|             _mfLogDataDir = context.getApplicationContext().getExternalFilesDir(TAG); | ||||
|             if (!_mfLogDataDir.exists()) { | ||||
|                 _mfLogDataDir.mkdirs(); | ||||
|             } | ||||
|             _mfLogUtilsBeanFile = new File(_mfLogDataDir, TAG + ".json"); | ||||
|         } else { | ||||
|             // 初始化日志缓存文件路径 | ||||
|             _mfLogCacheDir = new File(context.getApplicationContext().getCacheDir(), TAG); | ||||
|             if (!_mfLogCacheDir.exists()) { | ||||
|                 _mfLogCacheDir.mkdirs(); | ||||
|             } | ||||
|             _mfLogCatchFile = new File(_mfLogCacheDir, "log.txt"); | ||||
|  | ||||
|             // 初始化日志配置文件路径 | ||||
|             _mfLogDataDir = new File(context.getApplicationContext().getFilesDir(), TAG); | ||||
|             if (!_mfLogDataDir.exists()) { | ||||
|                 _mfLogDataDir.mkdirs(); | ||||
|             } | ||||
|             _mfLogUtilsBeanFile = new File(_mfLogDataDir, TAG + ".json"); | ||||
|         } | ||||
|  | ||||
| //        Toast.makeText(context, | ||||
| //                       "_mfLogUtilsBeanFile : " + _mfLogUtilsBeanFile | ||||
| //                       + "\n_mfLogCatchFile : " + _mfLogCatchFile, | ||||
| //                       Toast.LENGTH_SHORT).show(); | ||||
| // | ||||
|         _mLogUtilsBean = LogUtilsBean.loadBeanFromFile(_mfLogUtilsBeanFile.getPath(), LogUtilsBean.class); | ||||
|         if (_mLogUtilsBean == null) { | ||||
|             _mLogUtilsBean = new LogUtilsBean(); | ||||
|             _mLogUtilsBean.saveBeanToFile(_mfLogUtilsBeanFile.getPath(), _mLogUtilsBean); | ||||
|         } | ||||
|  | ||||
|         // 加载当前应用下的所有类的 TAG | ||||
|         addClassTAGList(); | ||||
|         loadTAGBeanSettings(); | ||||
|         _IsInited = true; | ||||
|         LogUtils.d(TAG, String.format("mapTAGList : %s", mapTAGList.toString())); | ||||
|     } | ||||
|  | ||||
|     public static Map<String, Boolean> getMapTAGList() { | ||||
|         return mapTAGList; | ||||
|     } | ||||
|  | ||||
|     static void loadTAGBeanSettings() { | ||||
|         ArrayList<LogUtilsClassTAGBean> list = new ArrayList<LogUtilsClassTAGBean>(); | ||||
|         LogUtilsClassTAGBean.loadBeanList(_mContext, list, LogUtilsClassTAGBean.class); | ||||
|         for (int i = 0; i < list.size(); i++) { | ||||
|             LogUtilsClassTAGBean beanSetting = list.get(i); | ||||
|             for (Map.Entry<String, Boolean> entry : mapTAGList.entrySet()) { | ||||
|                 if (entry.getKey().equals(beanSetting.getTag())) { | ||||
|                     entry.setValue(beanSetting.getEnable()); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     static void saveTAGBeanSettings() { | ||||
|         ArrayList<LogUtilsClassTAGBean> list = new ArrayList<LogUtilsClassTAGBean>(); | ||||
|         for (Map.Entry<String, Boolean> entry : mapTAGList.entrySet()) { | ||||
|             list.add(new LogUtilsClassTAGBean(entry.getKey(), entry.getValue())); | ||||
|         } | ||||
|         LogUtilsClassTAGBean.saveBeanList(_mContext, list, LogUtilsClassTAGBean.class); | ||||
|     } | ||||
|  | ||||
|     static void addClassTAGList() { | ||||
|         //ClassLoader classLoader = getClass().getClassLoader(); | ||||
|         try { | ||||
|             //String packageName = context.getPackageName(); | ||||
|             String packageNamePrefix = "cc.winboll.studio"; | ||||
|             List<String> classNames = new ArrayList<>(); | ||||
|             String apkPath = _mContext.getPackageCodePath(); | ||||
|             //Log.d("APK_PATH", "The APK path is: " + apkPath); | ||||
|             LogUtils.d(TAG, String.format("apkPath : %s", apkPath)); | ||||
|             //String apkPath = "/data/app/" + packageName + "-"; | ||||
|  | ||||
|             //DexFile dexfile = new DexFile(apkPath + "1/base.apk"); | ||||
|             DexFile dexfile = new DexFile(apkPath); | ||||
|  | ||||
|             int countTemp = 0; | ||||
|             Enumeration<String> entries = dexfile.entries(); | ||||
|             while (entries.hasMoreElements()) { | ||||
|                 countTemp++; | ||||
|                 String className = entries.nextElement(); | ||||
|                 if (className.startsWith(packageNamePrefix)) { | ||||
|                     classNames.add(className); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             LogUtils.d(TAG, String.format("countTemp : %d\nClassNames size : %d", countTemp, classNames.size())); | ||||
|  | ||||
|             for (String className : classNames) { | ||||
|                 try { | ||||
|                     Class<?> clazz = Class.forName(className); | ||||
|                     Field[] fields = clazz.getDeclaredFields(); | ||||
|                     for (Field field : fields) { | ||||
|                         if (Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()) && field.getType() == String.class && "TAG".equals(field.getName())) { | ||||
|                             String tagValue = (String) field.get(null); | ||||
|                             //Log.d("TAG_INFO", "Class: " + className + ", TAG value: " + tagValue); | ||||
|                             //LogUtils.d(TAG, String.format("Tag Value : %s", tagValue)); | ||||
|                             //mapTAGList.put(tagValue, true); | ||||
|                             mapTAGList.put(tagValue, false); | ||||
|                         } | ||||
|                     } | ||||
|                 } catch (NoClassDefFoundError | ClassNotFoundException | IllegalAccessException e) { | ||||
|                     LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|                     //LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                     //Toast.makeText(context, TAG + " : " + e.getMessage(), Toast.LENGTH_SHORT).show(); | ||||
|                 } | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|             //Toast.makeText(context, TAG + " : " + e.getMessage(), Toast.LENGTH_SHORT).show(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void setTAGListEnable(String tag, boolean isEnable) { | ||||
|         Iterator<Map.Entry<String, Boolean>> iterator = mapTAGList.entrySet().iterator(); | ||||
|         while (iterator.hasNext()) { | ||||
|             Map.Entry<String, Boolean> entry = iterator.next(); | ||||
|             if (tag.equals(entry.getKey())) { | ||||
|                 entry.setValue(isEnable); | ||||
|                 //System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         saveTAGBeanSettings(); | ||||
|         LogUtils.d(TAG, String.format("mapTAGList : %s", mapTAGList.toString())); | ||||
|     } | ||||
|  | ||||
|     public static void setALlTAGListEnable(boolean isEnable) { | ||||
|         Iterator<Map.Entry<String, Boolean>> iterator = mapTAGList.entrySet().iterator(); | ||||
|         while (iterator.hasNext()) { | ||||
|             Map.Entry<String, Boolean> entry = iterator.next(); | ||||
|             entry.setValue(isEnable); | ||||
|             //System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); | ||||
|         } | ||||
|         saveTAGBeanSettings(); | ||||
|         LogUtils.d(TAG, String.format("mapTAGList : %s", mapTAGList.toString())); | ||||
|     } | ||||
|  | ||||
|     public static void setLogLevel(LOG_LEVEL logLevel) { | ||||
|         LogUtils._mLogUtilsBean.setLogLevel(logLevel); | ||||
|         _mLogUtilsBean.saveBeanToFile(_mfLogUtilsBeanFile.getPath(), _mLogUtilsBean); | ||||
|     } | ||||
|  | ||||
|     public static LOG_LEVEL getLogLevel() { | ||||
|         return LogUtils._mLogUtilsBean.getLogLevel(); | ||||
|     } | ||||
|  | ||||
|     static boolean isLoggable(String tag, LOG_LEVEL logLevel) { | ||||
|         return _IsInited && mapTAGList.get(tag) && isInTheLevel(logLevel); | ||||
|     } | ||||
|  | ||||
|     static boolean isInTheLevel(LOG_LEVEL logLevel) { | ||||
|         return (LogUtils._mLogUtilsBean.getLogLevel().ordinal() == logLevel.ordinal() | ||||
|             || LogUtils._mLogUtilsBean.getLogLevel().ordinal() > logLevel.ordinal()); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 获取应用日志文件夹 | ||||
|     // | ||||
|     public static File getLogCacheDir() { | ||||
|         return _mfLogCacheDir; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 调试日志写入函数 | ||||
|     // | ||||
|     public static void e(String szTAG, String szMessage) { | ||||
|         if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Error)) { | ||||
|             saveLog(szTAG, LogUtils.LOG_LEVEL.Error, szMessage); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 调试日志写入函数 | ||||
|     // | ||||
|     public static void w(String szTAG, String szMessage) { | ||||
|         if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Warn)) { | ||||
|             saveLog(szTAG, LogUtils.LOG_LEVEL.Warn, szMessage); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 调试日志写入函数 | ||||
|     // | ||||
|     public static void i(String szTAG, String szMessage) { | ||||
|         if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Info)) { | ||||
|             saveLog(szTAG, LogUtils.LOG_LEVEL.Info, szMessage); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 调试日志写入函数 | ||||
|     // | ||||
|     public static void d(String szTAG, String szMessage) { | ||||
|         if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) { | ||||
|             saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, szMessage); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 调试日志写入函数 | ||||
|     // 包含线程调试堆栈信息 | ||||
|     // | ||||
|     public static void d(String szTAG, String szMessage, StackTraceElement[] listStackTrace) { | ||||
|         if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) { | ||||
|             StringBuilder sbMessage = new StringBuilder(szMessage); | ||||
|             sbMessage.append(" \nAt "); | ||||
|             sbMessage.append(listStackTrace[2].getMethodName()); | ||||
|             sbMessage.append(" ("); | ||||
|             sbMessage.append(listStackTrace[2].getFileName()); | ||||
|             sbMessage.append(":"); | ||||
|             sbMessage.append(listStackTrace[2].getLineNumber()); | ||||
|             sbMessage.append(")"); | ||||
|             saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sbMessage.toString()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 调试日志写入函数 | ||||
|     // 包含异常信息和线程调试堆栈信息 | ||||
|     // | ||||
|     public static void d(String szTAG, Exception e, StackTraceElement[] listStackTrace) { | ||||
|         if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) { | ||||
|             StringBuilder sbMessage = new StringBuilder(e.getClass().toGenericString()); | ||||
|             sbMessage.append(" : "); | ||||
|             sbMessage.append(e.getMessage()); | ||||
|             sbMessage.append(" \nAt "); | ||||
|             sbMessage.append(listStackTrace[2].getMethodName()); | ||||
|             sbMessage.append(" ("); | ||||
|             sbMessage.append(listStackTrace[2].getFileName()); | ||||
|             sbMessage.append(":"); | ||||
|             sbMessage.append(listStackTrace[2].getLineNumber()); | ||||
|             sbMessage.append(")"); | ||||
|             saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sbMessage.toString()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 调试日志写入函数 | ||||
|     // | ||||
|     public static void v(String szTAG, String szMessage) { | ||||
|         if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Verbose)) { | ||||
|             saveLog(szTAG, LogUtils.LOG_LEVEL.Verbose, szMessage); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 日志文件保存函数 | ||||
|     // | ||||
|     static void saveLog(String szTAG, LogUtils.LOG_LEVEL logLevel, String szMessage) { | ||||
|         try { | ||||
|             BufferedWriter out = null; | ||||
|             out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(_mfLogCatchFile, true), "UTF-8")); | ||||
|             out.write("[" + logLevel + "]  " + mSimpleDateFormat.format(System.currentTimeMillis()) + "  [" + szTAG + "]\n" + szMessage + "\n"); | ||||
|             out.close(); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, "IOException : " + e.getMessage()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 历史日志加载函数 | ||||
|     // | ||||
|     public static String loadLog() { | ||||
|         if (_mfLogCatchFile.exists()) { | ||||
|             StringBuffer sb = new StringBuffer(); | ||||
|             try { | ||||
|                 BufferedReader in = null; | ||||
|                 in = new BufferedReader(new InputStreamReader(new FileInputStream(_mfLogCatchFile), "UTF-8")); | ||||
|                 String line = ""; | ||||
|                 while ((line = in.readLine()) != null) { | ||||
|                     sb.append(line); | ||||
|                     sb.append("\n"); | ||||
|                 } | ||||
|             } catch (IOException e) { | ||||
|                 LogUtils.d(TAG, "IOException : " + e.getMessage()); | ||||
|             }  | ||||
|             return sb.toString(); | ||||
|         } | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 清理日志函数 | ||||
|     // | ||||
|     public static void cleanLog() { | ||||
|         if (_mfLogCatchFile.exists()) { | ||||
|             try { | ||||
|                 FileUtils.writeStringToFile(_mfLogCatchFile.getPath(), ""); | ||||
|                 //LogUtils.d(TAG, "cleanLog"); | ||||
|             } catch (IOException e) { | ||||
|                 LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,70 @@ | ||||
| package cc.winboll.studio.libappbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/08/23 15:39:07 | ||||
|  * @Describe LogUtils 数据配置类。 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import java.io.IOException; | ||||
| public class LogUtilsBean extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "LogUtilsBean"; | ||||
|  | ||||
|     LogUtils.LOG_LEVEL logLevel; | ||||
|  | ||||
|     public LogUtilsBean() { | ||||
|         this.logLevel = LogUtils.LOG_LEVEL.Off; | ||||
|     } | ||||
|  | ||||
|     public LogUtilsBean(LogUtils.LOG_LEVEL logLevel) { | ||||
|         this.logLevel = logLevel; | ||||
|     } | ||||
|  | ||||
|     public void setLogLevel(LogUtils.LOG_LEVEL logLevel) { | ||||
|         this.logLevel = logLevel; | ||||
|     } | ||||
|  | ||||
|     public LogUtils.LOG_LEVEL getLogLevel() { | ||||
|         return logLevel; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return LogUtilsBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         LogUtilsBean bean = this; | ||||
|         jsonWriter.name("logLevel").value(bean.getLogLevel().ordinal()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("logLevel")) { | ||||
|                 setLogLevel(LogUtils.LOG_LEVEL.values()[jsonReader.nextInt()]); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,87 @@ | ||||
| package cc.winboll.studio.libappbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2025/01/04 14:17:02 | ||||
|  * @Describe 日志类class TAG 标签数据类 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class LogUtilsClassTAGBean extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "LogUtilsClassTAGBean"; | ||||
|  | ||||
|     // 标签名 | ||||
|     String tag; | ||||
|     // 是否启用 | ||||
|     Boolean enable; | ||||
|  | ||||
|     public LogUtilsClassTAGBean() { | ||||
|         this.tag = TAG; | ||||
|         this.enable = true; | ||||
|     } | ||||
|  | ||||
|     public LogUtilsClassTAGBean(String tag, Boolean enable) { | ||||
|         this.tag = tag; | ||||
|         this.enable = enable; | ||||
|     } | ||||
|  | ||||
|     public void setTag(String tag) { | ||||
|         this.tag = tag; | ||||
|     } | ||||
|  | ||||
|     public String getTag() { | ||||
|         return tag; | ||||
|     } | ||||
|  | ||||
|     public void setEnable(Boolean enable) { | ||||
|         this.enable = enable; | ||||
|     } | ||||
|  | ||||
|     public Boolean getEnable() { | ||||
|         return enable; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return LogUtilsClassTAGBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         LogUtilsClassTAGBean bean = this; | ||||
|         jsonWriter.name("tag").value(bean.getTag()); | ||||
|         jsonWriter.name("enable").value(bean.getEnable()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("tag")) { | ||||
|                 setTag(jsonReader.nextString()); | ||||
|             } else if (name.equals("enable")) { | ||||
|                 setEnable(jsonReader.nextBoolean()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 ZhanGSKen
					ZhanGSKen