Android MVP模式下Retrofit2请求返回空列表问题求助
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

