You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android MVP模式下Retrofit2请求返回空列表问题求助

Why Your Retrofit + MVP Implementation Returns an Empty List

Hey, let's break down why you're getting an empty list even though the network response is successful—this is a super common pitfall with asynchronous operations in Android!

The Root Cause

Your searchUser method uses Retrofit's call.enqueue() which runs the network request asynchronously (on a background thread). But right after you kick off the request, you immediately return searchResult—at this point, the onResponse callback hasn't fired yet, so searchResult is still its initial empty/uninitialized value. The method doesn't wait for the network call to finish before returning!

On top of that, having your MainModel create a MainPresenter instance breaks MVP's dependency rules (Model shouldn't depend on Presenter—they should communicate via callbacks instead).

Fixing the Issue

We'll adjust the code to use a callback interface to pass data from Model to Presenter once the async request completes. Here's how:

1. Define a Callback Interface

First, create an interface to handle success/failure events from the network request:

public interface OnSearchUserListener {
    void onSearchSuccess(List<SearchDdb> result);
    void onSearchFailed();
}

2. Rewrite the MainModel to Use Callbacks

Remove the Presenter reference from the Model and use the callback to pass data once it's ready:

public class MainModel {
    private Context context;

    public MainModel(Context context){
        this.context = context;
    }

    // Async method with callback instead of synchronous return
    public void searchUser(String name, final OnSearchUserListener listener) {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://jsonplaceholder.typicode.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        Db db = retrofit.create(Db.class);
        Call<List<SearchDdb>> call = db.getUsers(name);
        
        call.enqueue(new Callback<List<SearchDdb>>() {
            @Override
            public void onResponse(Call<List<SearchDdb>> call, Response<List<SearchDdb>> response) {
                if(response.isSuccessful() && response.body() != null){
                    // Pass the valid result to the callback
                    listener.onSearchSuccess(response.body());
                } else {
                    listener.onSearchFailed();
                }
            }

            @Override
            public void onFailure(Call<List<SearchDdb>> call, Throwable t) {
                listener.onSearchFailed();
                // Add logging here to debug failures: t.printStackTrace();
            }
        });
    }
}

3. Update the Presenter to Handle the Callback

Modify the Presenter to use the callback and update the View (the UI layer) once data is received:

public class MainPresenter {
    private Context context;
    private MainModel model;
    private MainView view; // Reference to your UI layer

    public MainPresenter(Context context, MainView view){
        this.context = context;
        this.view = view;
        this.model = new MainModel(context);
    }

    public void searchUser(String name) {
        model.searchUser(name, new OnSearchUserListener() {
            @Override
            public void onSearchSuccess(List<SearchDdb> result) {
                // Pass the result to the View to update UI
                if(view != null){
                    view.displaySearchResults(result);
                }
            }

            @Override
            public void onSearchFailed() {
                if(view != null){
                    view.showErrorDialog();
                }
            }
        });
    }

    // Define a View interface to communicate with the UI
    public interface MainView {
        void displaySearchResults(List<SearchDdb> results);
        void showErrorDialog();
    }
}

4. Update Your UI Layer (e.g., Activity/Fragment)

Make your Activity/Fragment implement the MainView interface to receive and display the results:

public class MainActivity extends AppCompatActivity implements MainPresenter.MainView {
    private MainPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        presenter = new MainPresenter(this, this);
        // Trigger search when needed
        presenter.searchUser("1");
    }

    @Override
    public void displaySearchResults(List<SearchDdb> results) {
        // Update your RecyclerView/ListView with the non-empty results here
    }

    @Override
    public void showErrorDialog() {
        // Show your error dialog as before
    }
}

Key Takeaways

  • Never return synchronously from an async operation: Network calls take time—always use callbacks (or Kotlin coroutines/Flow if you're using Kotlin) to pass data when it's ready.
  • Follow MVP rules: Model should only handle data operations, Presenter mediates between Model and View, and View handles UI updates.
  • Always null-check: Make sure response.body() and your View reference aren't null to avoid crashes.

内容的提问来源于stack exchange,提问作者Yousef Elsayed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:49:19