Android 는 애플 리 케 이 션 충돌 정 보 를 개발 자 에 게 보 내 고 애플 리 케 이 션 을 다시 시작 하 는 방법 을 실현 합 니 다.
18721 단어 Android응용 정보 전송응용 프로그램 다시 시작
개발 과정 에서 테스트 를 거 쳤 지만 발표 후 많은 사용자 들 의 다양한 운영 환경 과 작업 에서 예상 치 못 한 오류 가 발생 하여 프로그램 이 무 너 질 수 있 습 니 다.이러한 오류 정 보 를 수집 하고 개발 자 에 게 피드백 하 는 것 은 개발 자 에 게 최적화 프로그램 을 개선 하 는 데 상당히 중요 하 다.자,다음은 이런 기능 을 실현 합 시다.
(정정 시간:2012 년 2 월 9 일 18 시 42 분 07 초)
역사 첩 때문에 다음 과 같은 방법 은 낭비 되 지만 이상 한 효 과 를 잡 는 것 은 같다.
1.UI 스 레 드(즉,Android 의 메 인 스 레 드)에 대한 캡 처 되 지 않 은 이상 정 보 를 저장 한 후 전체 프로그램 으로 종료 합 니 다.프로그램 을 다시 시작 하면 충돌 정보 피드백 인터페이스 에 들 어가 오류 정 보 를 개발 자 에 게 이메일 로 보 냅 니 다.
2.비 UI 스 레 드 가 던 진 이상 에 대해 서 는 충돌 정보 피드백 인터페이스 에서 사용자 에 게 오류 메 시 지 를 이메일 로 보 내 는 것 을 알려 줍 니 다.
효과 도 는 다음 과 같다.
과정 을 이해 하면 알 아야 할 몇 가지 지식 은 다음 과 같다.
1.차단 UncaughtException
application.onCreate()는 전체 Android 응용 프로그램의 입구 방법 입 니 다.이 방법 에서 다음 코드 를 실행 하면 UncaughtException 을 차단 할 수 있 습 니 다.
ueHandler = new UEHandler(this);
//
Thread.setDefaultUncaughtExceptionHandler(ueHandler);
2.프로그램 붕 괴 를 초래 한 이상 정 보 를 캡 처UEHandler 는 Thread.UncaughtExceptionHandler 의 실현 클래스 로 Public void uncaughtException(Thread thread,Throwable ex)의 실현 에서 충돌 정 보 를 얻 을 수 있 습 니 다.코드 는 다음 과 같 습 니 다.
// fetch Excpetion Info
String info = null;
ByteArrayOutputStream baos = null;
PrintStream printStream = null;
try {
baos = new ByteArrayOutputStream();
printStream = new PrintStream(baos);
ex.printStackTrace(printStream);
byte[] data = baos.toByteArray();
info = new String(data);
data = null;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (printStream != null) {
printStream.close();
}
if (baos != null) {
baos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
3.프로그램 이 이상 을 던 진 후 전체 프로그램 을 닫 아야 합 니 다.슬 픈 프로그래머,에이,다음 세 가지 방식 이 모두 무효 야,어 떡 해!!
3.1 android.os.Process.killProcess(android.os.Process.myPid());
3.2 ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.restartPackage("lab.sodino.errorreport");
3.3 System.exit(0)
좋아,모 주석 은 우리 에 게 스스로 풍족 하 게 생활 하 라 고 말 했다.
SoftApplication 에서 변수 need2Exit 를 설명 합 니 다.그 값 은 true 표지 입 니 다.현재 프로그램 은 완전히 종료 해 야 합 니 다.false 때 뭐 해?뭐 해?이 변 수 는 액 티 비 티.onCreate()를 시작 하 는 곳 에 false 를 할당 합 니 다.
충돌 정 보 를 캡 처 한 후 Softapplication.setNeed 2 Exit(true)표지 프로그램 을 종료 하고 finish()에서 ActErrorReport 를 떨 어 뜨 려 야 합 니 다.이때 ActErrorReport 가 스 택 을 탈퇴 하고 잘못 던 진 ActOccurError 가 휴대 전화 화면 을 차지 합 니 다.Activity 의 수명 주기 에 따라 onStart()를 호출 하려 면 onStart()에서 need 2 Exit 의 상 태 를 읽 고 true 라면 현재 Activity 로 닫 습 니 다.전체 애플 리 케 이 션 을 종료 하 였 습 니 다.이 방법 은 여러 개의 Activity 가 열 린 애플 리 케 이 션 을 한꺼번에 종료 하 는 것 을 해결 할 수 있 습 니 다.상세 코드 는 아래 의 예시 원본 코드 를 읽 으 십시오.
자,코드 는 다음 과 같 습 니 다.
lab.sodino.errorreport.SoftApplication.java
package lab.sodino.errorreport;
import java.io.File;
import android.app.Application;
/**
* @author Sodino E-mail:[email protected]
* @version Time:2011-6-9 11:49:56
*/
public class SoftApplication extends Application {
/** "/data/data/<app_package>/files/error.log" */
public static final String PATH_ERROR_LOG = File.separator + "data" + File.separator + "data"
+ File.separator + "lab.sodino.errorreport" + File.separator + "files" + File.separator
+ "error.log";
/** 。 true Activity finish()。 */
private boolean need2Exit;
/** 。 */
private UEHandler ueHandler;
public void onCreate() {
need2Exit = false;
ueHandler = new UEHandler(this);
//
Thread.setDefaultUncaughtExceptionHandler(ueHandler);
}
public void setNeed2Exit(boolean bool) {
need2Exit = bool;
}
public boolean need2Exit() {
return need2Exit;
}
}
lab.sodino.errorreport.ActOccurError.java
package lab.sodino.errorreport;
import java.io.File;
import java.io.FileInputStream;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class ActOccurError extends Activity {
private SoftApplication softApplication;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
softApplication = (SoftApplication) getApplication();
// "need2Exit=false"。
softApplication.setNeed2Exit(false);
Log.d("ANDROID_LAB", "ActOccurError.onCreate()");
Button btnMain = (Button) findViewById(R.id.btnThrowMain);
btnMain.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
Log.d("ANDROID_LAB", "Thread.main.run()");
int i = 0;
i = 100 / i;
}
});
Button btnChild = (Button) findViewById(R.id.btnThrowChild);
btnChild.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
new Thread() {
public void run() {
Log.d("ANDROID_LAB", "Thread.child.run()");
int i = 0;
i = 100 / i;
}
}.start();
}
});
// error.log
String errorContent = getErrorLog();
if (errorContent != null) {
Intent intent = new Intent(this, ActErrorReport.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("error", errorContent);
intent.putExtra("by", "error.log");
startActivity(intent);
}
}
public void onStart() {
super.onStart();
if (softApplication.need2Exit()) {
Log.d("ANDROID_LAB", "ActOccurError.finish()");
ActOccurError.this.finish();
} else {
// do normal things
}
}
/**
* 。<br/>
* error.log 。<br/>
*
* @return null。
*/
private String getErrorLog() {
File fileErrorLog = new File(SoftApplication.PATH_ERROR_LOG);
String content = null;
FileInputStream fis = null;
try {
if (fileErrorLog.exists()) {
byte[] data = new byte[(int) fileErrorLog.length()];
fis = new FileInputStream(fileErrorLog);
fis.read(data);
content = new String(data);
data = null;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
if (fileErrorLog.exists()) {
fileErrorLog.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return content;
}
}
lab.sodino.errorreport.ActErrorReport.java
package lab.sodino.errorreport;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
/**
* @author Sodino E-mail:[email protected]
* @version Time:2011-6-12 01:34:17
*/
public class ActErrorReport extends Activity {
private SoftApplication softApplication;
private String info;
/** 。 */
private String by;
private Button btnReport;
private Button btnCancel;
private BtnListener btnListener;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.report);
softApplication = (SoftApplication) getApplication();
by = getIntent().getStringExtra("by");
info = getIntent().getStringExtra("error");
TextView txtHint = (TextView) findViewById(R.id.txtErrorHint);
txtHint.setText(getErrorHint(by));
EditText editError = (EditText) findViewById(R.id.editErrorContent);
editError.setText(info);
btnListener = new BtnListener();
btnReport = (Button) findViewById(R.id.btnREPORT);
btnCancel = (Button) findViewById(R.id.btnCANCEL);
btnReport.setOnClickListener(btnListener);
btnCancel.setOnClickListener(btnListener);
}
private String getErrorHint(String by) {
String hint = "";
String append = "";
if ("uehandler".equals(by)) {
append = " when the app running";
} else if ("error.log".equals(by)) {
append = " when last time the app running";
}
hint = String.format(getResources().getString(R.string.errorHint), append, 1);
return hint;
}
public void onStart() {
super.onStart();
if (softApplication.need2Exit()) {
// Activity “ ” 。
Log.d("ANDROID_LAB", "ActErrorReport.finish()");
ActErrorReport.this.finish();
} else {
// go ahead normally
}
}
class BtnListener implements Button.OnClickListener {
@Override
public void onClick(View v) {
if (v == btnReport) {
// android.permission.SEND
Intent mailIntent = new Intent(Intent.ACTION_SEND);
mailIntent.setType("plain/text");
String[] arrReceiver = { "[email protected]" };
String mailSubject = "App Error Info[" + getPackageName() + "]";
String mailBody = info;
mailIntent.putExtra(Intent.EXTRA_EMAIL, arrReceiver);
mailIntent.putExtra(Intent.EXTRA_SUBJECT, mailSubject);
mailIntent.putExtra(Intent.EXTRA_TEXT, mailBody);
startActivity(Intent.createChooser(mailIntent, "Mail Sending..."));
ActErrorReport.this.finish();
} else if (v == btnCancel) {
ActErrorReport.this.finish();
}
}
}
public void finish() {
super.finish();
if ("error.log".equals(by)) {
// do nothing
} else if ("uehandler".equals(by)) {
// 1.
// android.os.Process.killProcess(android.os.Process.myPid());
// 2.
// ActivityManager am = (ActivityManager)
// getSystemService(ACTIVITY_SERVICE);
// am.restartPackage("lab.sodino.errorreport");
// 3.
// System.exit(0);
// 1.2.3. ,Google 。
softApplication.setNeed2Exit(true);
// ////////////////////////////////////////////////////
// // “HOME”
// Intent i = new Intent(Intent.ACTION_MAIN);
// // , newtask
// i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// i.addCategory(Intent.CATEGORY_HOME);
// startActivity(i);
// ////////////////////////////////////////////////////
}
}
}
lab.sodino.errorreport.UEHandler.java
package lab.sodino.uncaughtexception;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import android.content.Intent;
import android.util.Log;
/**
* @author Sodino E-mail:[email protected]
* @version Time:2011-6-9 11:50:43
*/
public class UEHandler implements Thread.UncaughtExceptionHandler {
private SoftApplication softApp;
private File fileErrorLog;
public UEHandler(SoftApplication app) {
softApp = app;
fileErrorLog = new File(SoftApplication.PATH_ERROR_LOG);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
// fetch Excpetion Info
String info = null;
ByteArrayOutputStream baos = null;
PrintStream printStream = null;
try {
baos = new ByteArrayOutputStream();
printStream = new PrintStream(baos);
ex.printStackTrace(printStream);
byte[] data = baos.toByteArray();
info = new String(data);
data = null;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (printStream != null) {
printStream.close();
}
if (baos != null) {
baos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
// print
long threadId = thread.getId();
Log.d("ANDROID_LAB", "Thread.getName()=" + thread.getName() + " id=" + threadId + " state=" + thread.getState());
Log.d("ANDROID_LAB", "Error[" + info + "]");
if (threadId != 1) {
// 。
Intent intent = new Intent(softApp, ActErrorReport.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("error", info);
intent.putExtra("by", "uehandler");
softApp.startActivity(intent);
} else {
// ,
Intent intent = new Intent(softApp, ActOccurError.class);
// <span style="background-color: rgb(255, 255, 255); "> NEW_TASK </span> UI ANR
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
softApp.startActivity(intent);
// write 2 /data/data/<app_package>/files/error.log
write2ErrorLog(fileErrorLog, info);
// kill App Progress
android.os.Process.killProcess(android.os.Process.myPid());
}
}
private void write2ErrorLog(File file, String content) {
FileOutputStream fos = null;
try {
if (file.exists()) {
//
file.delete();
} else {
file.getParentFile().mkdirs();
}
file.createNewFile();
fos = new FileOutputStream(file);
fos.write(content.getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Throws Exception By Main Thread"
android:id="@+id/btnThrowMain"
></Button>
<Button android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Throws Exception By Child Thread"
android:id="@+id/btnThrowChild"
></Button>
</LinearLayout>
/res/layout/report.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/errorHint"
android:id="@+id/txtErrorHint" />
<EditText android:layout_width="fill_parent"
android:layout_height="wrap_content" android:id="@+id/editErrorContent"
android:editable="false" android:layout_weight="1"></EditText>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content" android:background="#96cdcd"
android:gravity="center" android:orientation="horizontal">
<Button android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="Report"
android:id="@+id/btnREPORT" android:layout_weight="1"></Button>
<Button android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="Cancel"
android:id="@+id/btnCANCEL" android:layout_weight="1"></Button>
</LinearLayout>
</LinearLayout>
사용 할 string.xml 자원 은:A error has happened %1$s.Please click "REPORT" to send the error information to us by email, Thanks!!!
중요 한 것 은 AndroidManifest.xml 에서더 많은 안 드 로 이 드 관련 내용 에 관심 이 있 는 독자 들 은 본 사이트 의 주 제 를 볼 수 있다.,,,,,,,
본 고 에서 말 한 것 이 여러분 의 안 드 로 이 드 프로 그래 밍 에 도움 이 되 기 를 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.