diff --git a/README.md b/README.md
index a8377d7..718f860 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ Debug监听程序崩溃日志,直接页面展示崩溃日志列表,方便自
#### 2.在app目录下的build.gradle中添加依赖
``` gradle
dependencies {
- compile 'com.github.maning0303:MNCrashMonitor:V1.0.2'
+ compile 'com.github.maning0303:MNCrashMonitor:V1.0.3'
}
```
@@ -36,12 +36,20 @@ Debug监听程序崩溃日志,直接页面展示崩溃日志列表,方便自
``` java
- /**
- * 初始化日志系统
- * context : 上下文
- * isDebug : 是不是Debug模式,true:崩溃后显示自定义崩溃页面 ;false:关闭应用,不跳转奔溃页面(默认)
- */
- MCrashMonitor.init(this, true);
+ /**
+ * 初始化日志系统
+ * context : 上下文
+ * isDebug : 是不是Debug模式,true:崩溃后显示自定义崩溃页面 ;false:关闭应用,不跳转奔溃页面(默认)
+ * CrashCallBack : 回调执行
+ */
+ MCrashMonitor.init(this, true, new CrashCallBack() {
+ @Override
+ public void onCrash(File file) {
+ //可以在这里重启应用
+ //可以在这里保存标识,下次再次进入把日志发送给服务器
+ Log.i(TAG, "CrashMonitor回调:" + file.getAbsolutePath());
+ }
+ });
```
@@ -49,6 +57,8 @@ Debug监听程序崩溃日志,直接页面展示崩溃日志列表,方便自
``` java
/Android/data/包名/cache/crashLogs/
+ 或者
+ /data/data/包名/cache/crashLogs/
```
@@ -56,10 +66,31 @@ Debug监听程序崩溃日志,直接页面展示崩溃日志列表,方便自
### 喜欢就Star一下吧!
### 注意:
-当应用已启动就崩溃的无法打开页面,直接看通知或者去文件夹里面查看:/Android/data/包名/cache/crashLogs/
+当应用已启动就崩溃的无法打开页面,直接看通知或者去文件夹里面查看:
+ /Android/data/包名/cache/crashLogs/
+ 或者
+ /data/data/包名/cache/crashLogs/
## 感谢:
#### 内部使用了一些三方库文件:
##### [StatusBarUtil](https://github.com/laobie/StatusBarUtil)
##### [NotifyUtil](https://github.com/wenmingvs/NotifyUtil)
+
+## 推荐:
+Name | Describe |
+--- | --- |
+[GankMM](https://github.com/maning0303/GankMM) | (Material Design & MVP & Retrofit + OKHttp & RecyclerView ...)Gank.io Android客户端:每天一张美女图片,一个视频短片,若干Android,iOS等程序干货,周一到周五每天更新,数据全部由 干货集中营 提供,持续更新。 |
+[MNUpdateAPK](https://github.com/maning0303/MNUpdateAPK) | Android APK 版本更新的下载和安装,适配7.0,简单方便。 |
+[MNImageBrowser](https://github.com/maning0303/MNImageBrowser) | 交互特效的图片浏览框架,微信向下滑动动态关闭 |
+[MNCalendar](https://github.com/maning0303/MNCalendar) | 简单的日历控件练习,水平方向日历支持手势滑动切换,跳转月份;垂直方向日历选取区间范围。 |
+[MClearEditText](https://github.com/maning0303/MClearEditText) | 带有删除功能的EditText |
+[MNCrashMonitor](https://github.com/maning0303/MNCrashMonitor) | Debug监听程序崩溃日志,展示崩溃日志列表,方便自己平时调试。 |
+[MNProgressHUD](https://github.com/maning0303/MNProgressHUD) | MNProgressHUD是对常用的自定义弹框封装,加载ProgressDialog,状态显示的StatusDialog和自定义Toast,支持背景颜色,圆角,边框和文字的自定义。 |
+[MNXUtilsDB](https://github.com/maning0303/MNXUtilsDB) | xUtils3 数据库模块单独抽取出来,方便使用。 |
+[MNVideoPlayer](https://github.com/maning0303/MNVideoPlayer) | SurfaceView + MediaPlayer 实现的视频播放器,支持横竖屏切换,手势快进快退、调节音量,亮度等。------代码简单,新手可以看一看。 |
+[MNZXingCode](https://github.com/maning0303/MNZXingCode) | 快速集成二维码扫描和生成二维码 |
+[MNChangeSkin](https://github.com/maning0303/MNChangeSkin) | Android夜间模式,通过Theme实现 |
+[SwitcherView](https://github.com/maning0303/SwitcherView) | 垂直滚动的广告栏文字展示。 |
+[MNPasswordEditText](https://github.com/maning0303/MNPasswordEditText) | 类似微信支付宝的密码输入框。 |
+[MNSwipeToLoadDemo](https://github.com/maning0303/MNSwipeToLoadDemo) | 利用SwipeToLoadLayout实现的各种下拉刷新效果(饿了吗,京东,百度外卖,美团外卖,天猫下拉刷新等)。 |
diff --git a/app/build.gradle b/app/build.gradle
index aaef4e2..9bbac88 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -21,6 +21,7 @@ android {
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
+ compile 'com.android.support.constraint:constraint-layout:1.0.2'
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 17a7aa8..d6ce8a3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,6 +16,7 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/com/maning/crashmonitor/MainActivity.java b/app/src/main/java/com/maning/crashmonitor/MainActivity.java
index a8d0396..756c153 100644
--- a/app/src/main/java/com/maning/crashmonitor/MainActivity.java
+++ b/app/src/main/java/com/maning/crashmonitor/MainActivity.java
@@ -1,5 +1,6 @@
package com.maning.crashmonitor;
+import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
@@ -24,4 +25,9 @@ public void btn02(View view) {
MCrashMonitor.startCrashListPage(this);
}
+
+ public void btn03(View view) {
+ startActivity(new Intent(this,SecondActivity.class));
+ }
+
}
diff --git a/app/src/main/java/com/maning/crashmonitor/MyApplication.java b/app/src/main/java/com/maning/crashmonitor/MyApplication.java
index e1310b4..9e3205e 100644
--- a/app/src/main/java/com/maning/crashmonitor/MyApplication.java
+++ b/app/src/main/java/com/maning/crashmonitor/MyApplication.java
@@ -3,8 +3,11 @@
import android.app.Application;
import android.util.Log;
+import com.maning.librarycrashmonitor.listener.CrashCallBack;
import com.maning.librarycrashmonitor.main.MCrashMonitor;
+import java.io.File;
+
/**
* Created by maning on 2017/4/20.
*/
@@ -28,7 +31,15 @@ private void initCrashMonitor() {
* 初始化日志系统
* context : 上下文
* isDebug : 是不是Debug模式,true:崩溃后显示自定义崩溃页面 ;false:关闭应用,不跳转奔溃页面(默认)
+ * CrashCallBack : 回调执行
*/
- MCrashMonitor.init(this, true);
+ MCrashMonitor.init(this, true, new CrashCallBack() {
+ @Override
+ public void onCrash(File file) {
+ //可以在这里重启应用
+ //可以在这里保存标识,下次再次进入把日志发送给服务器
+ Log.i(TAG, "CrashMonitor回调:" + file.getAbsolutePath());
+ }
+ });
}
}
diff --git a/app/src/main/java/com/maning/crashmonitor/SecondActivity.java b/app/src/main/java/com/maning/crashmonitor/SecondActivity.java
new file mode 100644
index 0000000..bb8868d
--- /dev/null
+++ b/app/src/main/java/com/maning/crashmonitor/SecondActivity.java
@@ -0,0 +1,20 @@
+package com.maning.crashmonitor;
+
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.View;
+
+public class SecondActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_second);
+ }
+
+ public void btn01(View view) {
+ //手动造成一个Crash
+ throw new NullPointerException("自定义异常抛出2");
+ }
+
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index f47a6b5..6896fd6 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -4,10 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin">
+ android:padding="10dp">
+
+
diff --git a/app/src/main/res/layout/activity_second.xml b/app/src/main/res/layout/activity_second.xml
new file mode 100644
index 0000000..8b369ee
--- /dev/null
+++ b/app/src/main/res/layout/activity_second.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/library/src/main/java/com/maning/librarycrashmonitor/crash/CrashHandler.java b/library/src/main/java/com/maning/librarycrashmonitor/crash/CrashHandler.java
index 8397c1c..9c86107 100644
--- a/library/src/main/java/com/maning/librarycrashmonitor/crash/CrashHandler.java
+++ b/library/src/main/java/com/maning/librarycrashmonitor/crash/CrashHandler.java
@@ -8,9 +8,11 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;
+import android.os.SystemClock;
import android.util.Log;
import com.maning.librarycrashmonitor.R;
+import com.maning.librarycrashmonitor.listener.CrashCallBack;
import com.maning.librarycrashmonitor.main.MCrashMonitor;
import com.maning.librarycrashmonitor.ui.activity.CrashListActivity;
import com.maning.librarycrashmonitor.utils.MFileUtils;
@@ -27,8 +29,7 @@
public class CrashHandler implements UncaughtExceptionHandler {
- private static final String TAG = "Crash";
- private static final boolean DEBUG = true;
+ private static final String TAG = "CrashMonitor";
//log文件的后缀名
private static final String FILE_NAME_SUFFIX = ".txt";
@@ -40,7 +41,10 @@ public class CrashHandler implements UncaughtExceptionHandler {
private Context mContext;
+ //是否处于Debug状态
private boolean isDebug = false;
+ //回调
+ private CrashCallBack crashCallBack;
//构造方法私有,防止外部构造多个实例,即采用单例模式
private CrashHandler() {
@@ -65,26 +69,40 @@ public void init(Context context, boolean isDebug) {
this.isDebug = isDebug;
}
+ public void init(Context context, boolean isDebug, CrashCallBack crashCallBack) {
+ init(context);
+ this.isDebug = isDebug;
+ this.crashCallBack = crashCallBack;
+ }
+
+ public void init(Context context, CrashCallBack crashCallBack) {
+ init(context);
+ this.crashCallBack = crashCallBack;
+ }
+
/**
* 这个是最关键的函数,当程序中有未被捕获的异常,系统将会自动调用#uncaughtException方法
* thread为出现未捕获异常的线程,ex为未捕获的异常,有了这个ex,我们就可以得到异常信息。
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
- try {
- //导出异常信息到SD卡中
- dumpExceptionToSDCard(ex);
- } catch (IOException e) {
- e.printStackTrace();
+
+ //导出异常信息到SD卡中
+ File file = dumpExceptionToSDCard(ex);
+
+ //回调处理
+ if (crashCallBack != null) {
+ crashCallBack.onCrash(file);
}
//打印出当前调用栈信息
ex.printStackTrace();
- //开启页面
- if (isDebug) {
- MCrashMonitor.startCrashShowPage(mContext);
- }
+ //延时1秒杀死进程
+ SystemClock.sleep(1000);
+
+ //Debug相关处理
+ debugHandler(ex);
//这里可以弹出自己自定义的程序崩溃页面:然后自己干掉自己;
//如果系统提供了默认的异常处理器,则交给系统去结束我们的程序,否则就由我们自己结束自己
@@ -97,63 +115,51 @@ public void uncaughtException(Thread thread, Throwable ex) {
}
- private void dumpExceptionToSDCard(Throwable ex) throws IOException {
- //如果SD卡不存在或无法使用,则无法把异常信息写入SD卡
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- if (DEBUG) {
- Log.w(TAG, "sdcard unmounted,skip dump exception");
- return;
- }
- }
- File dir = new File(MFileUtils.getCrashLogPath(mContext));
- if (!dir.exists()) {
- dir.mkdirs();
- }
- long current = System.currentTimeMillis();
- //版本号
- String version = "";
+ private File dumpExceptionToSDCard(Throwable ex) {
+ File file = null;
+ PrintWriter pw = null;
try {
+ //Log保存路径
+ // SDCard/Android/data//cache
+ // data/data//cache
+ File dir = new File(MFileUtils.getCrashLogPath(mContext));
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+ //版本号
PackageManager pm = mContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
- version = "V" + pi.versionName + "_";
- } catch (Exception e) {
-
- }
- //时间
- String time = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date(current));
-
- time = "T" + time;
-
- //以当前时间创建log文件
- File file = new File(dir, "CrashLog_" + version + time.trim() + FILE_NAME_SUFFIX);
- if (!file.exists()) {
- file.createNewFile();
- }
+ String version = "V" + pi.versionName + "_";
+ //时间
+ String time = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date(System.currentTimeMillis()));
+ time = "T" + time;
+
+ //以当前时间创建log文件
+ file = new File(dir, "CrashLog_" + version + time.trim() + FILE_NAME_SUFFIX);
+ if (!file.exists()) {
+ file.createNewFile();
+ }
- try {
- PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
+ //开始写日志
+ pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
//导出发生异常的时间
pw.println(time);
-
//导出手机信息
dumpPhoneInfo(pw);
-
+ //换行
pw.println();
-
//导出异常的调用栈信息
ex.printStackTrace(pw);
- //Debug才通知
- if (isDebug) {
- notify_log(time.trim(), Log.getStackTraceString(ex));
- }
-
- pw.close();
-
} catch (Exception e) {
- Log.e(TAG, "dump crash info failed:" + e.toString());
+ Log.e(TAG, "保存日志失败::" + e.toString());
+ } finally {
+ if (pw != null) {
+ pw.close();
+ }
}
+ return file;
}
private void dumpPhoneInfo(PrintWriter pw) throws NameNotFoundException {
@@ -185,7 +191,18 @@ private void dumpPhoneInfo(PrintWriter pw) throws NameNotFoundException {
}
- private void notify_log(String title, String content) {
+ private void debugHandler(Throwable ex) {
+ if (!isDebug) {
+ return;
+ }
+ //发送通知
+ notify_log(Log.getStackTraceString(ex));
+ //开启日志详情页面
+ MCrashMonitor.startCrashShowPage(mContext);
+ }
+
+
+ private void notify_log(String content) {
//设置想要展示的数据内容
Intent intent = new Intent(mContext, CrashListActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
@@ -193,6 +210,8 @@ private void notify_log(String title, String content) {
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
int smallIcon = R.drawable.crash_ic_show_error;
String ticker = "Crash通知";
+ String time = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date(System.currentTimeMillis()));
+ String title = "Crash通知:" + time;
//实例化工具类,并且调用接口
MNotifyUtil notify2 = new MNotifyUtil(mContext, 1);
notify2.notify_normail_moreline(pIntent, smallIcon, ticker, title, content, true, true, false);
diff --git a/library/src/main/java/com/maning/librarycrashmonitor/listener/CrashCallBack.java b/library/src/main/java/com/maning/librarycrashmonitor/listener/CrashCallBack.java
new file mode 100644
index 0000000..a014625
--- /dev/null
+++ b/library/src/main/java/com/maning/librarycrashmonitor/listener/CrashCallBack.java
@@ -0,0 +1,13 @@
+package com.maning.librarycrashmonitor.listener;
+
+import java.io.File;
+
+/**
+ * Created by maning on 2017/11/8.
+ */
+
+public interface CrashCallBack {
+
+ void onCrash(File file);
+
+}
diff --git a/library/src/main/java/com/maning/librarycrashmonitor/main/MCrashMonitor.java b/library/src/main/java/com/maning/librarycrashmonitor/main/MCrashMonitor.java
index 253a76c..6407ce2 100644
--- a/library/src/main/java/com/maning/librarycrashmonitor/main/MCrashMonitor.java
+++ b/library/src/main/java/com/maning/librarycrashmonitor/main/MCrashMonitor.java
@@ -4,6 +4,7 @@
import android.content.Intent;
import com.maning.librarycrashmonitor.crash.CrashHandler;
+import com.maning.librarycrashmonitor.listener.CrashCallBack;
import com.maning.librarycrashmonitor.ui.activity.CrashListActivity;
import com.maning.librarycrashmonitor.ui.activity.CrashShowActivity;
@@ -14,11 +15,26 @@
public class MCrashMonitor {
+ public static void init(Context context) {
+ CrashHandler crashHandler = CrashHandler.getInstance();
+ crashHandler.init(context);
+ }
+
public static void init(Context context, boolean isDebug) {
CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(context, isDebug);
}
+ public static void init(Context context, CrashCallBack crashCallBacks) {
+ CrashHandler crashHandler = CrashHandler.getInstance();
+ crashHandler.init(context, crashCallBacks);
+ }
+
+ public static void init(Context context, boolean isDebug, CrashCallBack crashCallBacks) {
+ CrashHandler crashHandler = CrashHandler.getInstance();
+ crashHandler.init(context, isDebug, crashCallBacks);
+ }
+
public static void startCrashListPage(Context context) {
Intent intent = new Intent(context.getApplicationContext(), CrashListActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/library/src/main/java/com/maning/librarycrashmonitor/utils/MFileUtils.java b/library/src/main/java/com/maning/librarycrashmonitor/utils/MFileUtils.java
index 21788f4..dd1954f 100644
--- a/library/src/main/java/com/maning/librarycrashmonitor/utils/MFileUtils.java
+++ b/library/src/main/java/com/maning/librarycrashmonitor/utils/MFileUtils.java
@@ -1,6 +1,7 @@
package com.maning.librarycrashmonitor.utils;
import android.content.Context;
+import android.os.Environment;
import java.io.File;
import java.util.ArrayList;
@@ -14,17 +15,36 @@
public class MFileUtils {
- private static final String TAG = "CrashMonitor";
-
/**
* SDCard/Android/data//cache
+ * data/data//cache
*/
public static String getCrashLogPath(Context context) {
- File externalCacheDir = context.getExternalCacheDir();
- String path = externalCacheDir.getAbsolutePath() + File.separator + "crashLogs";
+ String path = getCachePath(context) + File.separator + "crashLogs";
return path;
}
+ /**
+ * 获取app缓存路径
+ * SDCard/Android/data//cache
+ * data/data//cache
+ *
+ * @param context
+ * @return
+ */
+ public static String getCachePath(Context context) {
+ String cachePath;
+ if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
+ || !Environment.isExternalStorageRemovable()) {
+ //外部存储可用
+ cachePath = context.getExternalCacheDir().getAbsolutePath();
+ } else {
+ //外部存储不可用
+ cachePath = context.getCacheDir().getAbsolutePath();
+ }
+ return cachePath;
+ }
+
public static List getFileList(File file) {
List mFileList = new ArrayList<>();