編輯:關於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 = { [email protected] }; 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中網絡請求一般使用Apache HTTP Client或者采用HttpURLConnect,但是直接使用這兩個類庫需要寫大量的代碼才能完成網絡post和ge
今天我們實現一個直接繼承於View的全新控件。大家都知道音樂播放器吧,在點擊一首歌進行播放時,通常會有一塊區域用於顯示音頻條,我們今天就來學習下,播放器音頻條的實現。首先
AsyncTask 資料上寫是android提供的輕量級的異步類 可以直接繼承AsyncTask 在類中實現異步操作 並提供接口反饋當
本文實例講解了Android自動提取短信驗證碼解決方案,分享給大家供大家參考,具體內容如下主要功能及優點1.收到驗證碼短信後,自動提取短信中的驗證碼填寫到相應輸入框 2.