0

Scene

I want to update the content of several fragments once I get the response from some HTTP requests.

My Idea

My implementation is something like this: Idea onCreate of activity, Bind ViewPagerAdapter to it. Then trigger the HTTP request to get data. Once the request succeeds, update the content in Fragment.

Code

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

Adapter

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

Fragment Sample

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

Problem

The log shows that updateData for fragments at position 0,1 works well. but it incurs error for the fragment at position 2.

enter image description here

The difference I found is that the adaptor didn't call getItem for position 2, which means onAttach of shippingFragment doesn't been called. So mActivity does not exist.

Without mActivity, using getFragmentManager in shippingFragment, get this error: enter image description here

My intuition tells me that the problem must from the work flow of adapter or the fragmentManager transaction. But as a beginner of Android, I have spent all day on them, no clue.

How to fix it? By the way, is there better way to implement my scene?

Zheyuuu
  • 151
  • 1
  • 12

1 Answers1

1

Try to call viewPager.setOffscreenPageLimit(3) to make sure all 3 fragments are attached to the activity once the activity open.

TaQuangTu
  • 2,155
  • 2
  • 16
  • 30
  • Are there potential problems in my code? Memory leak etc. – Zheyuuu Jun 25 '20 at 06:32
  • @Zheyuuu No, to the best of my knowledge, ViewPaper inits just 2 fragments at once, example, the first one will be destroyed when the third one is displayed, when user want to back to the first one, it's will be initialized again. The `setOffscreenPapgeLimit(3)` sure that the viewPager will keep 3 fragments at once. – TaQuangTu Jun 25 '20 at 06:36