แนวทางปฏิบัติที่ดีที่สุดสำหรับชิ้นส่วนที่ซ้อนกันใน Android 4.0, 4.1 (<4.2) โดยไม่ต้องใช้ไลบรารีการสนับสนุน


115

ฉันกำลังเขียนแอปสำหรับแท็บเล็ต 4.0 และ 4.1 ซึ่งฉันไม่ต้องการใช้ไลบรารีสนับสนุน (หากไม่จำเป็น) แต่ใช้เฉพาะ 4.x api เท่านั้น

ดังนั้นแพลตฟอร์มเป้าหมายของฉันจึงถูกกำหนดไว้อย่างดีเช่น:> = 4.0 และ <= 4.1

แอปมีเค้าโครงหลายบานหน้าต่าง (สองส่วนเล็ก ๆ ทางซ้ายหนึ่งชิ้นส่วนเนื้อหาทางด้านขวา) และแถบการดำเนินการที่มีแท็บ

คล้ายกับสิ่งนี้:

ใส่คำอธิบายภาพที่นี่

การคลิกแท็บบนแถบการดำเนินการจะเปลี่ยนแฟรกเมนต์ 'ด้านนอก' จากนั้นแฟรกเมนต์ด้านในจะเป็นแฟรกเมนต์ที่มีแฟรกเมนต์ที่ซ้อนกันสองชิ้น (1. แฟรกเมนต์รายการเล็กทางซ้าย 2. แฟรกเมนต์เนื้อหากว้าง)

ตอนนี้ฉันสงสัยว่าแนวทางปฏิบัติที่ดีที่สุดในการเปลี่ยนชิ้นส่วนและชิ้นส่วนที่ซ้อนกันโดยเฉพาะอย่างยิ่งคืออะไร ViewPager เป็นส่วนหนึ่งของไลบรารีการสนับสนุนไม่มีทางเลือก 4.x ดั้งเดิมสำหรับคลาสนี้ ดูเหมือนว่า 'เลิกใช้แล้ว' ในความหมายของฉัน - http://developer.android.com/reference/android/support/v4/view/ViewPager.html

จากนั้นฉันอ่านบันทึกประจำรุ่นสำหรับ Android 4.2 เกี่ยวกับChildFragmentManagerซึ่งน่าจะเหมาะสม แต่ฉันกำหนดเป้าหมายเป็น 4.0 และ 4.1 ดังนั้นจึงไม่สามารถใช้ได้เช่นกัน

ChildFragmentManager มีเฉพาะใน 4.2

น่าเสียดายที่แทบจะไม่มีตัวอย่างที่ดีที่แสดงแนวทางปฏิบัติที่ดีที่สุดสำหรับการใช้งานชิ้นส่วนโดยไม่มีไลบรารีการสนับสนุนแม้แต่ในคู่มือสำหรับนักพัฒนา Android ทั้งหมด และโดยเฉพาะอย่างยิ่งไม่มีอะไรเกี่ยวกับชิ้นส่วนที่ซ้อนกัน

ดังนั้นฉันจึงสงสัยว่า: เป็นไปไม่ได้ที่จะเขียน 4.1 แอพที่มีส่วนที่ซ้อนกันโดยไม่ใช้ไลบรารีการสนับสนุนและทุกสิ่งที่มาพร้อมกับมัน? (ต้องใช้ FragmentActivity แทน Fragment ฯลฯ ?) หรือแนวทางปฏิบัติที่ดีที่สุดคืออะไร?


ปัญหาที่ฉันกำลังมีในการพัฒนาคือคำแถลงนี้:

ขณะนี้ไลบรารีการสนับสนุน Android รองรับส่วนที่ซ้อนกันแล้วดังนั้นคุณสามารถใช้การออกแบบชิ้นส่วนที่ซ้อนกันบน Android 1.6 ขึ้นไป

หมายเหตุ: คุณไม่สามารถขยายเค้าโครงเป็นส่วนย่อยได้เมื่อเค้าโครงนั้นมีไฟล์<fragment>. ส่วนที่ซ้อนกันจะได้รับการสนับสนุนเมื่อเพิ่มลงในส่วนแบบไดนามิกเท่านั้น

เนื่องจากฉันใส่กำหนดส่วนที่ซ้อนกันใน XML ซึ่งทำให้เกิดข้อผิดพลาดเช่น:

Caused by: java.lang.IllegalArgumentException: Binary XML file line #15: Duplicate id 0x7f090009, tag frgCustomerList, or parent id 0x7f090008 with another fragment for de.xyz.is.android.fragment.CustomerListFragment_

ในขณะนี้ฉันสรุปด้วยตัวเอง: แม้ใน 4.1 เมื่อฉันไม่ต้องการกำหนดเป้าหมายแพลตฟอร์ม 2.x ชิ้นส่วนที่ซ้อนกันดังที่แสดงในภาพหน้าจอจะเป็นไปไม่ได้หากไม่มีไลบรารีสนับสนุน

(นี่อาจเป็นรายการวิกิมากกว่าคำถาม แต่อาจมีคนอื่นเคยจัดการมาก่อน)

ปรับปรุง:

คำตอบที่เป็นประโยชน์อยู่ที่: Fragment Inside Fragment


22
คุณมีสามทางเลือก: 1. กำหนดเป้าหมายเฉพาะ 4.2 ด้วยส่วนย่อยที่ซ้อนกันดั้งเดิม 2. กำหนดเป้าหมาย 4.x ด้วยแฟรกเมนต์ที่ซ้อนกันจากไลบรารีการสนับสนุน 3. อย่าใช้แฟรกเมนต์ที่ซ้อนกันสำหรับสถานการณ์เป้าหมายแพลตฟอร์มอื่น ๆ สิ่งนี้ควรตอบคำถามของคุณนอกจากนี้คุณไม่สามารถใช้ส่วนที่ซ้อนกันที่ฝังอยู่ในเค้าโครง xml ได้ต้องเพิ่มทั้งหมดในโค้ด แทบจะไม่มีตัวอย่างที่ดีที่แสดงแนวทางปฏิบัติที่ดีที่สุดสำหรับการใช้งานแฟรกเมนต์ที่ไม่มีไลบรารีการสนับสนุน - เฟรมเวิร์กแฟรกเมนต์การสนับสนุนจะจำลองแบบเนทีฟดังนั้นตัวอย่างใด ๆ ควรทำงานในลักษณะใดก็ได้
Luksprog

@Luksprog ขอบคุณสำหรับความคิดเห็นของคุณ ฉันชอบโซลูชัน 2 ของคุณและแฟรกเมนต์ทำงานได้ดีในไลบรารีการสนับสนุน แต่แท็บใน ActionBar ทำไม่ได้ - afaik ฉันต้องใช้ ActionBarSherlock แต่แท็บจะไม่รวมอยู่ใน ActionBar แต่จะอยู่ด้านล่างเท่านั้น (ซึ่งไม่ใช่ ' t จำเป็นสำหรับ 4.x) และ ActionBar.TabListener รองรับเฉพาะ Fragments จาก android.app.Fragment ไม่ใช่จากไลบรารีสนับสนุน
Mathias Conradt

2
ฉันไม่คุ้นเคยกับแอปผู้ติดต่อบนแท็บ Galaxy แต่โปรดทราบว่าคุณอาจต้องเผชิญกับการใช้งานActionBar(ที่ Samsung สร้างขึ้นเอง) ดู ActionBarSherlock ให้ละเอียดยิ่งขึ้นมีแท็บใน ActionBar หากมีที่ว่าง
Luksprog

4
@Luksprog ฉันเชื่อว่าคุณได้ให้คำตอบเดียวที่จะให้แล้วคุณจะกรุณาใส่เป็นคำตอบที่เหมาะสม
Warpzit

1
@Pork เหตุผลหลักของฉันสำหรับคำถามคือ: มีวิธีแก้ปัญหาสำหรับส่วนที่ซ้อนกันโดยไม่ต้องใช้ไลบรารีสนับสนุนหรือไม่และทั้งหมดเป็นองค์ประกอบมุมมองอื่น ๆ หมายความว่าถ้าฉันเปลี่ยนไปใช้ไลบรารีสนับสนุนฉันจะใช้ FragmentActivity แทน Fragment แต่ฉันต้องการใช้ Fragment สิ่งที่ฉันต้องการคือการแทนที่Nested Fragmentsแต่ไม่ใช่ส่วนประกอบ v4 ทั้งหมด เช่นผ่านไลบรารีโอเพ่นซอร์สอื่น ๆ เป็นต้น ตัวอย่างเช่นภาพหน้าจอด้านบนทำงานบน 4.0 และฉันสงสัยว่าพวกเขากำลังใช้ ABS, SupportLib หรือสิ่งอื่นใด
Mathias Conradt

คำตอบ:


60

ข้อ จำกัด

ดังนั้นการซ้อนเศษภายในส่วนอื่นจึงเป็นไปไม่ได้ด้วย xml ไม่ว่าจะเป็นเวอร์ชันใดก็ตาม FragmentManagerคุณจะใช้ใดก็ตาม

ดังนั้นคุณต้องเพิ่มชิ้นส่วนผ่านโค้ดซึ่งอาจดูเหมือนเป็นปัญหา แต่ในระยะยาวจะทำให้เค้าโครงของคุณยืดหยุ่นได้มาก

ดังนั้นการทำรังโดยไม่ใช้getChildFragmentManger? สาระสำคัญที่อยู่เบื้องหลังchildFragmentManagerคือการเลื่อนการโหลดจนกว่าธุรกรรมส่วนย่อยก่อนหน้านี้จะเสร็จสิ้น และแน่นอนว่ามันได้รับการสนับสนุนตามธรรมชาติใน 4.2 หรือไลบรารีการสนับสนุนเท่านั้น

การทำรังโดยไม่มี ChildManager - โซลูชัน

เฉลยแน่! ฉันทำสิ่งนี้มานานแล้ว (ตั้งแต่ViewPagerประกาศ)

ดูด้านล่าง; นี่คือสิ่งFragmentที่เลื่อนการโหลดดังนั้นFragmentสามารถโหลดภายในได้

มันค่อนข้างง่ายHandlerเป็นคลาสที่มีประโยชน์จริงๆตัวจัดการรอให้มีช่องว่างในการดำเนินการบนเธรดหลักหลังจากที่ธุรกรรมส่วนย่อยในปัจจุบันเสร็จสิ้นการคอมมิทชัน (เนื่องจากแฟรกเมนต์รบกวน UI ที่รันบนเธรดหลัก)

// Remember this is an example, you will need to modify to work with your code
private final Handler handler = new Handler();
private Runnable runPager;

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

@Override
public void onActivityCreated(Bundle savedInstanceState)
{
    super.onActivityCreated(savedInstanceState);
    runPager = new Runnable() {

        @Override
        public void run()
        {
          getFragmentManager().beginTransaction().addFragment(R.id.frag_container, MyFragment.newInstance()).commit();
        }
    };
    handler.post(runPager);
}

/**
 * @see android.support.v4.app.Fragment#onPause()
 */
@Override
public void onPause()
{
    super.onPause();
    handler.removeCallbacks(runPager);
}

ฉันจะไม่คิดว่ามันเป็น 'แนวทางปฏิบัติที่ดีที่สุด' แต่ฉันมีแอพถ่ายทอดสดโดยใช้แฮ็คนี้และฉันยังไม่มีปัญหาใด ๆ กับมัน

ฉันยังใช้วิธีนี้ในการฝังเพจเจอร์มุมมอง - https://gist.github.com/chrisjenx/3405429


คุณจัดการกับชิ้นส่วนที่ซ้อนกันของเค้าโครงอย่างไร
pablisco

วิธีเดียวที่ฉันจะเห็นการทำงานนี้คือการใช้ CustomLayoutInflater เมื่อคุณเจอfragmentองค์ประกอบคุณจะแทนที่การใช้งานขั้นสูงและพยายามแยกวิเคราะห์ / ขยายด้วยตัวเอง แต่นั่นจะเป็นความพยายามอย่างมากนอกจากนี้ยังอยู่นอกขอบเขตของคำถาม StackOverflow
ริสเจนคินส์

สวัสดีทุกคนสามารถช่วยฉันในปัญหานี้ได้หรือไม่? ฉันติดจริงๆ .. stackoverflow.com/questions/32240138/…
Nicks

2

วิธีที่ดีที่สุดในการทำก่อน API 17 คืออย่าทำเลย การพยายามใช้พฤติกรรมนี้จะทำให้เกิดปัญหา อย่างไรก็ตามไม่ได้หมายความว่าจะไม่สามารถปลอมแปลงได้อย่างน่าเชื่อถือโดยใช้ API ปัจจุบัน 14 สิ่งที่ฉันทำมีดังต่อไปนี้:

1 - ดูการสื่อสารระหว่างส่วนต่างๆhttp://developer.android.com/training/basics/fragments/communicating.html

2 - ย้ายเลย์เอาต์ xml FrameLayout ของคุณจาก Fragment ที่คุณมีอยู่ไปยังเค้าโครงกิจกรรมและซ่อนมันโดยให้ความสูงเป็น 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" />

3 - ใช้อินเทอร์เฟซใน Fragment หลัก

    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*/);
}

4 - ใช้อินเทอร์เฟซในกิจกรรมหลัก

คลาสสาธารณะ YourActivity ขยายกิจกรรมใช้ yourParentFragment OnListener {

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();
}

}

5 - เพลิดเพลินด้วยวิธีนี้คุณจะได้รับฟังก์ชันการทำงานที่ลื่นไหลเช่นเดียวกับฟังก์ชัน getChildFragmentManager () ในสภาพแวดล้อมก่อน API 17 ดังที่คุณอาจสังเกตเห็นว่าส่วนย่อยของเด็กไม่ได้เป็นลูกของส่วนพ่อแม่อีกต่อไป แต่ตอนนี้เป็นลูกของกิจกรรมนี้ไม่สามารถหลีกเลี่ยงได้จริงๆ


1

ฉันต้องจัดการกับปัญหานี้อย่างแน่นอนเนื่องจากการรวมกันของ NavigationDrawer, TabHost และ ViewPager ซึ่งมีความยุ่งยากในการใช้ไลบรารีสนับสนุนเนื่องจาก TabHost จากนั้นฉันก็ต้องรองรับ min API ของ JellyBean 4.1 ดังนั้นการใช้ชิ้นส่วนที่ซ้อนกันกับ getChildFragmentManager จึงไม่ใช่ตัวเลือก

ดังนั้นปัญหาของฉันสามารถกลั่นถึง ...

TabHost (สำหรับระดับบนสุด)
+ ViewPager (สำหรับเศษแท็บระดับบนสุดเพียงชิ้นเดียว)
= ต้องใช้ Nested Fragments (ซึ่ง JellyBean 4.1 ไม่รองรับ)

วิธีแก้ปัญหาของฉันคือการสร้างภาพลวงตาของชิ้นส่วนที่ซ้อนกันโดยไม่ต้องสร้างชิ้นส่วนที่ซ้อนกัน ฉันทำสิ่งนี้โดยให้กิจกรรมหลักใช้ TabHost AND ViewPager เพื่อจัดการมุมมองพี่น้องสองคนที่มีการจัดการการมองเห็นโดยการสลับ layout_weight ระหว่าง 0 ถึง 1

//Hide the fragment used by TabHost by setting height and weight to 0
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 0);
mTabHostedView.setLayoutParams(lp);
//Show the fragment used by ViewPager by setting height to 0 but weight to 1
lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 1);
mPagedView.setLayoutParams(lp);

สิ่งนี้ช่วยให้ "ชิ้นส่วนซ้อน" ปลอมของฉันทำงานเป็นมุมมองอิสระได้อย่างมีประสิทธิภาพตราบใดที่ฉันจัดการน้ำหนักโครงร่างที่เกี่ยวข้องด้วยตนเอง

นี่คือ activity_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_weight =" 0.5 "'และ' android: layout_height =" 0dp "' เพื่อที่ฉันจะได้เห็นมันในตัวแสดงตัวอย่างสำหรับหน้าจอขนาดใดก็ได้ น้ำหนักของพวกเขาจะถูกจัดการด้วยโค้ดในระหว่างรันไทม์อยู่ดี


สวัสดีฉันสงสัยว่าทำไมคุณถึงเลือกใช้ TabHost แทน ActionBar กับ Tabs? ตัวฉันเองเปลี่ยนจาก TabHost เป็นเพียง ActionBar และรหัสของฉันก็สะอาดและกะทัดรัดมากขึ้น ...
IgorGanapolsky

เท่าที่ฉันจำได้ข้อเสียอย่างหนึ่งของการใช้แท็บใน ActionBar คือการตัดสินใจโดยอัตโนมัติที่จะแสดงเป็นเมนูแบบเลื่อนลงของสปินเนอร์ (ในกรณีที่เป็นหน้าจอขนาดเล็ก) และนั่นไม่ดีสำหรับฉัน แต่ฉันไม่แน่ใจ 100%
WindRider

@Igor ฉันอ่านที่ไหนสักแห่งที่นี่เกี่ยวกับการSOใช้ActionBarแท็บที่มี a Navigation Drawerไม่ดีเพราะมันจะวางแท็บไว้เหนือมุมมองของลิ้นชักของคุณโดยอัตโนมัติ ขออภัยฉันไม่มีลิงก์สำหรับสำรองข้อมูลนี้
Azurespot

1
@NoniA blog.xamarin.com/android-tips-hello-toolbar-goodbye-action-bar คุณติดตามการพัฒนาของ Android หรือไม่?
IgorGanapolsky

1
ว้าวขอบคุณสำหรับลิงค์ @Igor! ฉันจะตรวจสอบสิ่งนี้อย่างแน่นอน ฉันยังเป็นมือใหม่ดังนั้นมีอีกหลายล้านสิ่งที่ต้องเรียนรู้กับ Android แต่สิ่งนี้ดูเหมือนจะเป็นอัญมณี! ขอบคุณอีกครั้ง.
Azurespot

1

จากคำตอบของ @ Chris Jenkins นี่เป็นวิธีแก้ปัญหาที่ทำงานได้ดีสำหรับฉันสำหรับการลบส่วนย่อยในช่วงเหตุการณ์ของวงจรชีวิต (ซึ่งมีแนวโน้มที่จะโยน IllegalStateExceptions) สิ่งนี้ใช้การผสมผสานระหว่างวิธีการจัดการและการตรวจสอบ Activity.isFinishing () (มิฉะนั้นจะทำให้เกิดข้อผิดพลาด "ไม่สามารถดำเนินการนี้ได้หลังจาก onSaveInstanceState)

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();
    }
}

1

แม้ว่า OP อาจมีสถานการณ์พิเศษที่ทำให้เขาไม่สามารถใช้ Support Library ได้ แต่คนส่วนใหญ่ควรใช้มัน เอกสารประกอบ Android แนะนำและจะทำให้แอปของคุณพร้อมใช้งานสำหรับผู้ชมที่กว้างที่สุด

ในคำตอบที่สมบูรณ์ของฉันที่นี่ฉันได้ทำตัวอย่างที่สาธิตวิธีการใช้ส่วนที่ซ้อนกันกับไลบรารีสนับสนุน

ใส่คำอธิบายภาพที่นี่


ฉันเป็น OP เหตุผลที่ไม่ใช้ lib สนับสนุนเนื่องจากเป็นแอปภายในของ บริษัท ซึ่งฮาร์ดแวร์ที่ใช้นั้นถูกกำหนดไว้อย่างชัดเจนว่า> = 4.0 และ <= 4.1 ไม่จำเป็นต้องเข้าถึงผู้ชมจำนวนมากเป็นพนักงานภายในและไม่มีความตั้งใจที่จะใช้แอปนอก บริษัท เหตุผลเดียวของการสนับสนุน lib คือการใช้งานร่วมกันได้แบบย้อนกลับ - แต่มีใครคาดหวังว่าทุกสิ่งที่คุณสามารถทำได้กับไลบรารีการสนับสนุนคุณควรจะสามารถบรรลุ "โดยกำเนิด" ได้หากไม่มีมัน เหตุใด "เนทีฟ" เวอร์ชันที่สูงกว่าจึงมีคุณลักษณะน้อยกว่าไลบรารีการสนับสนุนซึ่งมีจุดประสงค์เพียงเพื่อให้เข้ากันได้ในระดับล่างเท่านั้น
Mathias Conradt

1
อย่างไรก็ตามคุณสามารถใช้ไลบรารีการสนับสนุนได้และฉันก็ทำได้เช่นกัน ไม่เข้าใจว่าเหตุใด Google จึงเสนอคุณลักษณะเฉพาะในไลบรารีการสนับสนุน แต่ไม่ใช่ภายนอกหรือทำไมพวกเขาถึงเรียกว่าไลบรารีการสนับสนุนและไม่ทำให้เป็นมาตรฐานโดยรวมหากเป็นแนวทางปฏิบัติที่ดีที่สุด นี่คือบทความดีๆเกี่ยวกับไลบรารีสนับสนุน: martiancraft.com/blog/2015/06/android-support-library
Mathias Conradt

@Mathias บทความที่ดี
Suragch
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.