Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/199.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 4.0、4.1(<;4.2)中无需使用支持库的嵌套片段的最佳实践_Android_Android Fragments_Android Support Library_Android Nested Fragment - Fatal编程技术网

Android 4.0、4.1(<;4.2)中无需使用支持库的嵌套片段的最佳实践

Android 4.0、4.1(<;4.2)中无需使用支持库的嵌套片段的最佳实践,android,android-fragments,android-support-library,android-nested-fragment,Android,Android Fragments,Android Support Library,Android Nested Fragment,我正在为4.0和4.1平板电脑编写一个应用程序,我不想使用支持库(如果不需要的话),但只想使用4.x api 因此,我的目标平台定义得非常好:>=4.0和限制 因此,无论您使用的是哪个版本的FragmentManager,xml都不可能将片段嵌套在另一个片段中 因此,您必须通过代码添加片段,这似乎是一个问题,但从长远来看,这会使您的布局更加灵活 那么不使用getchildfragmentmanager进行嵌套?childFragmentManager背后的本质是,它延迟加载,直到上一个片段事务完

我正在为4.0和4.1平板电脑编写一个应用程序,我不想使用支持库(如果不需要的话),但只想使用4.x api

因此,我的目标平台定义得非常好:>=4.0和限制 因此,无论您使用的是哪个版本的
FragmentManager
,xml都不可能将片段嵌套在另一个片段中

因此,您必须通过代码添加片段,这似乎是一个问题,但从长远来看,这会使您的布局更加灵活

那么不使用
getchildfragmentmanager
进行嵌套?
childFragmentManager
背后的本质是,它延迟加载,直到上一个片段事务完成。当然,它只在4.2或支持库中得到了自然支持

无ChildManager的嵌套-解决方案 解决方案,当然!我已经做了很长一段时间了,(自从
ViewPager
发布以来)

见下文;这是一个延迟加载的
片段
,因此可以在其中加载
片段

它非常简单,
处理程序
是一个非常方便的类,在当前片段事务完成提交后,处理程序实际上会等待一个空间在主线程上执行(因为片段会干扰它们在主线程上运行的UI)

<>我不认为这是“最佳实践”,但我有使用这个黑客的实时应用程序,而且我还没有任何问题。


我还使用此方法嵌入视图寻呼机-

由于NavigationDrawer、TabHost和ViewPager的组合,我不得不处理这个确切的问题,因为TabHost会使支持库的使用变得复杂。然后我还必须支持Jellybean4.1的MinAPI,所以在getChildFragmentManager中使用嵌套片段不是一个选项

所以我的问题可以提炼成。。。 TabHost (for top level) + ViewPager (for just one of the top level tabbed fragments) = need for Nested Fragments (which JellyBean 4.1 won't support) 这实际上允许我的伪“嵌套片段”作为独立视图运行,只要我手动管理相关的布局权重

以下是我的活动_main.xml:

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ringofblades.stackoverflow.app.MainActivity">

    <TabHost
        android:id="@android:id/tabhost"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <FrameLayout android:id="@android:id/tabcontent"
                android:background="@drawable/background_image"
                android:layout_width="match_parent"
                android:layout_weight="0.5"
                android:layout_height="0dp"/>
            <android.support.v4.view.ViewPager
                xmlns:tools="http://schemas.android.com/tools"
                android:id="@+id/pager"
                android:background="@drawable/background_image"
                android:layout_width="match_parent"
                android:layout_weight="0.5"
                android:layout_height="0dp"
                tools:context="com.ringofblades.stackoverflow.app.MainActivity">
                <FrameLayout
                    android:id="@+id/container"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </android.support.v4.view.ViewPager>
            <TabWidget android:id="@android:id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </TabHost>

    <fragment android:id="@+id/navigation_drawer"
        android:layout_width="@dimen/navigation_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:name="com.ringofblades.stackoverflow.app.NavigationDrawerFragment"
        tools:layout="@layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>


请注意,“@+id/pager”和“@+id/container”与“android:layout\u weight=“0.5”和“android:layout\u height=“0dp”是同级的。这是为了让我可以看到它在预览任何屏幕大小。无论如何,它们的权重将在运行时在代码中进行操作。

在API 17之前的版本中,最好的方法是根本不这样做。尝试实现此行为将导致问题。然而,这并不是说使用当前的API 14不能令人信服地伪造它。我所做的是:

1-查看片段之间的通信

2-将布局xml FrameLayout从现有片段移动到活动布局,并通过指定高度0将其隐藏:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent">
<FrameLayout android:id="@+id/content"
          android:layout_width="300dp"
          android:layout_height="match_parent" />


<FrameLayout android:id="@+id/lstResults"
             android:layout_width="300dp"
             android:layout_height="0dp"
             android:layout_below="@+id/content"
             tools:layout="@layout/treeview_list_content"/>


<FrameLayout android:id="@+id/anomalies_fragment"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
        android:layout_toRightOf="@+id/content" />
4-在父活动中实现接口

公共类YourActivity扩展活动实现yourParentFragment.OnListener {

}


5-享受,使用此方法,您可以获得与API 17之前环境中的getChildFragmentManager()函数相同的流体功能。正如您可能已经注意到的,子片段不再是父片段的子片段,而是活动的子片段,这确实是无法避免的。

基于@Chris.Jenkins answer,这是一个对我来说很有效的解决方案,用于在生命周期事件中移除片段(有抛出IllegalStateExceptions的倾向)。这使用处理程序方法和Activity.isFinishing()检查的组合(否则它将抛出“onSaveInstanceState之后无法执行此操作”的错误)

用法:

class MyFragment extends Fragment {
    @Override
    public void onDestroyView() {
        removeFragments(mFragment1, mFragment2, mFragment3);
        super.onDestroyView();
    }
}

尽管OP可能有特殊情况阻止他使用支持库,但大多数人都应该使用它。Android文档推荐使用它,它将使你的应用程序尽可能地面向最广泛的受众

在年,我做了一个示例,演示如何使用支持库中的嵌套片段


您有三个选项:1.仅针对4.2使用本机嵌套片段。2.针对4.x使用支持库中的嵌套片段。3.不要将嵌套片段用于任何其他平台目标场景。这应该可以回答您的问题。此外,您不能使用嵌入xml布局中的嵌套片段,所有这些片段都必须添加到代码中。有在没有支持库的情况下,几乎没有任何好的示例可以展示片段使用的最佳实践-支持片段框架复制了本机框架,因此任何示例都可以使用。@Luksprog感谢您的评论。我更喜欢您的解决方案2,框架在支持库中运行良好,但ActionBar中的选项卡可以不是-好吧,我需要使用ActionBarSherlock,但是选项卡不会集成在ActionBar中,而是只集成在ActionBar下面(4.x不需要).和ActionBar.TabListener仅支持来自android.app.Fragment的片段,而不支持来自支持库的片段。我不熟悉Galaxy选项卡上的Contacts应用程序,但请记住,您随时可能会遇到自定义的
ActionBar
(由三星内置)。请仔细查看ActionBar Sherlock,如果有空间,它在ActionBar中有选项卡。@Luksprog我相信您已经提供了唯一的答案,请您将其作为正确的答案。@Pork我提出这个问题的主要原因是:是否有任何解决嵌套片段而不必使用支持li的方法brary及其所有其他视图元素。这意味着,如果我切换到支持库,我将使用FragmentActivity而不是Fragment。但我确实想使用Fragment,我只想替换嵌套片段,但不是所有v4组件。例如,通过其他开源库等。
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ringofblades.stackoverflow.app.MainActivity">

    <TabHost
        android:id="@android:id/tabhost"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <FrameLayout android:id="@android:id/tabcontent"
                android:background="@drawable/background_image"
                android:layout_width="match_parent"
                android:layout_weight="0.5"
                android:layout_height="0dp"/>
            <android.support.v4.view.ViewPager
                xmlns:tools="http://schemas.android.com/tools"
                android:id="@+id/pager"
                android:background="@drawable/background_image"
                android:layout_width="match_parent"
                android:layout_weight="0.5"
                android:layout_height="0dp"
                tools:context="com.ringofblades.stackoverflow.app.MainActivity">
                <FrameLayout
                    android:id="@+id/container"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </android.support.v4.view.ViewPager>
            <TabWidget android:id="@android:id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </TabHost>

    <fragment android:id="@+id/navigation_drawer"
        android:layout_width="@dimen/navigation_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:name="com.ringofblades.stackoverflow.app.NavigationDrawerFragment"
        tools:layout="@layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent">
<FrameLayout android:id="@+id/content"
          android:layout_width="300dp"
          android:layout_height="match_parent" />


<FrameLayout android:id="@+id/lstResults"
             android:layout_width="300dp"
             android:layout_height="0dp"
             android:layout_below="@+id/content"
             tools:layout="@layout/treeview_list_content"/>


<FrameLayout android:id="@+id/anomalies_fragment"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
        android:layout_toRightOf="@+id/content" />
    OnListener mCallback;

// Container Activity must implement this interface
public interface OnListener 
{
    public void onDoSomethingToInitChildFrame(/*parameters*/);
    public void showResults();
    public void hideResults();
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    // This makes sure that the container activity has implemented
    // the callback interface. If not, it throws an exception
    try {
        mCallback = (OnFilterAppliedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement OnListener");
    }
}

@Override
public void onActivityCreated(Bundle savedInstanceState) 
{
    super.onActivityCreated(savedInstanceState);

    mCallback.showResults();
}

@Override
public void onPause()
{
    super.onPause();

    mCallback.hideResults();
}

public void onClickButton(View view)
{
    // do click action here

    mCallback.onDoSomethingToInitChildFrame(/*parameters*/);
}
public void onDoSomethingToInitChildFrame(/*parameters*/)
{
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment childFragment = getFragmentManager().findFragmentByTag("Results");
    if(childFragment == null)
    {
        childFragment = new yourChildFragment(/*parameters*/);
        ft.add(R.id.lstResults, childFragment, "Results");
    }
    else
    {
        ft.detach(childFragment);

        ((yourChildFragment)childFragment).ResetContent(/*parameters*/);

        ft.attach(childFragment);
    }
    ft.commit();

    showResultsPane();
}

public void showResults()
{
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment childFragment = getFragmentManager().findFragmentByTag("Results");
    if(childFragment != null)
        ft.attach(childFragment);
    ft.commit();

    showResultsPane();
}

public void showResultsPane()
{
    //resize the elements to show the results pane
    findViewById(R.id.content).getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
    findViewById(R.id.lstResults).getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
}

public void hideResults()
{
    //resize the elements to hide the results pane
    findViewById(R.id.content).getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
    findViewById(R.id.lstResults).getLayoutParams().height = 0;

    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment childFragment = getFragmentManager().findFragmentByTag("Results");
    if(childFragment != null)
        ft.detach(childFragment);
    ft.commit();
}
import android.app.Activity;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;

public abstract class BaseFragment extends Fragment {
    private final Handler handler = new Handler();

    /**
     * Removes the {@link Fragment} using {@link #getFragmentManager()}, wrapped in a {@link Handler} to
     * compensate for illegal states.
     *
     * @param fragment The {@link Fragment} to schedule for removal.
     */
    protected void removeFragment(@Nullable final Fragment fragment) {
        if (fragment == null) return;

        final Activity activity = getActivity();
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (activity != null && !activity.isFinishing()) {
                    getFragmentManager().beginTransaction()
                            .remove(fragment)
                            .commitAllowingStateLoss();
                }
            }
        });
    }

    /**
     * Removes each {@link Fragment} using {@link #getFragmentManager()}, wrapped in a {@link Handler} to
     * compensate for illegal states.
     *
     * @param fragments The {@link Fragment}s to schedule for removal.
     */
    protected void removeFragments(final Fragment... fragments) {
        final FragmentManager fragmentManager = getFragmentManager();
        final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        for (Fragment fragment : fragments) {
            if (fragment != null) {
                fragmentTransaction.remove(fragment);
            }
        }

        final Activity activity = getActivity();
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (activity != null && !activity.isFinishing()) {
                    fragmentTransaction.commitAllowingStateLoss();
                }
            }
        });
    }
}
class MyFragment extends Fragment {
    @Override
    public void onDestroyView() {
        removeFragments(mFragment1, mFragment2, mFragment3);
        super.onDestroyView();
    }
}