2012-06-12 50 views
7

Dưới đây là một ứng dụng Android đơn giản tôi đã tạo ra để chứng minh vấn đề của tôi:onCreateOptionsMenu android gọi hai lần khi khôi phục trạng thái

public class OptionMenuTest extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.d("test", "create activity"); 
     setContentView(R.layout.options_layout); 
     if(getFragmentManager().findFragmentByTag("frag") == null) { 
      getFragmentManager().beginTransaction().add(R.id.option_fragment_container, new OptionMenuFragment(), "frag").commit(); 
     } 

    } 

    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
     Log.d("test", "saving Activity state"); 
     super.onSaveInstanceState(outState); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     Log.d("test", "create Activity options menu"); 
     menu.add("activity"); 
     return true; 
    } 
} 

Fragment:

public class OptionMenuFragment extends Fragment { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.d("test", "create fragment"); 
     setHasOptionsMenu(true); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     TextView tv = new TextView(getActivity()); 
     tv.setText("Hello world"); 
     Log.d("test", "create fragment view"); 
     return tv; 
    } 

    @Override 
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     menu.add("fragment"); 
     Log.d("test", "create fragment options menu"); 
    } 
} 

Layout chỉ là một LinearLayout để đổ đoạn vào :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/option_fragment_container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    > 
</LinearLayout> 

Rất đơn giản phải không? Khi tôi chạy nó tôi nhận được đầu ra sau như mong đợi:

06-12 15:42:51.415: D/test(957): create activity 
06-12 15:42:51.446: D/test(957): create fragment 
06-12 15:42:51.446: D/test(957): create fragment view 
06-12 15:42:51.446: D/test(957): create Activity options menu 
06-12 15:42:51.446: D/test(957): create fragment options menu 

Bây giờ khi tôi xoay điện thoại tôi nhận được một số hành vi kỳ lạ:

06-12 15:43:11.251: D/test(957): saving Activity state 
06-12 15:43:11.290: D/test(957): create fragment 
06-12 15:43:11.290: D/test(957): create activity 
06-12 15:43:11.306: D/test(957): create fragment view 
06-12 15:43:11.306: D/test(957): create Activity options menu 
06-12 15:43:11.306: D/test(957): create fragment options menu 
06-12 15:43:11.306: D/test(957): create Activity options menu 
06-12 15:43:11.306: D/test(957): create fragment options menu 

Tại sao hoạt động onCreateOptionMenu và mảnh onCreateOptionsMenu gọi hai lần? Nếu tôi loại bỏ các tùy chọn trình đơn từ đoạn tôi nhận được 1 cuộc gọi để hoạt động onCreateOptionsMenu như mong đợi:

06-12 15:50:03.610: D/test(1076): create fragment 
06-12 15:50:03.610: D/test(1076): create fragment view 
06-12 15:50:03.813: D/test(1076): create Activity options menu 
06-12 15:50:08.392: D/test(1076): saving Activity state // <-- rotate happens here 
06-12 15:50:08.446: D/test(1076): create fragment 
06-12 15:50:08.446: D/test(1076): create activity 
06-12 15:50:08.462: D/test(1076): create fragment view 
06-12 15:50:08.470: D/test(1076): create Activity options menu 

Tôi không hiểu điều này và không ai khác dường như đã gặp phải vấn đề này. Vấn đề thực sự là SearchView của tôi không thể phục hồi trạng thái của nó trên thay đổi cấu hình (xoay điện thoại) vì onCreateOptionMenu đang được gọi hai lần. Lần đầu tiên có vẻ như nó có trạng thái nhưng lần thứ hai nó bị xóa và thiết lập lại. Tôi không thể tìm ra những gì tôi đang làm sai.

Xin cảm ơn trước.

+0

Tôi nghĩ rằng bức ảnh đẹp nhất của bạn sẽ được để có được một tổ chức của các mã nguồn và bước qua nó với các trình gỡ lỗi. Rất có thể là một lỗi trong Android. –

+0

Tôi chưa thực hiện bất kỳ tiến bộ nào về vấn đề này. Tôi đã bước qua mã nhưng không đủ quen thuộc với vòng đời của mảnh/hoạt động đằng sau hậu trường để biết điều gì đang xảy ra hoặc vấn đề có thể là gì. Tôi đã có một workaround ngay bây giờ đó là khá "hacky" nhưng tôi đang di chuyển trên. Nếu có ai đưa ra câu trả lời cho tôi biết. Cảm ơn! – Dave

+0

Tôi có cùng một vấn đề. 'onCreateOptionMenu' và' onPrepareOptionsMenu' được gọi hai lần và lần thứ hai chúng đặt lại trạng thái menu. Đã không tìm thấy một giải pháp nào được nêu ra: ( –

Trả lời

5

Tôi nghĩ rằng tôi đã tìm thấy câu trả lời cho vấn đề này.

Hãy xem một này:

https://stackoverflow.com/a/7225296/48468

vấn đề này dường như có liên quan đến thực tế rằng Android không phá hủy các mảnh vỡ khi hoạt động bị phá hủy (khi xoay thiết bị).

Về cơ bản tôi đã thêm:

setRetainInstance(true); 

để xây dựng đoạn tôi và các vấn đề đi giải quyết.

Hy vọng điều đó sẽ hữu ích!

+3

Có! Cảm ơn bạn rất nhiều. Điều này đã giải quyết được vấn đề của tôi Điều thú vị là, hoạt động này cũng có vấn đề này nếu một đoạn tham gia vào menu tùy chọn và không gọi setRetainInstance (đúng) , ngay cả khi SearchView được thêm vào bởi hoạt động này.Nếu bạn xóa setHasOptionsMenu khỏi đoạn, hoạt động SearchView hoạt động bình thường.Tôi nghĩ rằng vì đoạn mới được thêm vào làm cho các hoạt động onCreateOptionsMenu được gọi lại. – Dave

2

@Gerardo Contijoch Câu trả lời là sai lạc, ngoại trừ một thực tế:

Trong ví dụ của bạn cả ActivityFragment bị phá hủy sau khi luân chuyển và tạo ra một lần nữa. Đó là lý do tại sao onCreateOptionsMenu() được gọi hai lần. Đây là hành vi đúng và mong đợi.

Bằng cách setRetainInstance(true) bạn yêu cầu Android không hủy phân đoạn. Điều này có thể hữu ích trong trường hợp đoạn giao diện người dùng không giữ bối cảnh Hoạt động (hữu ích cho việc phối hợp AsyncTask và một số công cụ giống như dịch vụ khác).

Trong các trường hợp khác, đoạn mã này có khả năng dẫn đến rò rỉ bộ nhớ mà bạn cần tránh.

0

Tôi vừa xóa đơn trước khi lạm phát và các công trình

@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     menu.clear(); 
     inflater.inflate(R.menu.call_menu, menu); 
     super.onCreateOptionsMenu(menu, inflater); 

} 
Các vấn đề liên quan