简体   繁体   English

从服务器通过API传输数据完成后,如何使用远程数据构建recyclerview

[英]How to build recyclerview with remote data after the data transfer from server thorugh API is complete

I have built a recyclerview inside a fragment.我在片段中构建了一个回收视图。 The data that is to be populated in the recyclerview is stored in remote server and is being parsed thorugh JSON.要在 recyclerview 中填充的数据存储在远程服务器中,并通过 JSON 进行解析。

I am using Retrofit to transfer data from server to the application.我正在使用 Retrofit 将数据从服务器传输到应用程序。 Note: I am beginner in Android development and using Retrofit for the first time by watching tutorials.注意:我是 Android 开发初学者,第一次通过看教程使用 Retrofit。

Until now I have understood the following, corret me if I am wrong As the Retrofit library uses another thread instead of main thread to get response from server, it take few seconds for the data to transfer completely but till that time the recyclerview is already built with an empty ArrayList.到目前为止,我已经理解了以下内容,如果我错了,请纠正我由于 Retrofit 库使用另一个线程而不是主线程来从服务器获取响应,数据完全传输需要几秒钟,但直到那时 recyclerview 已经构建带有空的 ArrayList。

So, my question here is, How to hold the recyclerView from being built until the data transfer is complete?所以,我的问题是,如何保持 recyclerView 从构建到数据传输完成? OR How to update the empty ArrayList after the data transfer is complete and populate the recyclerview from that data?或如何在数据传输完成后更新空的 ArrayList 并从该数据填充 recyclerview? OR You can tell me whatever is the best and most efficient way to achieve the desired result.或者你可以告诉我什么是达到预期结果的最好和最有效的方法。

I already tried adapter.notifyDataSetChanged() , but either I didn't use it at correct place, or I didn't use it the correct way as it didn't work.我已经尝试过adapter.notifyDataSetChanged() ,但是我没有在正确的地方使用它,或者我没有以正确的方式使用它,因为它不起作用。 You can see it in the code.你可以在代码中看到它。

Library Fragment:-库片段:-

package com.diginfoexpert.mybooks.Fragment;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.diginfoexpert.mybooks.Activity.CategoryActvity;
import com.diginfoexpert.mybooks.Adapter.LibraryCategoriesCardAdapter;
import com.diginfoexpert.mybooks.Model.Category;
import com.diginfoexpert.mybooks.Model.LibraryAPI;
import com.diginfoexpert.mybooks.Model.LibraryCategories;
import com.diginfoexpert.mybooks.R;

import java.util.ArrayList;

import Controllers.JSONApiHolder;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.Retrofit.Builder;
import retrofit2.converter.gson.GsonConverterFactory;

public class LibraryFragment extends Fragment implements LibraryCategoriesCardAdapter.CategoryClickListener {

    private JSONApiHolder jsonApiHolder;
    ArrayList<Category> categories = new ArrayList<>();
    LibraryCategoriesCardAdapter adapter;
    RecyclerView recyclerView;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_library, container, false);
        Log.d("RETROFIT", "onCreateView: Library Fragment Started");

        recyclerView = view.findViewById(R.id.library_category_recycler_view);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://myurl.in/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        jsonApiHolder = retrofit.create(JSONApiHolder.class);

        getCategories();

        buildRecyclerView();

        return view;
    }

    private void buildRecyclerView() {
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        adapter = new LibraryCategoriesCardAdapter(buildCategoryList(),this);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(adapter);
    }

    private void getCategories() {
        Call<LibraryAPI> call = jsonApiHolder.getLibrary();

        call.enqueue(new Callback<LibraryAPI>() {
            @Override
            public void onResponse(Call<LibraryAPI> call, Response<LibraryAPI> response) {
                if(!response.isSuccessful()){
                    Log.d("RETROFIT", "onResponse: callback failed");
                    return;
                }

                else{
                    Log.d("RETROFIT", "onResponse: callback successful");
                    LibraryAPI libraryAPI = response.body();
                    categories = libraryAPI.getCategories();
                    adapter.notifyDataSetChanged();

                    for (Category category :categories){
                        Log.d("RETROFIT", "onResponse: "+category.getTitle());
                    }

                }
            }

            @Override
            public void onFailure(Call<LibraryAPI> call, Throwable t) {
                Log.d("RETROFIT", "onFailure: response failed : " +t.getMessage());
            }
        });
    }

    private ArrayList<Category> buildCategoryList() {
        ArrayList<Category> mList = new ArrayList<>();
//        mList.add(new Category("Art"));
//        mList.add(new Category("Action"));
//        mList.add(new Category("Thrill"));
//        mList.add(new Category("Fiction"));
//        mList.add(new Category("Romance"));
//        mList.add(new Category("Crime"));
//        mList.add(new Category("Classical"));
//        mList.add(new Category("Financial"));
//        mList.add(new Category("Business"));
        Log.d("RETROFIT", "Size of categories ArrayList "+categories.size());
        return categories;
    }

    @Override
    public void onCategoryClick() {
        Intent intent = new Intent(getActivity(), CategoryActvity.class);
        startActivity(intent);
    }
}

Debug Log:-调试日志:-

2020-03-25 14:26:37.536 1703-1703/com.myurl.mybooks D/RETROFIT: onCreateView: Library Fragment Started
2020-03-25 14:26:37.630 1703-1703/com.myurl.mybooks D/RETROFIT: Size of categories ArrayList 0
2020-03-25 14:26:42.171 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: callback successful
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC Mains Syllabus
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER 1 PART "A" History
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER 1 PART "B" Geography
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER-2 (PART "A") Polity
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER 2 (PART "B") Economics & Social
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER 3 Science
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER 4 Ethics
2020-03-25 14:26:42.173 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC HINDI

Here is your modified code portion这是您修改后的代码部分

public void onResponse(Call<LibraryAPI> call, Response<LibraryAPI> response) {
                if(!response.isSuccessful()){
                    Log.d("RETROFIT", "onResponse: callback failed");
                    return;
                }

                else{
                    Log.d("RETROFIT", "onResponse: callback successful");
                    LibraryAPI libraryAPI = response.body();
                    categories = libraryAPI.getCategories();
                    adapter.notifyDataSetChanged();

                    for (Category category :categories){
                      categories.add(category) // Added by me  
                      Log.d("RETROFIT", "onResponse: "+category.getTitle());
                    }
                    adapter.notifyDataSetChanged() // Added by me
                }
            }

I found the way out after sometime.过了一段时间我找到了出路。 I was building the recycler view in main method, which is the main thread.我在 main 方法中构建了回收器视图,这是主线程。 When we enque network requests in retrofit, it works on a different thread and hence till the data transfer completes, the recycler view has already been built in the main thread with no data available.当我们在改造中对网络请求进行排队时,它在不同的线程上工作,因此直到数据传输完成,回收器视图已经构建在主线程中,没有可用的数据。

So instead of building the recycler view in main thread, I created a method to build it.因此,我没有在主线程中构建回收器视图,而是创建了一个方法来构建它。 And I called the method after the application has got response from the server.在应用程序得到服务器响应后,我调用了该方法。

private void buildRecyclerView() {
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        adapter = new LibraryCategoriesCardAdapter(buildCategoryList(),this);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(adapter);
    }



private void getCategories() {
    Call<LibraryAPI> call = jsonApiHolder.getLibrary();

    call.enqueue(new Callback<LibraryAPI>() {
        @Override
        public void onResponse(Call<LibraryAPI> call, Response<LibraryAPI> response) {
            if(!response.isSuccessful()){
                Log.d("RETROFIT", "onResponse: callback failed");
                return;
            }

            else{
                Log.d("RETROFIT", "onResponse: callback successful");
                LibraryAPI libraryAPI = response.body();
                categories = libraryAPI.getCategories();
                buildRecyclerView();

                for (Category category :categories){
                    Log.d("RETROFIT", "onResponse: "+category.getTitle());
                }

            }
        }

        @Override
        public void onFailure(Call<LibraryAPI> call, Throwable t) {
            Log.d("RETROFIT", "onFailure: response failed : " +t.getMessage());
        }
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM