2016-05-08 14 views
11

Tôi có Hoạt động chính A sử dụng CursorLoader để truy vấn DB. Này tôi tạo ra trong hoạt động onCreate() phương pháp:Tại sao CursorLoader onLoaderReset() được gọi sau khi xoay thiết bị?

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    ... 
    getSupportLoaderManager().initLoader(LOADER_MEASUREMENTS, null, A.this); 
} 

Hoạt động A cũng thực hiện 3 callbacks cho CursorLoader:

public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) 
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) 
public void onLoaderReset(Loader<Cursor> loader) 

Khi tôi xoay điện thoại, tôi thấy phương pháp vòng đời đúng chạy:

A.onPause() 
A.onStop() 
A.onDestroy()   
A.onCreate()  <-- re-connect to existing loader, onCreateLoader() not called 
A.onLoadFinished() 
A.onStart() 
A.onResume() 

Sau đó, tôi mở một hoạt động phụ B và xoay thiết bị của tôi. Khi tôi kết thúc B và quay lại Hoạt động A, tôi thấy hoạt động sau:

B.onPause() 
     A.onLoaderReset()  <- why does this run? 
     A.onDestroy()   
     A.onCreate() 
     A.onCreateLoader()  <- now runs as loader is null 
     A.onStart() 
     ... 

Tại sao bộ nạp của tôi được đặt lại vì tôi đã kích hoạt Hoạt động B và xoay thiết bị? Chỉ cần thêm Activity B đó không liên quan gì đến DB hoặc CursorLoader.

+2

[Câu hỏi này] (http://stackoverflow.com/questions/15897547/loader-unable-to-retain-itself-during-certain-configuration-change?lq=1) và các câu hỏi được liên kết có liên quan. Có lẽ bạn có thể tìm thấy một cái gì đó có thể giúp đỡ. –

+0

Cảm ơn George - câu hỏi đó thảo luận chính xác cùng một vấn đề tôi đang gặp phải. Có vẻ như nó có thể là do Trình quản lý tải hỗ trợ. – MickeyR

+2

[link] này (https://code.google.com/p/android/issues/detail?id=183783) nói rằng điều này là/sẽ được sửa trong v24. – MickeyR

Trả lời

1

Dường như việc này có liên quan đến LoaderManager và không giữ trạng thái hoạt động.

LoaderManager được quản lý bởi android.app.FragmentHostCallbackvoid doLoaderStop(boolean retain) trong lớp này dường như tạo sự khác biệt. Tùy thuộc vào đối số, số này sẽ là retain() hoặc stop() bộ nạp của nó.

Khi thay đổi cấu hình trong hoạt động A (xoay màn hình) hoạt động bị hủy và được tạo lại ngay lập tức. Trong ActivityThread#handleRelaunchActivity() giá trị mChangingConfigurations của hoạt động được đặt thành true. Đây là quan trọng, bởi vì khi dừng hoạt động của bạn trên thay đổi cấu hình, điều này được gọi trong Activity:

final void performStop() { 
    mDoReportFullyDrawn = false; 
    mFragments.doLoaderStop(mChangingConfigurations /*retain*/); 
    // ... 
} 

Bạn có thể thử giảm dần sâu hơn vào những gì xảy ra — cài đặt Android của bạn nên có các nguồn và grep là tuyệt vời để làm — này nhưng tôi sẽ tóm tắt phần còn lại.

Tuyên bố miễn trừ: Tôi chưa xác minh kỹ lưỡng những điều sau đây, nhưng đây là những gì tôi hiểu đang diễn ra.

Như có thể thấy ở trên, khi hoạt động này được xem phù hợp cho relaunch nó sẽ giữ các bộ tải thay vì dừng họ. Khi bạn xoay hoạt động A, các bộ nạp sẽ được giữ lại. Khi bạn xoay hoạt động B, hoạt động B được tạo lại ngay lập tức, trong khi hoạt động A chỉ bị phá hủy. Trái ngược với trước, các bộ tải sẽ bị dừng lại.

Trình nạp bị dừng chỉ có thể bị hủy và tái tạo khi phù hợp với Trình quản lý tải, và đây là những gì đang xảy ra với máy của bạn.

Nếu bạn muốn tham gia một tốt nhìn chính mình, hãy kiểm tra:

  • app/LoaderManager hoặc v4/app/LoaderManager
  • app/FragmentHostCallback
  • ActivityActivityThread
1

Bạn có thể dễ dàng thiết lập một breakpoint bên A .onLoaderReset() và chạy ứng dụng trong chế độ gỡ lỗi để xem theo dõi ngăn xếp để gỡ rối bằng cách sử dụng somethin g như:

class A extends Activity implements LoaderManager.LoaderCallbacks 
{ 
    @Override 
    public void onLoaderReset(Loader loader) 
    { 
     try 
     { 
      // Constructs a new Exception that includes the current stack trace. 
      throw new Exception(); 
     } 
     catch (Exception e) 
     { 
      Log.d("TAG", Log.getStackTraceString(e)); 
     } 
    } 
} 
3

Tôi đã kiểm tra LoaderManagersource code bạn sẽ tìm thấy phương pháp này:

/** 
    * Stops and removes the loader with the given ID. If this loader 
    * had previously reported data to the client through 
    * {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, a call 
    * will be made to {@link LoaderCallbacks#onLoaderReset(Loader)}. 
    */ 
    public abstract void destroyLoader(int id); 

Có vẻ như bạn nạp bị phá hủy khi xoay màn hình (do thay đổi cấu hình). LoaderManager nội bộ gọi phương thức destroyLoader mà lần lượt gọi phương thức gọi lại onLoaderReset.

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