在片段中获取 null FragmentManager/Activity

Get null FragmentManager/Activity in fragment

场景

我想在收到一些 HTTP 请求的响应后更新几个 fragment 的内容。

我的想法

我的实现是这样的: activity 的 onCreate,绑定 ViewPagerAdapter 到它。然后触发HTTP请求获取数据。 请求成功后,更新Fragment中的内容。

代码

sendRequest。 --> adapter.updateFragment(bundle) --> fragment.updateData(bundle);

Activity

protected void onCreate(Bundle savedInstanceState) {
    Log.d("DetailedProduct-LifeCycle", "------------onCreate------------");

    ...

    // Set ViewPager
    viewPager = findViewById(R.id.view_pager);
    adapter = new ViewPagerAdapter(getSupportFragmentManager());
    viewPager.setAdapter(adapter);
    // Send Request
    sendRequest();

    ...
}

public void sendRequest(){
    Log.d("DetailedProduct", requestUrl);

    RequestQueue queue = Volley.newRequestQueue(this);
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET,
            requestUrl,
            null,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    LinearLayout progressView = findViewById(R.id.progressView);
                    progressView.setVisibility(View.GONE);
                    bundle.putString("detail", response.toString());
                    Log.d("DetailedProduct", "get data:"+response.toString());
                    Log.d("DetailedProduct", "final Data:" + bundle.toString());
                    adapter.updateFragment(bundle);
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    Log.d("DetailedProduct", "Cannot get detailed data");
                }
            });
    queue.add(jsonObjectRequest);
}

适配器

public class ViewPagerAdapter extends FragmentPagerAdapter {
    private SellerFragment sellerFragment;
    private ShippingFragment shippingFragment;
    private ProductSummaryFragment productSummaryFragment;
    private FragmentManager fragManager;
    public ViewPagerAdapter(FragmentManager fragmentManager){
        super(fragmentManager);
        sellerFragment = new SellerFragment();
        shippingFragment = new ShippingFragment();
        productSummaryFragment = new ProductSummaryFragment();
    }
    @NonNull
    @Override
    public Fragment getItem(int position) {
        // ToDo:
        Log.d("ViewPager", position+": ------------getItem----------");

        switch (position){
            case 0:
                if(productSummaryFragment==null){
                    productSummaryFragment = new ProductSummaryFragment();
                }
                return productSummaryFragment;
            case 1:
                if(sellerFragment==null){
                    sellerFragment = new SellerFragment();
                }
                return sellerFragment;
            case 2:
                if(shippingFragment==null){
                    shippingFragment = new ShippingFragment();
                }
                return shippingFragment;
            default:
                return null;
        }
    }

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

    public void updateFragment(Bundle bundle){
        Log.d("ViewPager", "------------updateData----------");
        productSummaryFragment.updateData(bundle);
        sellerFragment.updateData(bundle);
        shippingFragment.updateData(bundle);
    }
}

片段示例

public class ShippingFragment extends Fragment {
    private TextView shippingSection;
    protected JSONObject data;
    private AppCompatActivity mActivity;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.shipping_fragment_layout, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        shippingSection = view.findViewById(R.id.shipping_info_section_content);
        setData();
    }

    @Override
    public void onAttach(@NonNull Context context) {
        Log.d("ShippingFragment", "-----------onAttach----------");
        super.onAttach(context);
        if(context instanceof AppCompatActivity){
            Log.d("ShippingFragment", "---------bind mActivity Success-------");
            mActivity = (AppCompatActivity)context;
        }
    }

    @Override
    public void onDetach() {
        Log.d("ShippingFragment", "-----------onDetach----------");
        super.onDetach();
    }
    // Same for all fragments
    public void  updateData(Bundle bundle){
        Log.d("ShippingFragment", "--------------updateData------------");
        setArguments(bundle);

        if(mActivity==null){
            Log.e("ShippingFragment", "------------activity disappears----------");
        }
        FragmentManager fragmentManager = mActivity.getSupportFragmentManager();
        fragmentManager.beginTransaction().detach(this).attach(this).commit();
    }
}

问题

日志显示位置 0,1 的片段 updateData 运行良好。但它会导致位置 2 的片段出错。

我发现的区别是适配器没有为位置 2 调用 getItem,这意味着 shippingFragmentonAttach 没有被调用。所以mActivity不存在。

没有mActivity,在shippingFragment中使用getFragmentManager,得到这个错误:

我的直觉告诉我问题一定出在adapter的工作流程或者fragmentManager事务。但是作为Android的初学者,我花了一整天的时间,毫无头绪。

如何解决?顺便问一下,有没有更好的方法来实现我的场景?

尝试调用 viewPager.setOffscreenPageLimit(3) 以确保在 activity 打开后所有 3 个片段都附加到 activity。