【问题标题】:Fragment in ActionBar Tab can't access activityActionBar 选项卡中的片段无法访问活动
【发布时间】:2014-03-04 04:23:15
【问题描述】:

我已按照 developer.android.com/guide/topics/ui/action.bar.html 上的指南在操作栏中实现选项卡。

在我的主要活动中,我添加了三个标签:

public class ToDoActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        actionBar.setDisplayShowTitleEnabled(false);

        Tab tab = actionBar.newTab().setText("Task List")
            .setTabListener(new TabListener<TaskListFragment>(
                    this, "task list", TaskListFragment.class));
        actionBar.addTab(tab);

        tab = actionBar.newTab().setText("Pie Chart")
            .setTabListener(new TabListener<TaskPieChartFragment>(
                    this, "pie chart", TaskPieChartFragment.class));
        actionBar.addTab(tab);

        tab = actionBar.newTab().setText("Task Map")
            .setTabListener(new TabListener<TaskMapFragment>(
                    this, "task map", TaskMapFragment.class));
        actionBar.addTab(tab);
    }
}

第一个选项卡的片段执行得很好。它可以找到视图并访问活动。单击导航中的第二个选项卡会显示片段(如预期的那样),但不会执行该片段的生命周期函数(onActivityCreated()、onStart()、onResume() 等)。此外,从该片段中对 getActivity() 的每次调用都会返回一个空对象。

public class TaskPieChartFragment extends Fragment {

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

    public void updatePieChart() {
        TextView textView = (TextView) getActivity().findViewById(R.id.some_text);
        textView.setText("something something");
    }
}

布局:

<?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="match_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/some_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

从 TabListener 中调用 updatePieChart() 函数:

public class TabListener<T extends Fragment> implements ActionBar.TabListener {

    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        if (mFragment == null) {
            mFragment = Fragment.instantiate(mActivity,  mClass.getName());
            ft.add(android.R.id.content, mFragment, mTag);
        } else {
            ft.attach(mFragment);
        }
        try {
            TaskPieChartFragment pieChartFragment = (TaskPieChartFragment) mFragment;
            pieChartFragment.updatePieChart();
        } catch (ClassCastException e) {
        // not the fragment we were looking for
        }
    }

}

每当我选择带有 TaskPieChartFragment 的选项卡时,我都会在 updatePieChart() 的第一行得到一个 NullPointerException。为什么第二个片段的行为与第一个片段完全不同,而我似乎无法获得对活动的引用?

PS

我还尝试传递保存在 TabListener 中的活动。那么 NullPointerException 不是源自 updatePieChart() 中的第一行,而是第二行,因此活动找不到视图。

【问题讨论】:

    标签: android android-fragments android-actionbar


    【解决方案1】:

    它崩溃的原因是FragmentTransaction 还没有完成。

    方法getActivity() 只返回片段回调onAttach()onDetach() 之间的活动,并且只有在事务ft 完成并且框架完成所有回调之后才会发生。

    您可能应该在onResume() 或其他一些片段生命周期回调期间更新您的饼图。

    编辑:

    重新阅读代码,此时您正在调用updatePieChart(),视图尚未创建。所以也有。

    作为一般规则,片段的视图应该在实际片段中更新。

    大概是这样的:

    公共类 TaskPieChartFragment 扩展片段 {

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_task_pie_chart, container, false);
    }
    
    public void onResume(){
        super.onResume();
        updatePieChart();
    }
    
    private void updatePieChart() {
        TextView textView = (TextView) getView().findViewById(R.id.some_text);
        textView.setText("something something");
    }
    

    }

    这样做的想法是片段应该是自包含的实体,而不是依赖于调用它们进行更新的活动。

    【讨论】:

      【解决方案2】:

      Activity 不拥有该视图,因此找不到它也就不足为奇了。将getActivity() 替换为getView(),您应该一切顺利。 getView() 为您提供此 Fragment 的根视图,并且应该能够找到您正在寻找的视图,因为它是视图的祖先之一。您只能找到具有其祖先之一的视图,因为findViewWithId() 递归地查看所有子视图以找到该视图。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-09
        相关资源
        最近更新 更多