Welcome to 16892 Developer Community-Open, Learning,Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Inside a viewpager fragment is having a network call to load the data. Due to this network call it creates a lag for users. How can i handle network call inside a fragment which reside inside a viewpager. I just dont want my users to see the lag as it takes 4-7 seconds to load a fragment. what is efficent way to load a fragment via network call for Viewpager

below is code for Activity:

import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;

import android.os.Bundle;

import com.test.androidtest20202.R;
import com.test.androidtest20202.adapter.ViewPagerAdapter;

import java.util.ArrayList;
import java.util.List;

public class ViewPagerActivity extends AppCompatActivity {
    ViewPagerAdapter adapter;
    ViewPager viewPager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view_pager);
        viewPager = findViewById(R.id.viewpager);

        ArrayList<Integer> task_ids = new ArrayList<>();
        for(int i=0;i<5;i++){
            task_ids.add(i);
        }
        adapter = new ViewPagerAdapter(this, getSupportFragmentManager(),task_ids);
        viewPager.setAdapter(adapter);
    }
}

Below activity xml layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.ViewPagerActivity">

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@color/white"
        android:largeHeap="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Below is my Viewpager Adapter :

import android.content.Context;
import android.os.Bundle;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;

import com.test.androidtest20202.fragments.ViewPagerFragment;

import java.util.ArrayList;

public class ViewPagerAdapter   extends FragmentStatePagerAdapter {
    private ArrayList<Integer> taskid;
    private SparseArray<Fragment> registeredFragments = new SparseArray<>();

    public ViewPagerAdapter(Context context, @NonNull FragmentManager fm, ArrayList<Integer> taskid) {
        super(fm);
        this.taskid = taskid;
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        Fragment fragment = null;
        Bundle bundle = new Bundle();
        bundle.putInt("COMPLETED_TASKID", taskid.get(position));
        fragment = new ViewPagerFragment();
        registeredFragments.put(position, fragment);

        fragment.setArguments(bundle);
        return fragment;
    }


    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        registeredFragments.remove(position);
        super.destroyItem(container, position, object);
    }

    @Override
    public int getCount() {
        return taskid.size();
    }


}

Below is my Viewpager Fragment code:

import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.test.androidtest20202.R;
import com.test.androidtest20202.pojo.SaleskenResponse;
import com.test.androidtest20202.util.RestApiClient;
import com.test.androidtest20202.util.RestUrlInterface;

import butterknife.BindView;
import butterknife.ButterKnife;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class ViewPagerFragment  extends Fragment {
    private static final String TAG = "ViewPagerFragment";
    private ViewGroup container;
    private LayoutInflater inflater;
    @BindView(R.id.textView2)
    TextView textView;
    private AsyncTask mAsyncTask;
    public RestUrlInterface restUrlInterface;
    Integer taskid = -1;


    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        this.container = container;
        this.inflater = inflater;
        return initializeView();
    }
    private View initializeView() {

        final View view;
        view = inflater.inflate(
                R.layout.fragment_laout, container, false);
        ButterKnife.bind(this, view);
        restUrlInterface = RestApiClient.getClient(getContext()).create(RestUrlInterface.class);
        if (getArguments() != null) {
            taskid = getArguments().getInt("COMPLETED_TASKID");
        }
        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Call<SaleskenResponse> task_details = restUrlInterface.getTaskDetail(getString(R.string.token), taskid );
        task_details.enqueue(new Callback<SaleskenResponse>() {
            @Override
            public void onResponse(Call<SaleskenResponse> call, Response<SaleskenResponse> response) {
                switch (response.code()) {
                    case 200:
                        textView.setText( response.body().toString());
                }
            }

            @Override
            public void onFailure(Call<SaleskenResponse> call, Throwable t) {

            }
        });
    }
}

Below is Fragment layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
313 views
Welcome To Ask or Share your Answers For Others

1 Answer

So as the data only need to be loaded once I would do this in the activity onCreate just after you have created your task_ids ArrayList.

You seem to be using a custom RestAPI package, but most package do Network request asynchronously, so when you get a response for each request you would then store them in a shared viewmodel using the unique task_id's as an index.

The shared viewmodel can then be observed from the fragment and when the data is available the fragment will be notified to use it.

So basically start the Network load as soon as the Activity starts, to give it a head start before the viewpager is setup and the first Fragment is loaded, and storing your data independently of the Activity and Fragments.

Note this won't guarantee that the first fragment in the viewpager will have it's data available by the time it is shown but at least it should be part way to having it available and by the time the user swaps to the second page in the viewpager that data should already be available.

How to share data between Fragments with a shared viewmodel example is at https://blog.mindorks.com/shared-viewmodel-in-android-shared-between-fragments (this example is between 2 fragments but the same concept can be used for comms between the background RestAPI calls in the Activity and each Fragment in the viewpager.

There might be a trade off on first page load time between requesting the data for all task_id's in parallel vs doing them sequentially start with the first page and then once that has loaded request the next one, etc.

Sorry no code example (other than in the link on how to use shared viewmodel) but is more of an architectural answer as you seem to be using a custom RestAPI package I'm not familiar with.

This is basically caching the data for each fragment as soon as the activity starts and the Fragments just display the cached data.

If you can cache between each time the Activity is started you could instead of the shared viewmodel use a Database like Android Rooms, then when it Activity is started it has the data from last time the Activity was started and really it could in the background just check the freshness of the data stored in the database with a RestAPI request.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to 16892 Developer Community-Open, Learning and Share
...