11

被正確地重新創建更新到最新的支持庫後,片段必須是一個公共靜態類,從實例狀態

compile 'com.android.support:appcompat-v7:24.2.0' 
compile 'com.android.support:design:24.2.0' 
compile 'com.android.support:percent:24.2.0' 
compile 'com.android.support:recyclerview-v7:24.2.0' 

,我發現了怪異的例外。

java.lang.IllegalStateException: Fragment null must be a public static class to be properly recreated from instance state. 
at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:435) 
at android.support.v4.app.BackStackRecord.add(BackStackRecord.java:414) 
at android.support.v4.app.DialogFragment.show(DialogFragment.java:154) 
at com.androidapp.base.BaseActivity.showDialogFragment(BaseActivity.java:78) 
at com.androidapp.MainActivity.showNewDialog(MainActivity.java:304) 
at com.androidapp.MainActivity$6.onClick(MainActivity.java:228) 

在我BaseActivity類,我創建一個擴展BaseActivty

public void showDialogFragment(DialogFragment newFragment) { 
     FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
     Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog"); 
     if (prev != null) { 
      ft.remove(prev); 
     } 
     ft.addToBackStack("dialog"); 
     newFragment.show(ft, "dialog"); 
    } 

回到MainActivty我可重複使用的片段可以在活動課中使用已經使用了這樣的片段,

public class MainActivity extends BaseActivity { 

    @SuppressLint("ValidFragment") 
     public void showNewDialog(int type, String title, String message) { 
      final DialogNew dialog = new DialogNew() { 
       @Override 
       public void success(boolean isLandscape) { 
        ....... 
       } 

       @Override 
       public void cancel() { 

       } 
      }; 
      dialog.setArgs(title, message); 
      super.showDialogFragment(dialog); 
     } 
} 

DialogNew類如下,

public abstract class DialogNew extends DialogFragment { 

    private View rootView; 

    private String title; 
    private String message; 

    public void setArgs(String title, String message) { 
     Bundle args = new Bundle(); 
     args.putString("title", title); 
     args.putString("message", message); 
     setArguments(args); 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setStyle(STYLE_NO_TITLE, 0); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 

     rootView = inflater.inflate(R.layout.fragment_new_dialog, container, false); 

     init(); 
     setListeners(); 

     return rootView; 
    } 

    public abstract void success(boolean isLandscape); 

    public abstract void cancel(); 
} 

PS:相同的代碼工作與舊的支持庫。

+0

爲什麼'DialogNew'抽象?你不能實例化一個抽象類。 – Vucko

+0

@Vucko很好。當你做這樣的事情時,你是對的,你不能*實例化一個抽象*,而是它將初始化一個匿名類來擴展這個抽象類。總之,這沒有問題。 – Enzokie

+0

在支持庫版本中面臨同樣的錯誤24.2.1 – Meet

回答

10

錯誤並不特別怪異。如果之前沒有收到此錯誤,很奇怪。

Android將銷燬和重新創建碎片作爲配置更改(例如,屏幕旋轉)的一部分,並在必要時作爲重建任務的一部分(例如,用戶切換到另一個應用程序,當您的應用程序處於後臺時終止,那麼用戶會嘗試返回到您的應用程序,全部在30分鐘左右)。 Android無法重新創建DialogNew的匿名子類。

因此,請擴展DialogNew,對你的業務邏輯的規則public Java類(或publicstatic嵌套類),更換的DialogNew匿名子類,您正在使用目前。

+0

感謝您的回覆!我同意你的邏輯。現在我的DialogNew已經擴展了DialogFragment,所以我不能在MainActivity中擴展它,因爲MainActivity本身擴展了Activity。我不知道如何,但相同的代碼與舊的支持回購正常工作。我只想保持對話框和活動類的分離。 –

0

編輯:你可能不想這樣做...查看評論。

代碼示例看起來類似於我對here提出的建議,我最近也發現我在那裏的解決方案不再有效。我已經有更新了我的答案Java7,但如果你有Java8解決辦法是超級簡單:

(我沒有測試過這還)

public class DialogNew extends DialogFragment { 
    private View rootView; 
    private String title; 
    private String message; 

    // Do nothing by default 
    private Consumer mSuccess = (boolean b) -> {}; 
    private Runnable mCancel =() -> {}; 

    public void setArgs(String title, String message) { 
     Bundle args = new Bundle(); 
     args.putString("title", title); 
     args.putString("message", message); 
     setArguments(args); 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setStyle(STYLE_NO_TITLE, 0); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     rootView = inflater.inflate(R.layout.fragment_new_dialog, container, false); 
     // use mSuccess.accept(boolean) when needed 
     init(); 
     setListeners(); 
     return rootView; 
    } 

    public void setSuccess(Consumer success) { 
     mSuccess = success; 
    } 

    public void setCancel(Runnable cancel) { 
     mCancel = cancel; 
    } 
} 

然後在主要活動:

public class MainActivity extends BaseActivity { 
     public void showNewDialog(int type, String title, String message) { 
      final DialogNew dialog = new DialogNew(); 
      dialog.setArgs(title, message); 
      dialog.setSuccess((boolean isLandscape) -> { 
       //.... 
      }); 
      super.showDialogFragment(dialog); 
     } 
} 
+1

這不會有幾個原因。首先,'mSuccess'和'mCancel'將無法在被分割的碎片中存活。如果你保留這個片段,你會遇到一個更糟糕的問題:當你調用dialog.setSuccess並將它傳遞給一個lambda表達式時,你實際上已經創建了一個MainActivity的內部類。當配置更改時重新創建活動時,您將遇到內存泄漏,並且回調將嘗試調用已銷燬的活動上的方法。 –

相關問題