2013-03-16 10 views
12

Tôi đang cố gắng hiểu cách bảo toàn trạng thái xem phân đoạn khi phân đoạn được sử dụng trong các tab điều hướng. Trong nỗ lực của tôi, tôi đã gặp hai vấn đề mà tôi không thể tìm thấy bất kỳ giải pháp thích hợp nào.Tab điều hướng Android: Khôi phục trạng thái xem phân đoạn

Tôi có hai tab, Tab1 và Tab2. Bố cục của Tab1 được xác định bởi bố cục của FragmentA và Tab2 được định nghĩa bởi FragmentB. Tôi đã theo phương pháp đưa ra ở đây: Adding navigation tabs

Vấn đề đầu tiên: Mặc dù quan điểm của tôi có ID, các quốc gia của họ không được phục hồi hoàn toàn khi một đoạn được tái đính kèm (sau khi một công tắc xoay tab). Cụ thể: Một EditText với một ID thực sự lưu văn bản đã nhập của nó, nhưng nó không lưu trạng thái được kích hoạt của nó. Ngoài ra các nút của tôi không lưu nếu chúng được kích hoạt hoặc vô hiệu hóa mặc dù chúng có ID. Tôi đã tìm thấy hai cách giải quyết có thể cho vấn đề này:

  1. Sử dụng hide()/show() thay vì attach()/detach() khi chuyển tab.
  2. trong onPause() lưu trạng thái chế độ xem đoạn hiện tại trong một biến mẫu View của đoạn qua getView(). Trong onCreateView(Bundle savedInstanceState) hãy kiểm tra xem trường này có phải là không null hay không và nếu trường hợp đó trả về giá trị của trường này. Giải pháp này có vẻ như bị hack, và tôi đã được bảo rằng nó cũng có thể giới thiệu một rò rỉ bộ nhớ trong ứng dụng của tôi.

Vấn đề thứ hai: Hãy xem xét các tương tác người dùng sau: tài bắt đầu từ ngày tab1 và hiện một số thay đổi mà đặt tình trạng quan điểm của tab1 ở tiểu bang khác hơn trạng thái mặc định của nó (và chúng tôi muốn đoạn để tiết kiệm trạng thái xem này thông qua tabswitches và thiết bị nghiêng). Người dùng sau đó chuyển đến Tab2. Người dùng sau đó nghiêng cô/thiết bị của anh ấy (vẫn ở Tab2). Người dùng sau đó hoán đổi sang Tab1 (theo hướng màn hình mới). Bây giờ, vấn đề là: Khi người dùng ban đầu hoán đổi từ Tab1 sang Tab2, đoạn được tách ra và do đó chế độ xem của nó bị loại bỏ (mặc dù cá thể mảnh vẫn còn sống). Khi người dùng sau đó nghiêng thiết bị, hoạt động - và do đó cả FragmentA và FragmentB liên kết với nó - đều bị hủy. Vì FragmentA tại thời điểm này không còn có chế độ xem nữa (hãy nhớ: nó đã được tách ra), chúng tôi không thể lưu trạng thái của các phần tử xem của nó (ví dụ: các nút được bật/tắt) trong khi gọi tới FragmentA.onSaveInstanceState(Bundle savedInstanceState). Làm cách nào để bạn khôi phục trạng thái xem phân đoạn trong tình huống như thế này? Là giải pháp khả thi duy nhất để lưu các cờ trạng thái khác nhau của mỗi phần tử xem như SharedPreferences? Điều này có vẻ quá phức tạp cho một "công việc hàng ngày" như vậy.

Tôi đã ở trên SO và nhiều bài đăng trên blog khác nhau nhưng chưa tìm được giải pháp cho vấn đề cụ thể này.

Trả lời

7

Vấn đề 1:

Android không lưu quan điểm của bạn kích hoạt trạng thái mặc định. Có vẻ như chỉ những thứ bị ảnh hưởng trực tiếp bởi hành động của người dùng (không có mã bổ sung) được lưu. Đối với Chế độ xem thông thường, no information is saved và đối với một TextView, trong đó EditText là một phân lớp, entered text is saved (nếu freezesText được đặt).

Nếu bạn muốn lưu bất kỳ thứ gì khác, bạn sẽ phải tự làm. Here là một câu hỏi với một số câu trả lời cho thấy cách triển khai chế độ xem trạng thái chế độ xem tùy chỉnh. Bạn có thể gắn bó với gắn/tách nếu bạn làm theo cách tiếp cận đó.

Vấn đề 2:

Bạn đang ngay trong Fragment.onSaveInstanceState đó (Bundle) có thể được gọi sau khi xem của bạn đã bị phá hủy. Tuy nhiên, đây không phải là nơi bạn nên lưu trạng thái xem của mình. Android sẽ gọi View.onSaveInstanceState() ngay trước khi nó phá hủy chế độ xem của bạn khi tách một đoạn. Nó lưu lại trạng thái này và trả lại cho bạn khi bạn đính kèm đoạn đó một lần nữa. Đây là chính xác những gì sẽ xảy ra khi bạn lật giữa các tab thông thường mà không có phép quay. Fragment.onSaveInstanceState (Bundle) không được gọi khi tách. Ngay cả khi bạn xoay thiết bị, trạng thái xem được lưu dưới dạng kết quả của phần tách sẽ vẫn tồn tại. Nếu bạn triển khai View.onSaveInstanceState() như được chỉ dẫn ở trên, trạng thái xem của bạn sẽ được lưu và khôi phục đúng cách, ngay cả trong trường hợp Tab1-Tab2-rotate-Tab1.

Lưu ý phụ: example code trong tài liệu dường như có một số vấn đề khi bạn cố gắng xoay. Thời gian tồn tại của TabListener giống như của Activity - một cái mới được tạo ra mỗi khi bạn xoay. Điều này có nghĩa là nó cũng mất tham chiếu nội bộ của nó vào đoạn, mỗi khi bạn xoay. Các mảnh được thêm vào được tự động tái tạo và do đó không cần TabListener cố gắng tạo một cá thể mới và thêm nó, sau khi xoay. Thay vào đó, tham chiếu nội bộ, nó chỉ nên cố gắng tìm đoạn có thẻ thích hợp trong trình quản lý phân đoạn. Sau khi xoay nó sẽ vẫn tồn tại.

Vấn đề khác là với tab đã chọn không được lưu, nhưng điều này được ghi chú ở cuối ví dụ. Bạn có thể lưu nó trong Activity.onSaveInstanceState (Bundle).

+0

Rất cám ơn - lời giải thích tốt. Tuy nhiên, mọi thứ vẫn chưa hoàn toàn rõ ràng với tôi. Tôi đã vượt qua câu trả lời mà bạn đang đề cập, nhưng tôi không hiểu cách sử dụng nó. Những gì được coi là một "CustomView"? Trạng thái xem đoạn của tôi bao gồm chỉ được xây dựng trong Chế độ xem (như EditTexts, Nút v.v.). Do đó tôi đã không mở rộng bất kỳ lớp Xem nào - tôi vừa xây dựng khung nhìn phân mảnh trong tệp bố cục xml. Làm thế nào tôi có thể kết nối mã mẫu được cung cấp trong câu trả lời cho bố cục của tôi không sử dụng bất kỳ chế độ xem do người dùng xác định nào (giả sử một CustomView là cho android điều khiển do người dùng định nghĩa là ASP .NET)? –

+1

@jvmk Để sử dụng View.onSaveInstanceState(), bạn sẽ cần phải phân lớp một View và ghi đè lên phương thức đó. XML bố cục của bạn sau đó cần tham chiếu đến các chế độ xem mới này, thay vì EditText/Button. – antonyt

+2

Woah, thật điên rồ. Tôi nghĩ khôi phục trạng thái xem được xây dựng trong Chế độ xem sẽ là một nhiệm vụ tái xuất hiện thường xuyên đủ để điều này được hỗ trợ như một tính năng tiêu chuẩn. Giả sử tôi nên viết một thư viện để sử dụng sau này. Cảm ơn vì đã giúp tôi ở đây. Điều này đã làm tôi khó chịu trong 2 tuần nay, heh. –

0
private ViewPager viewPager; 
viewPager = (ViewPager) findViewById(R.id.pager); 
mAdapter = new TabsPagerAdapter(getSupportFragmentManager()); 
viewPager.setAdapter(mAdapter); 
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { 

     @Override 
     public void onPageSelected(int position) { 
      // on changing the page 
      // make respected tab selected 
      actionBar.setSelectedNavigationItem(position); 
     } 

     @Override 
     public void onPageScrolled(int arg0, float arg1, int arg2) { 
     } 

     @Override 
     public void onPageScrollStateChanged(int arg0) { 
     } 
    }); 
} 

@Override 
public void onTabReselected(Tab tab, FragmentTransaction ft) { 
} 

@Override 
public void onTabSelected(Tab tab, FragmentTransaction ft) { 
    // on tab selected 
    // show respected fragment view 
    viewPager.setCurrentItem(tab.getPosition()); 
} 

@Override 
public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
} 
+1

Vui lòng xem xét bao gồm một số thông tin về câu trả lời của bạn, thay vì chỉ cần đăng mã. Chúng tôi cố gắng cung cấp không chỉ các bản sửa lỗi mà còn giúp mọi người tìm hiểu. Bạn nên giải thích những gì sai trong mã ban đầu, những gì bạn đã làm khác đi, và tại sao (các) thay đổi của bạn hoạt động. –