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 에서노드 에 android:name=".softApplication"을 설정 하 는 것 입 니 다.
더 많은 안 드 로 이 드 관련 내용 에 관심 이 있 는 독자 들 은 본 사이트 의 주 제 를 볼 수 있다.,,,,,,,
본 고 에서 말 한 것 이 여러분 의 안 드 로 이 드 프로 그래 밍 에 도움 이 되 기 를 바 랍 니 다.

좋은 웹페이지 즐겨찾기