簡體   English   中英

在片段中的ConfigurationChange之后,onClickListener無法正常工作

[英]onClickListener not working (properly) after ConfigurationChange in fragments

介紹

嗯,這是一個艱難的 至少, 想是這樣......要清理:

在搜索互聯網(使用谷歌)后,我沒有找到任何問題的答案。

我發現的一切都是關於人們為他們的View錯誤設置onClickListener的。 我想在我的情況下這是同樣的問題,但沒有其他問題與我的相符。

似乎是同樣的問題......它沒有答案。

建立

我在AppCompatActivity設置了三個Fragment和一個ViewPager

viewPager = (ViewPager) findViewById(R.id.main_view_pager);
viewPager.setAdapter(new SectionsPagerAdapter(getSupportFragmentManager()));

SectionsPagerAdapter處理。

public class SectionsPagerAdapter extends FragmentPagerAdapter {

    SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return MainTextHolder.newInstance(tabIndicatorOnClick);
            case 1:
                return PostWriter.newInstance(tabIndicatorOnClick);
            case 2:
                return TopPage.newInstance(tabIndicatorOnClick);
            default:
                return Error.newInstance();
        }
    }

    @Override
    public int getCount() {
        return 3;
    }

    // ... more methods
}

在每個Fragment我都有一些內容和一個自定義的TabIndicator

(以下xml文件是我的View for the indicator)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <View
        android:id="@+id/fragment_divider_one"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:tag="one" />

    <View
        android:id="@+id/fragment_divider_two"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:tag="two" />

    <View
        android:id="@+id/fragment_divider_three"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:tag="three" />

</LinearLayout>

然后我在FragmentonCreateView(LayoutInflater inflater, ViewGroup Bundle savedInstanceState)方法中為每個View (分隔OnClickListener設置一個OnClickListener OnClickListener已經在我的Activity中准備好了,我還實例化了我的ViewPager以便我可以更改當前的ItemFragment / tab)。

private final View.OnClickListener tabIndicatorOnClick = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (view.getTag().toString().equals("one"))
            viewPager.setCurrentItem(0, true); // second argument for smooth transition
        else if (view.getTag().toString().equals("two"))
            viewPager.setCurrentItem(1, true);
        else if (view.getTag().toString().equals("three"))
            viewPager.setCurrentItem(2, true);
    }
};

我通過將OnClickListener放入我的newInstance(View.OnClickListener tabIndicatorOnClick)方法將其傳遞給Fragment

這是其中一個片段。 對其他人來說是完全相同的!

public static MainTextHolder newInstance(View.OnClickListener tabIndicatorOnClick) {
    MainTextHolder fragment = new MainTextHolder();
    Bundle args = new Bundle();
    fragment.putIndicatorTabIndicatorOnClick(tabIndicatorOnClick);
    fragment.setArguments(args);
    fragment.setRetainInstance(true);
    return fragment;
}

我的putIndicatorTabIndicatorOnClick(View.OnClickListener tabIndicatorOnClick)方法是一個InterfaceVoid 它只是將OnClickListener應用於ClassFragment )。

@Override
public void putIndicatorTabIndicatorOnClick(View.OnClickListener tabIndicatorOnClick) {
    this.tabIndicatorOnClick = tabIndicatorOnClick;
}

它有用嗎

的確如此 它工作得很好......直到ConfigurationChange發生。 在我的情況下,我通過改變方向測試它。

問題

ConfigurationChange之后會發生一切正常的事情。 OnClickListener應用於所有 Fragment所有 View tabIndicatorOnClick OnClickListener是第二個和第三個Fragment中的空對象引用

因此,在PostWriter首頁上 ,竟然沒有一個真正的OnClickListenerView的對什么都原因。 但它變得更好:在MainTextHolder FragmenttabIndicatorOnClick不是null object reference ,但它不再更改ViewPagerItem 它運行代碼,但不會滾動Tab

當打開“不要保持活動”而不是設備的開發者選項並離開應用程序時,所有OnClickListener都是null object references 甚至是MainTextHolder那些。

摘要

ConfigurationChange之后, OnClickListener被傳遞到我的第一個Fragment ,但是它沒有正常工作,並且在剩下的Fragment它甚至沒有傳遞/ null object reference

可以通過銷毀Activity然后重新加載復制該問題。

到底...

......我不知道出了什么問題。 我希望我能正確地構建我的問題。

可能有意義

minSdkVersion14

targetSdkVersion25

我的ViewPager上已經有一個ViewPager 這沒有OnClickListener所以我添加了自己的“重疊”指標,它們具有所需的OnClick功能。 我也喜歡它的外觀,但如果你能為我的TabIndicator提供更好的解決方案,我也很樂意將它作為答案。

我遇到了將方法多次放入xml :onClick屬性的解決方案,但為此,我需要為每個Fragment創建相同的OnClickListener ,這不是很好的方式,它也沒有解決我的問題,但是繞過它。 - 我需要將ViewPager傳遞給我的Fragment ,然后從xml調用該方法,正如我所說,這只是另一種方式,而不是我喜歡的方式。 我也不知道它是否有效。 我很可能會測試它。

Fragment中的其他OnClickListener仍能正常工作。 所以正如我所說,問題在於OnClickListener本身不能正常工作/是一個null object reference

首先,為編寫問題的詳細描述做得很好。 StackOverflow上的許多提問者都可以從這個問題的能力中學習表達問題。

這個錯誤似乎來自於不考慮Fragment生命周期的變化。 在ViewPager中,Fragments將通過各種狀態,包括隱藏和顯示在臨時屏幕外時,如果它們在屏幕外並且系統釋放內存,則暫停和恢復,如果Android系統決定保存實例狀態,則最終創建和銷毀您的活動(例如來自配置更改)。 在后一種情況下,Android將嘗試從ViewPager中保存的實例狀態恢復Fragments的狀態。 由於您的Fragments無法保存View.OnClickedListener因此它們在參數中傳遞,它們在恢復時最終會返回一個null指針,這會導致您的錯誤。

要修復錯誤,我建議您不要將View.OnClickedListener作為參數傳遞給Fragments。 相反,通過Activity中的公共方法將OnClickListener暴露給OnClickListener ,讓Fragments在onResume()中自己獲取它。 這樣,您可以保證Fragments在處於恢復狀態時將具有對View.OnClickedListener的引用。 所以你的onResume()可能看起來像這樣:

@Override
public void onResume() {
    OnClickListener onClickListener = ((MyActivity) getActivity).getOnClickListener();
    putIndicatorTabIndicatorOnClick(onClickListener);

}

由於您已在onResume()設置它,因此應在onPause()中將其刪除:

@Override
public void onPause() {
    //set the onClickListener to null to free up the resource
}

使用像這樣的onResume()onPause()來從監聽器中釋放資源是開發人員指南中推薦的方法。

當然,您必須通過檢查onCreate(Bundle savedInstanceState)保存狀態並相應地恢復它來確保您的Activity也處理自己的生命周期。

請注意,可以通過多種方式觸發保存實例狀態和恢復:

  1. 配置狀態更改(例如旋轉手機並使活動以橫向而非縱向顯示
  2. 設備內存不足(例如,如果最近的應用程序中有大量活動)
  3. 啟用開發人員選項/不要保留活動並使用主頁將您的應用程序放在最近的應用程序中,然后導航回您的應用程序。

您將能夠使用這些方法之一來確定您是否正確處理了活動和碎片的生命周期。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM