2012-03-06 36 views
9

Trước hết, tôi mới phát triển Android nên hãy kiên nhẫn với tôi.Hoạt động được tạo hai lần trên android

Tôi sẽ bắt đầu từ giao diện người dùng, tôi có một nút khi bạn nhấn vào nó, bắt đầu một hoạt động để có kết quả.

public class GUIActivity extends Activity 

    @Override 
    public void onClick(....){ 
     Intent intent = new Intent(getApplicationContext(), GetImageActivity.class); 
     intent.putExtra("action", FROM_CAMERA); 
     startActivityForResult(intent, GET_IMAGE); 
    } 

    @Override 
    onActivityResult(int requestCode, int resultCode, Intent data){ 
     Log(TAG, "onActivityResult"); 
     //handle result 
    } 

} 

Lớp GetImageActivity là một wrapper cho hai hoạt động khác, một để chụp ảnh từ camera và khác để có được nó từ thư viện. Nó trả về và đối tượng Uri của ảnh đã chọn.

public class GetImageActivity extends Activity{ 
    private Uri mediaUri; 

    @Override 
    public void onCreate(Bundle savedInstanceState){ 
     super.onCreate(savedInstanceState); 
     Bundle extras = getIntent().getExtras(); 
     int action = extras.getInt("action"); 

     Log.d(TAG, "onCreate"); 

     switch(action){ 
      case FROM_CAMERA: 
       mediaUri = Uri.fromFile(new File(....)); 
       Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); 
       intent.putExtra(MediaStore.EXTRA_OUTPUT, mediaUri); 

       Log.d(TAG, "Calling camera activity" 
       startActivityForResult(intent, action); 
       break; 
      case FROM GALLERY: 
       //... 
     }    
    } 

    @Override 
    onActivityResult(int requestCode, int resultCode, Intent data){ 
     Log.d(TAG, "onActivityResult"); 

     switch(requestCode){ 
      case FROM_CAMERA: 
       if(resultCode == Activity.RESULT_OK){ 
        Intent data = new Intent(); 
        data.putExtra("uri", mediaUri); 
        setResult(Activity.RESULT_OK, data); 
        finish(); 
       }else{ 
        Log.e(TAG, "Camera activity failed!"); 
        setResult(Activity.RESULT_CANCELED); 
        finish(); 
       } 
       break; 

      case FROM_GALLERY: 
       //... 

     } 
    } 
} 

Đây là những gì được kỳ vọng sẽ xảy ra khi người dùng nhấp chuột vào nút:

  • Các hoạt động máy ảnh nên bắt đầu.
  • Khi người dùng chụp ảnh, nó sẽ gửi lại URI của nó tới lớp GUI.

Đôi khi (nó thường là một cơ hội 50%) nó hoạt động tại mong đợi, nhưng đôi khi đây là những gì sẽ xảy ra:

  • hoạt động Chiếc máy ảnh này bắt đầu.
  • Người dùng chụp ảnh.
  • Hoạt động của máy ảnh bắt đầu từ AGAIN.
  • Người dùng có thể chụp ảnh khác hoặc quay lại.
  • Cả hai trường hợp, URI quay trở lại lớp GUI không tồn tại.

Tôi đã thêm một vài dòng đăng nhập gỡ lỗi để theo dõi chuỗi sự kiện. Khi tôi nhận được hành vi xấu này là kết quả tôi nhận được:

  • GetImageActivity - onCreate
  • GetImageActivity - Gọi Máy ảnh Hoạt động

Chiếc máy ảnh này sẽ mở ra, và một khi tôi đã chụp ảnh nó nói :

  • GetImageActivity - onCreate (một lần nữa)
  • GetImageActivity - Gọi Máy ảnh Hoạt động
  • GetImageActivity - onActivityResult

Máy ảnh sẽ mở lần thứ hai. Người dùng phải mất một hình ảnh và:

  • GetImageActivity - onActivityResult
  • GUIActivity - onActivityResult

Vì vậy, câu hỏi của tôi là ... những gì có thể gây ra GetImageActivity được gọi là hai lần?

Trả lời

6

Sự cố là xử lý không đúng vòng đời Activity.

Cuộc gọi thứ hai tới onCreate là để xử lý kết quả.

Android có thể chọn hủy một số Activity đang chờ cuộc gọi đến onActivityResult; đặc biệt khi bộ nhớ trống đang ở mức thấp. Một số thiết bị xuất hiện tích cực hơn về việc phá hủy các Hoạt động trên ngăn xếp nhiệm vụ. Tôi có thể tái tạo một cách đáng tin cậy sự cố trên thiết bị Samsung được đặt ở chế độ gỡ lỗi được gọi là "chế độ nghiêm ngặt".

Bạn có thể xác minh xem đây có phải là vấn đề của bạn hay không bằng cách ghi lại cuộc gọi tới onCreate & onDestroy.

Trong trường hợp hoạt động bị hủy, khi kết quả hoạt động cần được xử lý, Android sẽ tạo lại Activity, chuyển qua savedInstanceState đến onCreate. Vì vậy, biện pháp khắc phục là kiểm tra giá trị savedInstanceState trong số GetImageActivity.onCreate của bạn. Nếu đó không phải là null thì không thực hiện bất kỳ cuộc gọi nào tới startActivityActivity của bạn đang được tạo lại để gọi onActivityResult.

Tùy chọn, nếu bạn cần giữ lại bất kỳ trạng thái nào sau đó ghi đè onSaveInstanceState(Bundle outState) và đặt dữ liệu bạn cần vào outState.

0

Khi bạn gọi startActivityForResult, thông báo cho Android biết rằng bạn muốn kết quả được gửi đến số Activity đang thực hiện cuộc gọi đó.Điều này giải thích những gì bạn thấy khi bạn đăng nhập GetImageActivity - onCreate (again).

Kể từ khi bạn gọi startActivityForResult trong hoạt động đầu tiên của bạn, có nghĩa là, GUIActivity hơn bạn nên được gọi setResult trong GetImageActivity để vượt qua đúng lại kết quả.

Vì vậy, trong GetImageActivity.onActivityResult() ngay trước khi bạn gọi finish() bạn nên gọi setResult để khi bạn quay lại GUIActivity, nó có thể xử lý kết quả mong đợi.

+0

tôi sẽ chỉnh sửa mã để làm cho nó rõ ràng hơn . Khi nó nói '// xử lý kết quả' trên lớp' GetImageActivity', tôi thực sự gọi 'setResult()'. Điều cần lưu ý là hoạt động được tạo lại ngay cả trước khi phương thức 'onActivityResult()' được gọi lần đầu tiên. –

1

Thêm này để định nghĩa hoạt động của bạn trong AndroidManifest.xml:

android:launchMode = "singleInstance" 
1

Thêm này để định nghĩa hoạt động của bạn trong AndroidManifest.xml:

android:launchMode = "singleTask" 
Các vấn đề liên quan