編輯:關於Android編程
當出現崩潰,軟件不會閃退,會出現彈出一個對話框,異常錯誤信息會自動保存在sd卡crash這個文件夾下。後續需要還可以發送到服務器的。看效果圖。

package com.crashhandler.util;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.crashhandler.activity.R;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.view.WindowManager;
/**
* UncaughtException處理類,當程序發生Uncaught異常的時候,由該類來接管程序,並記錄發送錯誤報告.
*
*/
public class CrashHandler implements UncaughtExceptionHandler {
// 系統默認的UncaughtException處理類
private Thread.UncaughtExceptionHandler mDefaultHandler;
// CrashHandler實例
private static CrashHandler INSTANCE;
// 程序的Context對象
private Context mContext;
//保證只有一個CrashHandler實例
private CrashHandler() {
}
//獲取CrashHandler實例 ,單例模式
public static CrashHandler getInstance() {
if (INSTANCE == null)
INSTANCE = new CrashHandler();
return INSTANCE;
}
/**
* 初始化
*
* @param context
*/
public void init(Context context) {
mContext = context;
// 獲取系統默認的UncaughtException處理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// 設置該CrashHandler為程序的默認處理器
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 當UncaughtException發生時會轉入該重寫的方法來處理
*/
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果自定義的沒有處理則讓系統默認的異常處理器來處理
mDefaultHandler.uncaughtException(thread, ex);
}
}
/**
* 自定義錯誤處理,收集錯誤信息 發送錯誤報告等操作均在此完成.
*
* @param ex
* 異常信息
* @return true 如果處理了該異常信息;否則返回false.
*/
public boolean handleException(Throwable ex) {
if (ex == null || mContext == null)
return false;
final String crashReport = getCrashReport(mContext, ex);
new Thread() {
public void run() {
Looper.prepare();
File file = save2File(crashReport);
sendAppCrashReport(mContext, crashReport, file);
Looper.loop();
}
}.start();
return true;
}
@SuppressLint(SimpleDateFormat)
private File save2File(String crashReport) {
//用於格式化日期,作為日志文件名的一部分
DateFormat dateFormat = new SimpleDateFormat(yyyyMMddHHmmss);
String time = dateFormat.format(new Date());
String fileName = crash- + time + - + System.currentTimeMillis() + .txt;
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
try {
//存儲路徑,是sd卡的crash文件夾
File dir = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + File.separator + crash);
if (!dir.exists())
dir.mkdir();
File file = new File(dir, fileName);
FileOutputStream fos = new FileOutputStream(file);
fos.write(crashReport.toString().getBytes());
fos.close();
return file;
} catch (Exception e) {
//sd卡存儲,記得加上權限,不然這裡會拋出異常
Log.i(Show,save2File error: + e.getMessage());
}
}
return null;
}
private void sendAppCrashReport(final Context context,
final String crashReport, final File file) {
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle(R.string.app_error)
.setMessage(R.string.app_error_message)
.setPositiveButton(R.string.submit_report,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try {
//這以下的內容,只做參考,因為沒有服務器
Intent intent = new Intent(Intent.ACTION_SEND);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
String[] tos = { way.ping.li@gmail.com };
intent.putExtra(Intent.EXTRA_EMAIL, tos);
intent.putExtra(Intent.EXTRA_SUBJECT,
Android客戶端 - 錯誤報告);
if (file != null) {
intent.putExtra(Intent.EXTRA_STREAM,
Uri.fromFile(file));
intent.putExtra(Intent.EXTRA_TEXT,
請將此錯誤報告發送給我,以便我盡快修復此問題,謝謝合作!
);
} else {
intent.putExtra(Intent.EXTRA_TEXT,
請將此錯誤報告發送給我,以便我盡快修復此問題,謝謝合作!
+ crashReport);
}
intent.setType(text/plain);
intent.setType(message/rfc882);
Intent.createChooser(intent, Choose Email Client);
context.startActivity(intent);
} catch (Exception e) {
Log.i(Show,error: + e.getMessage());
} finally {
dialog.dismiss();
// 退出
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
}
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
// 退出
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
});
AlertDialog dialog = builder.create();
//需要的窗口句柄方式,沒有這句會報錯的
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.show();
}
/**
* 獲取APP崩潰異常報告
*
* @param ex
* @return
*/
private String getCrashReport(Context context, Throwable ex) {
PackageInfo pinfo = getPackageInfo(context);
StringBuffer exceptionStr = new StringBuffer();
exceptionStr.append(Version: + pinfo.versionName + (
+ pinfo.versionCode + )
);
exceptionStr.append(Android: + android.os.Build.VERSION.RELEASE
+ ( + android.os.Build.MODEL + )
);
exceptionStr.append(Exception: + ex.getMessage() +
);
StackTraceElement[] elements = ex.getStackTrace();
for (int i = 0; i < elements.length; i++) {
exceptionStr.append(elements[i].toString() +
);
}
return exceptionStr.toString();
}
/**
* 獲取App安裝包信息
*
* @return
*/
private PackageInfo getPackageInfo(Context context) {
PackageInfo info = null;
try {
info = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
} catch (NameNotFoundException e) {
e.printStackTrace(System.err);
}
if (info == null)
info = new PackageInfo();
return info;
}
}
package com.crashhandler.util;
import android.app.Application;
public class MyApplication extends Application{
private static MyApplication mApplication;
public synchronized static MyApplication getInstance() {
return mApplication;
}
@Override
public void onCreate() {
super.onCreate();
initData();
}
private void initData() {
//當程序發生Uncaught異常的時候,由該類來接管程序,一定要在這裡初始化
CrashHandler.getInstance().init(this);
}
}
package com.crashhandler.activity;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.button1);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
//自已寫了一個異常信息,進行測試
Button button = (Button)findViewById(R.id.textView1);
break;
default:
break;
}
}
}
網絡請求庫之android-async-http
Android中網絡請求一般使用Apache HTTP Client或者采用HttpURLConnect,但是直接使用這兩個類庫需要寫大量的代碼才能完成網絡post和ge
Andriod 自定義控件之音頻條
今天我們實現一個直接繼承於View的全新控件。大家都知道音樂播放器吧,在點擊一首歌進行播放時,通常會有一塊區域用於顯示音頻條,我們今天就來學習下,播放器音頻條的實現。首先
android開發 AsyncTask的使用
AsyncTask 資料上寫是android提供的輕量級的異步類 可以直接繼承AsyncTask 在類中實現異步操作 並提供接口反饋當
Android實現自動提取短信驗證碼功能
本文實例講解了Android自動提取短信驗證碼解決方案,分享給大家供大家參考,具體內容如下主要功能及優點1.收到驗證碼短信後,自動提取短信中的驗證碼填寫到相應輸入框 2.