Retrofit 中的 Enqueue 方法不会在 Fragment 中加载数据

Posted

技术标签:

【中文标题】Retrofit 中的 Enqueue 方法不会在 Fragment 中加载数据【英文标题】:Enqueue method in Retrofit doesn't load data in Fragment 【发布时间】:2020-09-18 03:19:54 【问题描述】:

在过去的 3 天里,我感到震惊,无法使用改造 2.4.0 在 Fragment 中的 recyclerview 上加载数据。我可以在终端中看到数据是使用真实 url 从服务器获取的,但无法填充它(意味着当我调试代码时跳过 OnReponse 和 OnFailure)。此外,我可以在应用程序 UI 上看到一些垃圾值。在这方面已经回答了一些问题,但没有一个解决方案对我有用。即使我在 github 上进行了研究,但在那里没有找到任何解决方案。到目前为止,我有以下代码。

public interface UserAPIEndPoint 
    @GET("posts")
    Call<List<Post>> getAllUsers();

以下是改造实例

public class RetrofitInstance 
    public static Retrofit retrofit;
    private static final String base_Url = "https://jsonplaceholder.typicode.com/";
    public static Retrofit getRetrofitInstance()
        if (retrofit == null)
            HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
            interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

            retrofit = new Retrofit.Builder()
                    .baseUrl(base_Url)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        
        return retrofit;
    

这里是片段类

public class MessageFragment extends Fragment 
    private RecyclerView recyclerView;
    private List<Post> user;
    private PostAdapter userAdapter;
    private LinearLayoutManager layoutManager;
    View rootView;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
        rootView = inflater.inflate(R.layout.fragment_message,container,false);
        loadJSON();
        return rootView;
    

    private void loadJSON() 
        try 
        UserAPIEndPoint userAPIEndPoint= RetrofitInstance.getRetrofitInstance().create(UserAPIEndPoint.class);
        Call<List<Post>> userlist = userAPIEndPoint.getAllUsers();
//        userlist.execute();
    userlist.enqueue(new Callback<List<Post>>() 
            @Override
            public void onResponse(Call<List<Post>> call, Response<List<Post>> response) 
                user = response.body();
                recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview);
                recyclerView.setHasFixedSize(true);
                layoutManager = new LinearLayoutManager(getActivity());
                recyclerView.setLayoutManager(layoutManager);
                recyclerView.setItemAnimator(new DefaultItemAnimator());
                userAdapter = new PostAdapter(getActivity(),user);
                recyclerView.setAdapter(userAdapter);

            

            @Override
            public void onFailure(Call<List<Post>> call, Throwable t) 

            
        );
         catch (Exception e) 
            Log.d("Error", e.getMessage());
            Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_SHORT).show();
        
    

Post.class 通过 pojo2schema 进行转换。 RecyclerAdapter如下。

public class PostAdapter extends RecyclerView.Adapter<PostAdapter.ViewHolder> 
    private List<Post> posts;
    private Context mcontext;

    public PostAdapter(Context context,List<Post> post)
        this.posts = post;
        this.mcontext =context;
    

    @NonNull
    @Override
    public PostAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout_post,parent,false);
        return new ViewHolder(view);
    

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) 
        holder.userid.setText(String.valueOf(posts.get(position).getUserId()));
        holder.id.setText(String.valueOf(posts.get(position).getId()));
        holder.title.setText(posts.get(position).getTitle());
        holder.body.setText(posts.get(position).getBody());
    


    @Override
    public int getItemCount() 
        return posts.size();
    

    public class ViewHolder extends RecyclerView.ViewHolder 
        private TextView userid,id,title,body;

        public ViewHolder(View itemView) 
            super(itemView);
            userid = (TextView) itemView.findViewById(R.id.userId);
            id = (TextView) itemView.findViewById(R.id.id);
            title = (TextView) itemView.findViewById(R.id.title);
            body = (TextView) itemView.findViewById(R.id.body);

        
    


build.gradle(模块:app)

apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'

android 
    compileSdkVersion 28
    defaultConfig 
        applicationId "com.example.scratchnavigation"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
    buildTypes 
        release 
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        
    


dependencies 
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "androidx.core:core:1.4.0-alpha01"
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'com.google.android.material:material:1.1.0-alpha04'
    implementation 'com.google.firebase:firebase-core:16.0.3'
    implementation 'com.google.firebase:firebase-auth:16.0.3'
    implementation 'com.miguelcatalan:materialsearchview:1.4.0'

    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    testImplementation 'junit:junit:4.13'

    implementation 'com.google.code.gson:gson:2.8.5'
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
    implementation 'de.hdodenhof:circleimageview:3.1.0'
    implementation "androidx.cardview:cardview:1.0.0"
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation "androidx.drawerlayout:drawerlayout:1.0.0"
    implementation "androidx.cardview:cardview:1.0.0"
    implementation 'com.squareup.okhttp3:logging-interceptor:4.7.2'
    implementation 'com.squareup.okhttp3:okhttp:4.7.2'
    implementation 'org.conscrypt:conscrypt-android:2.4.0'

我们非常感谢这方面的任何帮助。提前致谢。

【问题讨论】:

【参考方案1】:

我相信这是因为它是一个异步网络调用。您在不同的线程中创建所有内容。

有两种方法可以解决这个问题。

1.) 尝试创建一个处理程序以在主线程上发布数据集已更改的内容,例如

        Handler mHandler = new Handler(Looper.getMainLooper());
    mHandler.post(new Runnable() 
        @Override
        public void run() 
            userAdapter = new PostAdapter(user);
            recyclerView.setAdapter(userAdapter);
            if (userAdapter != null) 
                userAdapter.notifyDataSetChanged(userAdapter);
                recyclerView.setVerticalScrollbarPosition(userAdapter.getItemCount());
            
            recyclerView.smoothScrollToPosition(userAdapter.getItemCount());
        
    );

2.) 在 onCreateView 中分配 recyclerView 和 Adapter 所以它看起来像:

    public class MessageFragment extends Fragment 
    private RecyclerView recyclerView;
    private List<Post> user;
    private PostAdapter userAdapter;
    private LinearLayoutManager layoutManager;
    View rootView;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
        rootView = inflater.inflate(R.layout.fragment_message,container,false);
        
        recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview);
        recyclerView.setHasFixedSize(true);
        layoutManager = new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        userAdapter = new PostAdapter(getActivity(), null);
        recyclerView.setAdapter(userAdapter);
        
        loadJSON();
        return rootView;
    

    private void loadJSON() 
        try 
            UserAPIEndPoint userAPIEndPoint= RetrofitInstance.getRetrofitInstance().create(UserAPIEndPoint.class);
            Call<List<Post>> userlist = userAPIEndPoint.getAllUsers();
            userlist.enqueue(new Callback<List<Post>>() 
                @Override
                public void onResponse(Call<List<Post>> call, Response<List<Post>> response) 
                    user = response.body();
                    userAdapter.setData(user);
                

                @Override
                public void onFailure(Call<List<Post>> call, Throwable t) 

                
            );
         catch (Exception e) 
            Log.d("Error", e.getMessage());
            Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_SHORT).show();
        
    

然后您还可以为该方法修改 PostsAdapter

    public class PostAdapter extends RecyclerView.Adapter<PostAdapter.ViewHolder> 
    private List<Post> posts;
    private Context mcontext;

    public PostAdapter(Context context,List<Post> post)
        this.posts = post;
        this.mcontext =context;
    

    @NonNull
    @Override
    public PostAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout_post,parent,false);
        return new ViewHolder(view);
    

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) 
        holder.userid.setText(String.valueOf(posts.get(position).getUserId()));
        holder.id.setText(String.valueOf(posts.get(position).getId()));
        holder.title.setText(posts.get(position).getTitle());
        holder.body.setText(posts.get(position).getBody());
    


    @Override
    public int getItemCount() 
        return posts.size();
    
    
    public void setData(@NonNull List<Posts> list)
        if(list.size() > 0) 
            posts = list;
        
        this.noftifyDataSetChanged();
    

    public class ViewHolder extends RecyclerView.ViewHolder 
        private TextView userid,id,title,body;

        public ViewHolder(View itemView) 
            super(itemView);
            userid = (TextView) itemView.findViewById(R.id.userId);
            id = (TextView) itemView.findViewById(R.id.id);
            title = (TextView) itemView.findViewById(R.id.title);
            body = (TextView) itemView.findViewById(R.id.body);

        
    


【讨论】:

以上是关于Retrofit 中的 Enqueue 方法不会在 Fragment 中加载数据的主要内容,如果未能解决你的问题,请参考以下文章

打开使用 Retrofit2 下载的通知点击文件

注解深入浅出(五Retrofit 中的注解)

注解深入浅出(五Retrofit 中的注解)

从 Retrofit 获取的颜色参数不会显示在 xml 布局中

Retrofit 中的注解以及如何自定义接口方法注解

RxAndroid + Retrofit callTimeout 不会触发 onError