ViewPager 中的片段没有与之关联的活动

Posted

技术标签:

【中文标题】ViewPager 中的片段没有与之关联的活动【英文标题】:Fragment inside a ViewPager does not have the activity associated with it 【发布时间】:2020-04-20 12:22:05 【问题描述】:

我有一个使用 ViewPager 和 TabLayout 的用例。我用过android教程linked here。

我的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:orientation="vertical">
     <androidx.viewpager.widget.ViewPager
        android:layout_
        android:layout_
        android:id="@+id/notification_view_pager">
        <com.google.android.material.tabs.TabLayout
            android:id="@+id/notification_tabs"
            android:layout_
            android:layout_ />
    </androidx.viewpager.widget.ViewPager>
</LinearLayout>

我的活动

public class MyActivity extends AppCompatActivity 


    int currentFocussedTab = -1;

    private TabLayout notificationsTabLayout;

    private ViewPager notificationsViewPager;

    private FragmentStatePagerAdapter notificationsStatePagerAdapter;

    private Fragment fragmentOne;

    private Fragment fragmentTwo;

    @Override
    public void onCreate(Bundle savedInstanceState)
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_activity);
        // Setting up tabbed layouts.
        notificationsTabLayout = findViewById(R.id.notification_tabs);

        notificationsTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() 
            @Override
            public void onTabSelected(TabLayout.Tab tab)
            
                int position = tab.getPosition();
                currentFocussedTab = position;
                // Custom function to log click.
                if (position == 0) 
                  fragmentOne.logClick();
                 else 
                  fragmentTwo.logClick();
                
            

            @Override
            public void onTabUnselected(TabLayout.Tab tab)
            
                int position = tab.getPosition();

                if (position == 0) 
                   fragmentOne.logUnselect();
                 else
                   fragmentTwo.logUnselect();
                
            

            @Override
            public void onTabReselected(TabLayout.Tab tab) 
        );

        // Set up view pager.
        notificationsViewPager = findViewById(R.id.notification_view_pager);
        notificationsViewPager.setCurrentItem(0);
        notificationsTabLayout.setupWithViewPager(notificationsViewPager);
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentOne = new FragmentOne();
        fragmentTwo = new FragmentTwo();
        notificationsStatePagerAdapter = new FragmentStatePagerAdapter(fragmentManager,
            FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) 
            @NonNull
            @Override
            public Fragment getItem(int position)
            
                return position == 0 ? fragmentOne : fragmentTwo;
            

            @Override
            public int getCount()
            
                // Two fixed tabs.
                return 2;
            

            @Nullable
            @Override
            public CharSequence getPageTitle(int position)
            
                return position == 0 ? getText(R.string.act_now_tab) : getText(R.string.others_tab);
            


        ;
        notificationsViewPager.setAdapter(notificationsStatePagerAdapter);
    

FragmentOne 和 Fragment 2 的设置类似。所以我以 FragmentOne 为例

class FragmentOne extends Fragment 


. . . . Define all UI elements . . . .

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState)
   
       final View view = inflater.inflate(R.layout.fragment_layout, container, false);
        ... Initialize all the layout UI elements . . . 

       return view;
   

更新

我在片段布局中定义了一个按钮。该按钮在onCreateView 方法中初始化。单击按钮时,我想启动一个新活动。

问题

我必须从片段内部加载另一个活动。我就是这样做的

Intent intent = new Intent(getActivity(), MyNewActivity.class);
getActivity().startActivity(intent);

但是,应用程序终止,因为 getActivity() 始终返回 null。如果我在视图分页器中没有片段,则该函数不会返回 null。

期望的行为

我想从已在视图寻呼机中加载的片段中加载新的应用程序活动。我该如何实现?

【问题讨论】:

您是否尝试过将 Activity 上下文从 Activity 传递给 Fragment 类?将其保存在全局变量中,然后您可以尝试使用它来启动另一个活动 您应该将活动变量作为成员存储在片段的 onAttach 中的片段中,稍后将其与 Intent 一起使用以启动新的活动。 onAttach 中的上下文(活动)保证为@NonNull 你把启动新Activity的代码放在哪里了? @MohammedAlaa 我将其放入片段中。有一个按钮被定义为片段布局中的 UI 元素之一。我有一个创建意图的 onclick 侦听器回调。 检查proandroiddev.com/…中的#2和#3 【参考方案1】:

假设您通过单击按钮启动新意图,请尝试这样的操作。

在你的片段类中

public class MyFragment extends Fragment implements View.OnclickListener 
    private Activity activity;

    @Override
    public void onAttach(Context context) 
        activity = (Activity) context;
    

    @Override
    public void onDetach()
        activity = null;
    

    @Override
    public void onClick(View v) 
        startIntent();
    

    private void startIntent()
        if (activity == null) return;
        Intent intent = new Intent(activity, MyNewActivity.class);
        activity.startActivity(intent);
    

如果这不起作用,即 activity 为 null,那么您可能在 Fragment 的错误生命周期阶段启动了 Intent,此时 Fragment 未附加到 Activity 并且不是通过按钮的 onclicklistener。

【讨论】:

这应该可以,但要小心在 Fragments 中保留对活动的引用,这不是好的形式,因为您可能会导致内存泄漏。 @CoryRoy 是的,一般来说。但是你能详细说明一下这个具体案例吗?我相信从 onAttach 传递的引用很好,并且在 onDetach 中被删除。【参考方案2】:

我会将有问题的方法放在您的Activity 中,然后从您的Fragment 调用它。我在你的类的底部添加了一个方法。

活动:

public class MyActivity extends AppCompatActivity 


    int currentFocussedTab = -1;

    private TabLayout notificationsTabLayout;

    private ViewPager notificationsViewPager;

    private FragmentStatePagerAdapter notificationsStatePagerAdapter;

    private Fragment fragmentOne;

    private Fragment fragmentTwo;

    @Override
    public void onCreate(Bundle savedInstanceState)
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_activity);
        // Setting up tabbed layouts.
        notificationsTabLayout = findViewById(R.id.notification_tabs);

        notificationsTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() 
            @Override
            public void onTabSelected(TabLayout.Tab tab)
            
                int position = tab.getPosition();
                currentFocussedTab = position;
                // Custom function to log click.
                if (position == 0) 
                  fragmentOne.logClick();
                 else 
                  fragmentTwo.logClick();
                
            

            @Override
            public void onTabUnselected(TabLayout.Tab tab)
            
                int position = tab.getPosition();

                if (position == 0) 
                   fragmentOne.logUnselect();
                 else
                   fragmentTwo.logUnselect();
                
            

            @Override
            public void onTabReselected(TabLayout.Tab tab) 
        );

        // Set up view pager.
        notificationsViewPager = findViewById(R.id.notification_view_pager);
        notificationsViewPager.setCurrentItem(0);
        notificationsTabLayout.setupWithViewPager(notificationsViewPager);
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentOne = new FragmentOne();
        fragmentTwo = new FragmentTwo();
        notificationsStatePagerAdapter = new FragmentStatePagerAdapter(fragmentManager,
            FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) 
            @NonNull
            @Override
            public Fragment getItem(int position)
            
                return position == 0 ? fragmentOne : fragmentTwo;
            

            @Override
            public int getCount()
            
                // Two fixed tabs.
                return 2;
            

            @Nullable
            @Override
            public CharSequence getPageTitle(int position)
            
                return position == 0 ? getText(R.string.act_now_tab) : getText(R.string.others_tab);
            


        ;
        notificationsViewPager.setAdapter(notificationsStatePagerAdapter);
    

    public void startNewActivity() 
        Intent intent = new Intent(this, MyNewActivity.class);
        startActivity(intent);
    

内部片段:

把它放在片段的点击函数中

...
MyActivity myActivity = getActivity()
if (myActivity != null)
  myActivity.startNewActivity()
...

【讨论】:

以上是关于ViewPager 中的片段没有与之关联的活动的主要内容,如果未能解决你的问题,请参考以下文章

响应Activity中的ViewPager2 Fragments事件

在使用ViewPager时尝试从其父活动修改片段时出现空指针异常

ViewPager开关没有显示片段之间

在popBackStack之后,ViewPager中的碎片不是显示器

viewpager 中的片段,未找到视图错误

如何使用 tabLayout 在 ViewPager 中显示片段?