2013-03-15 50 views
1

我有一個奇怪的問題。我在具有主機FragmentActivity的應用程序中使用Fragments,在該應用程序中,我實施了構建碎片並將其放入我的活動選項卡的內部class FragmentPagerAdapater片段的onCreateView()導致我的應用程序崩潰

在應用程序中,我需要將我的活動中的對象傳遞給碎片。我不太確定這樣做的正確方法是什麼,所以我即興創作,並在我的片段中使用靜態片段newInstance(Object obj)。這個方法只是調用默認的Fragment的構造函數,並設置一個實例變量來保存Fragment中的Object。

現在在片段的createView()方法中,我使用實例的Object信息來填充佈局。這在應用啓動時工作正常,但當我將屏幕方向從縱向更改爲橫向(或相反)時,應用崩潰。日誌在createView()的實例對象中指示NullPointerException。我覺得我錯過了生命週期中的某些東西,但我找不到答案。有沒有什麼特別的做法,我的碎片會保存它們的實例變量而不管它是什麼?

下面是一個代碼示例,以幫助您瞭解是什麼問題:

public class MyFragment extends Fragment { 

private Object obj; 

public static MyFragment newInstance(Object obj) { 
    MyFragment fragment = new MyFragment(); 
    fragment.setObject(obj); 
    return fragment; 
} 

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

    View rootView = inflater.inflate(R.layout.layout_fragment, container, false); 
    MyType res = ((Type) (obj)).getSomething(); // This line causes the crash because obj is null when I switch to another orientation 

    // I Do something with res to fill rootView 

    return rootView; 
} 

private void setObject(Object obj) { 
    this.obj = obj; 
} 
} 


// In the Activity I simply create the Fragment using 
MyFragment fragment = MyFragment.newInstance(myObjectToPass); 

感謝您的幫助!

+0

我們需要看到代碼! – 2013-03-15 16:14:15

+0

crash =>堆棧跟蹤。 – njzk2 2013-03-15 16:14:30

回答

2

當方向切換時(實際上每當Android決定重新創建Fragment時),現有的Fragment將被銷燬並重新創建。

但是,當Android重新創建Fragment時,它不會調用您的自定義newInstance()方法。它使用空的無參數構造函數。

這意味着你的Fragment不會有一個非空引用Object你想要的任何定製,導致NPE被拋出。

您需要找出一種方法來通過Object。如果Object是簡單的數據Object,請考慮通過setArguments()方法傳遞其字段或將其序列化。

MyFragment fragment = new MyFragment(); 
Bundle data = new Bundle(); 
data.putString ("key_string", "your string here"); 
fragment.setArguments (data); 

你也可以創建一個interface,查詢該對象的活動。例如:

public class MyFragment extends Fragment { 

    public interface ObjectProvider 
    { 
    public CustomObject getCustomObject(); 
    } 

    private ObjectProvider provider; 

    @Override 
    public void onAttach (Activity activity) 
    { 
    super.onAttach(activity); 
    try{ 
     provider = (ObjectProvider) activity;//get an instance of the ObjectProvider 
    } 
    catch (ClassCastException e) 
    { 
     e.printStackTrace(); 
     throw new RuntimeException ("This isn't an ObjectProvider."); 
    } 
    } 

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

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

    provider.getCustomObject().getSomething(); 

    return rootView; 
    } 
} 

那麼你的活動需要實現的接口:

public class MainActivity implements MyFragment.ObjectProvider{ 

@Override 
public CustomObject getCustomObject() 
{ 
    return new CustomObject(); 
} 
} 
+0

謝謝,它像一個魅力。 – francoisr 2013-03-16 13:51:11

+0

@francoisr歡迎您:-) – 2013-03-16 15:18:14

1

您也可以只使用setRetainInstance(真),如下所示:

public static MyFragment newInstance(Object obj) { 
    MyFragment fragment = new MyFragment(); 
    fragment.setObject(obj); 
    fragment.setRetainInstance(true); 
    return fragment; 
} 

這將堅持你的對象跨方向更改,只需確保該對象沒有對活動上下文的引用,否則將發生內存泄漏。