сохранить вид в последнем элементе - LoadMore RecyclerView - PullRequest
0 голосов
/ 28 июня 2018

Halo, в моем приложении есть LoadMore RecyclerView. это работа, но когда я загружаю больше элементов, окно повторного просмотра всегда показывает верхнюю часть списка. Я имею в виду, что должен быть показан последний загруженный элемент.

Кто-нибудь, не могли бы вы мне помочь? спасибо.

мой скриншот:

  1. 1 - 5 - первый загруженный список :

enter image description here

  1. 6 - 10 отображается после прокрутки окна просмотра, но после 6 - 10 загружен, recyclerView всегда показывает верхнюю часть списка (1-5) :

enter image description here

это мой код:

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_job_company);

    //intent untuk nerima value namaAdver dan handling jika tdk ada list
    TextView namaCompany = (TextView) findViewById(R.id.tv_companyname);
    TextView emptyList = (TextView) findViewById(R.id.emptylist);

    loading = (ProgressBar) findViewById(R.id.loading);
    loading.getIndeterminateDrawable().setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.MULTIPLY);

    Intent intentGet = getIntent();
    companyName = intentGet.getStringExtra("namaCompany");
    idComp = intentGet.getStringExtra("idCompany");

    try {
        compID = Integer.parseInt(idComp);
    } catch (NumberFormatException nfe) {

    }

    namaCompany.setText(companyName);
    setTitle(intentGet.getStringExtra("namaCompany"));

    PaginationJobCompany(compID, pageNum);

    recyclerView = (RecyclerView) findViewById(R.id.rv_job_company2);
    recyclerView.setHasFixedSize(true);
    mLayoutManager = new LinearLayoutManager(getApplicationContext());
    recyclerView.setLayoutManager(mLayoutManager);
    recyclerView.addItemDecoration(new DividerItemDecoration(getApplicationContext(), null)); //untuk divider

}

private void PaginationJobCompany(final int compID, final int pageNumber) {
    try {
        loading.getIndeterminateDrawable().setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.MULTIPLY);
        loading.setVisibility(View.GONE);


        //authorization JWT pref_token berdasarkan string yg disimpan di preferenceManager pada class login.
        Authorization = (PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString(
                getResources().getString(R.string.pref_token), ""));

        //production
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(getResources().getString(R.string.base_url))
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        //assign variabel request ke class interface TabAdverRequest
        final APIInterfaces request = retrofit.create(APIInterfaces.class);

        Call<ReportJobModel> call = request.getReportPagination(compID, pageNum, length, Authorization); //ngirim ke API
        call.enqueue(new Callback<ReportJobModel>() {
            @Override
            public void onResponse(Call<ReportJobModel> call, Response<ReportJobModel> response) {
                loading.getIndeterminateDrawable().setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.MULTIPLY);
                loading.setVisibility(View.GONE);
                if (response.isSuccessful()) {
                    companyResult = response.body().getResult();
                    if (!companyResult.isEmpty()) {
                        company.addAll(companyResult);

                        for (int i = 0; i < companyResult.size(); i++) {
                            if (company.get(i).getCompanyID() == compID) {
                                jobItemResult = response.body().getResult().get(i).getJobs();
                                jobItem.addAll(jobItemResult);
                            }
                        }
                    }
                    else {
                        for (int j = 0; j < companyResult.size(); j++) {
                            if (company.get(j).getCompanyID() == compID) {
                                lastId = jobItem.size()-1;
                            }
                        }

                    }

                    adapter = new JobCompanyAdapter(jobItem, recyclerView);
                    recyclerView.setAdapter(adapter);

                    adapter.setOnLoadMoreListener(new OnLoadMoreListener() {
                        @Override
                        public void onLoadMore() {
                            //add null , so the adapter will check view_type and show progress bar at bottom
                            jobItem.add(null);
                            adapter.notifyItemInserted(jobItem.size() - 1);
                            loading.getIndeterminateDrawable().setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.MULTIPLY);
                            loading.setVisibility(View.GONE);

                            handler.postDelayed(new Runnable() {
                                @Override
                                public void run() {

                                    jobItem.remove(jobItem.size() - 1);
                                    adapter.notifyItemRemoved(jobItem.size());
                                    loading.setVisibility(View.GONE);

                                        pageNum++;
                                        loading.setVisibility(View.GONE);
                                        PaginationJobCompany(compID, pageNum);
                                        adapter.notifyDataSetChanged();
                                }
                            }, 2000);
                        }
                    });

                } else if (response.errorBody() != null) {
                    loading.setVisibility(View.GONE);
                    Toast.makeText(getApplicationContext(), "Gagal Memuat. Periksa Koneksi Anda!", Toast.LENGTH_LONG).show();
                } else if (response.code() == 400) {
                    loading.setVisibility(View.GONE);
                    Toast.makeText(getApplicationContext(), "Gagal Memuat. Periksa Koneksi Anda!", Toast.LENGTH_LONG).show();
                } else {
                    loading.setVisibility(View.GONE);
                    Toast.makeText(getApplicationContext(), "Gagal Memuat. Periksa Koneksi Anda! 1", Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onFailure(Call<ReportJobModel> call, Throwable t) {
                Toast.makeText(getApplicationContext(), "Gagal Memuat. Periksa Koneksi Anda! 1", Toast.LENGTH_LONG).show();
            }
        });
    } catch (Exception e) {
        Toast.makeText(getApplicationContext(), "Gagal Memuat. Periksa Koneksi Anda! 1", Toast.LENGTH_LONG).show();
    }
}

1 Ответ

0 голосов
/ 29 июня 2018

Хорошо, я предполагаю, что у вас уже есть реализация EndlessScrollListener для RecyclerView, если нет, я призываю вас проверить это: https://gist.github.com/nesquena/d09dc68ff07e845cc622. Далее, чтобы сделать ваш код более читабельным и адаптируемым, Я бы порекомендовал вам использовать больше инкапсуляции.

Например: имейте NetworkHandler, который выполняет обратные вызовы для вас в пользовательском интерфейсе. Где вы переключаете поведение пользовательского интерфейса соответственно. Для этого вам нужен интерфейс OnDataCallback.

// OnDataCallback.java
interface OnDataCallback<T> {
    void onData(T data);
    void onError(Throwable error);
}

// NetworkHandler.java
public class NetworkHandler<T> {
    @Nullable
    protected OnDataCallback<T> dataCallback;

    protected int pageIndex = 0;

    public void setDataCallback(OnDataCallback<T> dataCallback) {
        this.dataCallback = dataCallback;
    }

    public void removeDataCallback() {
        dataCallback = null;
    }

    public void setPageIndex(int pageIndex) {
        this.pageIndex = pageIndex;
    }

    public void updatePageNumber() {
        pageIndex++;
    }
}

Создайте класс RetrofitUtils как Singleton, который можно использовать для создания служб.

public static class RetrofitUtils {

    private static RetrofitUtils utils;
    public static RetrofitUtils getInstance() {
        if (utils == null) {
            utils = new RetrofitUtils();
        }
        return utils;
    }

    private Retrofit retrofit;

    public Retrofit getRetrofitInstance(){
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl("http://mybaseurl.api/v1/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }

    public JobService constructJobService(Class<JobService> uClass)  {
        return getRetrofitInstance().create(uClass);
    }

    public LoginService construcstLoginService(Class<LoginService> uClass) {
        return getRetrofitInstance().create(uClass);
    }
}

Затем унаследуйте NetworkHandler и переопределите методы в соответствии с вашими спецификациями, например, получите JobNetworkHandler, который выполняет запрос и пейджинг для вас. Создайте пользовательские классы Throwable для более эффективной обработки ошибок, как в примере это ErrorBodyThrowable. Осталось только реализовать обратный вызов и установить пользовательский интерфейс во фрагменте или в операции.

public class JobReportHandler extends NetworkHandler<ReportJobModel> {
    int compID;
    int length;

    Authorization auth = AuthUtils.getAuth();

    @Override
    public void updatePageNumber() {
        super.updatePageNumber();
        fetchJobsModel(compID, length);
    }

    public void fetchJobsModel(int compID, int length) {
        this.compID = compID;
        this.length = length;
        JobService request = RetrofitUtils.getInstance().constructJobService(JobService.class);
        Call<ReportJobModel> call = request.getReportPagination(compID, pageIndex, length, auth); //ngirim ke API
        call.enqueue(new Callback<JobModel>() {
            @Override
            public void onResponse(Call<JobModel> call, Response<JobModel> response) {
                // manipulate data and pass the UI model
                // that needs to be handled by the view
                ReportJobModel reportJobModel = response.convertToReport();
                if (dataCallback == null) return;

                if (response.isSuccessful()) {
                    dataCallback.onData(reportJobModel);
                } else if (response.errorBody() != null) {
                    dataCallback.onError(new ErrorBodyThrowable());
                } else if (response.code() == 400) {
                    dataCallback.onError(new ApiError());
                } else {
                    // do something else
                }
            }

            @Override
            public void onFailure(Call<ReportJobModel> call, Throwable t) {
                if (dataCallback != null) {
                    dataCallback.onError(t);
                }
            }
        });
    }
    public class ErrorBodyThrowable extends Throwable {
        ErrorBodyThrowable() {
            super("Gagal Memuat. Periksa Koneksi Anda!");
        }
    }
}

Обратите внимание, что обновление pageIndex автоматически запускает сетевой вызов, поэтому вы избегаете записи избыточных вызовов.

Наконец-то в вашем Fragment или Activity есть что-то вроде этого:

// TestFragment.java
public final class TestFragment extends Fragment implements OnDataCallback<ReportJobModel>, CustomRecyclerOnScrollListener {
    @Bind(R.id.myRecyclerView)
    RecyclerView myRecyclerView;

    private JobsAdapter adapter;
    private final JobReportHandler jobHandler = new JobReportHandler();
    private final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
    private MyCustomEndlessScrollListener endlessScroll;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.my_list_fragment, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        endlessScroll = = new MyCustomEndlessScrollListener(this);
        setUi();
        initializeNetwork();
    }

    private void initializeNetwork() {
        // after setting the UI Parameters
        jobHandler.setDataCallback(this);
        jobHandler.fetchJobsModel(compID, length);
    }

    @Override
    public void onData(ReportJobModel dataModel) {
        // just a safety mechanism to handle threading
        // use the main thread dispatcher
        mainThreadHandler.post(new Runnable() {
            @Override
            public void run() {
                final ArrayList<JobItem> data = dataModel.getJobItems();
                UiUtils.makeGone(loadingProgress);
                if (myRecyclerView.getAdapter() == null || jobAdapter == null) {
                    jobAdapter = JobsAdapter(data);
                    myRecyclerView.setAdapter(jobAdapter);
                    myRecyclerView.setOnScrollChangeListener(endlessScroll);
                } else {
                    jobAdapter.getItems().addAll(data);
                    jobAdapter.notifyItemRangeInserted(jobAdapter.getItems().size() -1, data.size());
                }
            }
        });
    }


    @Override
    public void onScrolledToBottom() {
        jobHandler.updatePageNumber();
    }

    @Override
    public void onError(final Throwable error) {
        // just a safety mechanism to handle threading
        // use the main thread dispatcher
        mainThreadHandler.post(new Runnable() {
            @Override
            public void run() {
                if (error.getMessage() != null && !error.getMessage().isEmpty()) {
                    Toast.makeText(getContext(), error.getMessage(), Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    @Override
    public void onDestroy() {
        jobHandler.removeDataCallback();
        super.onDestroy();
    }
}

Как вы видите, onScrolledToBottom() будет запускаться через CustomRecyclerScrollListener, и это вызовет updatePageNumber(), который затем вызовет fetchJobModel(), и в итоге вы получите обратный вызов для вашего фрагмента.

...