更换片段和方向改变

发布于 2024-10-30 01:43:53 字数 4838 浏览 4 评论 0原文

我正在开发一个针对 2.x 和 3.0 设备的 Android 应用程序,因此我使用兼容性 API。我正在Android 2.0上进行测试。

我正在尝试将显示的片段替换为另一个片段(带有搜索结果的搜索表单),并且当显示第二个(结果)片段时,我在方向更改时遇到崩溃。

基本上,我有一个活动,其中包括在布局 xml 中定义的片段,

    <fragment class="org.prevoz.android.search.SearchFormFragment"
              android:id = "@+id/search_form_fragment"
              android:layout_width = "fill_parent"
              android:layout_height = "fill_parent" />

第一个片段 (SearchFormFragment) 默认显示。当用户点击“搜索”按钮时,我将 SearchFormFragment 替换为 SearchResultsFragment,它运行一个 AsyncTask (这就是我想保留它的原因),但是

    // Show the search results fragment
SearchResultsFragment newSearch = new SearchResultsFragment(from, to, when);
newSearch.setRetainInstance(true);

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
transaction.replace(R.id.search_form_fragment, newSearch);      
transaction.addToBackStack(null);
transaction.commit();

,当显示 SearchFormFragment 并更改方向时,我的应用程序崩溃并显示

ERROR/AndroidRuntime(334): FATAL EXCEPTION: main
ERROR/AndroidRuntime(334): java.lang.RuntimeException: Unable to start activity ComponentInfo{org.prevoz.android/org.prevoz.android.search.MainActivity}: android.view.InflateException: Binary XML file line #13: Error inflating class fragment
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3815)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.access$2400(ActivityThread.java:125)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2037)
ERROR/AndroidRuntime(334):     at android.os.Handler.dispatchMessage(Handler.java:99)
ERROR/AndroidRuntime(334):     at android.os.Looper.loop(Looper.java:123)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.main(ActivityThread.java:4627)
ERROR/AndroidRuntime(334):     at java.lang.reflect.Method.invokeNative(Native Method)
ERROR/AndroidRuntime(334):     at java.lang.reflect.Method.invoke(Method.java:521)
ERROR/AndroidRuntime(334):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
ERROR/AndroidRuntime(334):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
ERROR/AndroidRuntime(334):     at dalvik.system.NativeStart.main(Native Method)
ERROR/AndroidRuntime(334): Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class fragment
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:582)
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
ERROR/AndroidRuntime(334):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:198)
ERROR/AndroidRuntime(334):     at android.app.Activity.setContentView(Activity.java:1647)
ERROR/AndroidRuntime(334):     at org.prevoz.android.search.MainActivity.onCreate(MainActivity.java:40)
ERROR/AndroidRuntime(334):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
ERROR/AndroidRuntime(334):     ... 12 more
ERROR/AndroidRuntime(334): Caused by: java.lang.IllegalStateException: Fragment org.prevoz.android.search.SearchFormFragment did not create a view.
ERROR/AndroidRuntime(334):     at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:281)
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:558)
ERROR/AndroidRuntime(334):     ... 21 more
WARN/ActivityManager(59):   Force finishing activity org.prevoz.android/.search.MainActivity

相关的 onCreateView 代码from SearchFormFragment 确实被调用,并且我返回一个有效视图:

@Override
public View onCreateView(LayoutInflater inflater, 
                         ViewGroup container,
                         Bundle savedInstanceState) 
{       
    View newView = inflater.inflate(R.layout.search_form_frag, container, false);
    return newView;
}

仅当显示 SearchResultsFragment 时才会发生崩溃,如果显示默认 SearchFormFragment,则更改可以正常工作。

那么如何通过方向变化保留第二个片段状态呢?关于 API 和状态更改的文档确实很缺乏。

I'm developing an Android application targeting 2.x and 3.0 devices and thus I'm using the compatibilty API. I'm testing on Android 2.0.

I'm trying to replace a displayed fragment with another one (search form with search results) and I'm experiencing a crash on orientation change when the second (results) fragment is displayed.

Basically, I have an activity, that includes a fragment defined in layout xml as

    <fragment class="org.prevoz.android.search.SearchFormFragment"
              android:id = "@+id/search_form_fragment"
              android:layout_width = "fill_parent"
              android:layout_height = "fill_parent" />

The first fragment (SearchFormFragment) is displayed as a default. When user taps a "search" button, I replace the SearchFormFragment with SearchResultsFragment, which runs an AsyncTask (that's why I want to retain it) with

    // Show the search results fragment
SearchResultsFragment newSearch = new SearchResultsFragment(from, to, when);
newSearch.setRetainInstance(true);

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
transaction.replace(R.id.search_form_fragment, newSearch);      
transaction.addToBackStack(null);
transaction.commit();

However, when the SearchFormFragment is displayed and orientation is changed, my application crashes with

ERROR/AndroidRuntime(334): FATAL EXCEPTION: main
ERROR/AndroidRuntime(334): java.lang.RuntimeException: Unable to start activity ComponentInfo{org.prevoz.android/org.prevoz.android.search.MainActivity}: android.view.InflateException: Binary XML file line #13: Error inflating class fragment
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3815)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.access$2400(ActivityThread.java:125)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2037)
ERROR/AndroidRuntime(334):     at android.os.Handler.dispatchMessage(Handler.java:99)
ERROR/AndroidRuntime(334):     at android.os.Looper.loop(Looper.java:123)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.main(ActivityThread.java:4627)
ERROR/AndroidRuntime(334):     at java.lang.reflect.Method.invokeNative(Native Method)
ERROR/AndroidRuntime(334):     at java.lang.reflect.Method.invoke(Method.java:521)
ERROR/AndroidRuntime(334):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
ERROR/AndroidRuntime(334):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
ERROR/AndroidRuntime(334):     at dalvik.system.NativeStart.main(Native Method)
ERROR/AndroidRuntime(334): Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class fragment
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:582)
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
ERROR/AndroidRuntime(334):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:198)
ERROR/AndroidRuntime(334):     at android.app.Activity.setContentView(Activity.java:1647)
ERROR/AndroidRuntime(334):     at org.prevoz.android.search.MainActivity.onCreate(MainActivity.java:40)
ERROR/AndroidRuntime(334):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
ERROR/AndroidRuntime(334):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
ERROR/AndroidRuntime(334):     ... 12 more
ERROR/AndroidRuntime(334): Caused by: java.lang.IllegalStateException: Fragment org.prevoz.android.search.SearchFormFragment did not create a view.
ERROR/AndroidRuntime(334):     at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:281)
ERROR/AndroidRuntime(334):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:558)
ERROR/AndroidRuntime(334):     ... 21 more
WARN/ActivityManager(59):   Force finishing activity org.prevoz.android/.search.MainActivity

The relevant onCreateView code from SearchFormFragment does get called and I return a valid view:

@Override
public View onCreateView(LayoutInflater inflater, 
                         ViewGroup container,
                         Bundle savedInstanceState) 
{       
    View newView = inflater.inflate(R.layout.search_form_frag, container, false);
    return newView;
}

The crash only happens if the SearchResultsFragment is shown, the change works fine if the default SearchFormFragment is displayed.

So how do I retain the second fragment state through the orientation change? The documentation on API and state changes is really lacking.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

鱼窥荷 2024-11-06 01:43:53

不要在 XML 中创建 SearchFormFragment。相反,您可以在 Activity.onCreate() 中填充一个空的 FrameLayout,而不将其添加到返回堆栈中。这样,Activity 将保留当前的 ​​Fragment,而不是尝试添加 XML 中指定的片段。

此外,使用 AsyncLoader 可能是更好的方法,请参阅 http://code.google.com/p/android/issues/detail?id=14944

Don't create the SearchFormFragment in XML. Instead have an empty FrameLayout which you populate in Activity.onCreate() without adding it to the back stack. This way the Activity will keep the current Fragment instead of trying to add the one specified in XML.

Also, using AsyncLoader may be a better approach, see http://code.google.com/p/android/issues/detail?id=14944

哥,最终变帅啦 2024-11-06 01:43:53

经过几个小时的努力,我终于明白了。
问题根本不在于设置或我们调用 Fragment 类的方式。这与屏幕上显示的错误消息有关。如果您在 Ftagment 类的 onCreateView() 中检查容器是否为空,您将收到“无法膨胀片段”消息,而不是容器为空消息。因此,不要在 onCreateView() 中检查空容器。因此,请确保您的 onCreateView() 看起来像这样:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return(inflater.inflate(R.layout.title_layout, container, false));
    }

而不是这样:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if(container == null){
            return null;                                
        }
        return(inflater.inflate(R.layout.title_layout, container, false));
    }

After struggling with this for many hours, I finally got it.
The problem is not in the setup or the way we call Fragment class at all. It has to do with a wrong message being displayed on the screen. If you have a check for a container being null in your onCreateView() in your Ftagment class, you will get that "unable to inflate fragment" message, instead of container is null message. So, do not check for null container in your onCreateView(). So make sure your onCreateView() looks like this:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return(inflater.inflate(R.layout.title_layout, container, false));
    }

and NOT like this:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if(container == null){
            return null;                                
        }
        return(inflater.inflate(R.layout.title_layout, container, false));
    }
枕头说它不想醒 2024-11-06 01:43:53

出于参考原因:我们能够通过向 XML 创建的片段添加 android:id 来解决非常类似的问题。

支持无崩溃旋转的这个非常重要的先决条件仅在文档中作为旁注提及。 :

注意:每个片段都需要一个系统可以识别的唯一标识符
如果活动重新启动(并且其中
您可以使用捕获片段来执行事务,例如
删除它)。

For reference reasons: We were able to solve a very similar problem by adding an android:id to our fragment created in XML.

This very important precondition for supporting crash-free rotation is only mentioned as a side-note in the documentation:

Note: Each fragment requires a unique identifier that the system can
use to restore the fragment if the activity is restarted (and which
you can use to capture the fragment to perform transactions, such as
remove it).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文