Tengo que mostrar una lista de usuarios en una vista recicladora de un fragmento. El código está bien, pero la lista no aparece cuando corro la aplicación.
package com.example.demo;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
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.example.demo.Model.User;
import com.mongodb.Block;
import com.mongodb.DBObject;
import com.mongodb.stitch.android.core.Stitch;
import com.mongodb.stitch.android.core.StitchAppClient;
import com.mongodb.stitch.android.services.mongodb.remote.RemoteFindIterable;
import com.mongodb.stitch.android.services.mongodb.remote.RemoteMongoClient;
import com.mongodb.stitch.android.services.mongodb.remote.RemoteMongoCollection;
import com.mongodb.stitch.android.services.mongodb.remote.RemoteMongoCursor;
import org.bson.Document;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class UsersFragment extends Fragment {
private RecyclerView recyclerView;
private UserAdapter userAdapter = null;
private List<User> mUsers = null;
private String username;
private String imageURL;
@Override
public View onCreateView( LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fargment_users,container,false);
recyclerView = view.findViewById(R.id.recycler_view);
StitchAppClient stitchAppClient = Stitch.getDefaultAppClient();
RemoteMongoClient client = stitchAppClient.getServiceClient(RemoteMongoClient.factory,"mongodb-atlas");
RemoteMongoCollection db = client.getDatabase("db").getCollection("Users");
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mUsers = new ArrayList<>();
mUsers.clear();
try {
readUsers();
} catch (InterruptedException e) {
e.printStackTrace();
}
return view;
}
private void readUsers() throws InterruptedException {
StitchAppClient stitchAppClient = Stitch.getDefaultAppClient();
RemoteMongoClient client = stitchAppClient.getServiceClient(RemoteMongoClient.factory, "mongodb-atlas");
RemoteMongoCollection db = client.getDatabase("db").getCollection("Users");
RemoteFindIterable docs = db.find();
docs.forEach(new Block<Document>() {
@Override
public void apply(Document document) {
username = document.getString("username");
imageURL = document.getString("imageURL");
Log.d("rrrrrrrr", "apply: " + username + imageURL);
User user = new User(username, imageURL);
mUsers.add(user);
Log.d("rrrrrrrr", "apply: " + mUsers);
}
});
userAdapter = new UserAdapter(getContext(), mUsers);
recyclerView.setAdapter(userAdapter);
}
}
Luego he intentado depurar el código y poner un punto de interrupción en estas líneas
userAdapter = new UserAdapter(getContext(), mUsers);
recyclerView.setAdapter(userAdapter);
Y la lista se presentó. Yo no sé lo que pasó, así que quitaron los puntos de interrupción y el código no estaba trabajando. Entonces intentado añadir un punto de interrupción en el
username = document.getString("username");
y lo ejecuto a través de cada línea y he encontrado nunca se va a las líneas mencionadas anteriormente. La lista todavía no estaba mostrando. He intentado poner
Thread.yield();
Entre las líneas, pero nada funcionó. Incluso he intentado poner esas líneas entre
getActivity.runOnUiThread(){new Runnable{...}}
Pero no funciona. Por favor ayuda. Gracias.
No han trabajado con MongoDB, pero parece que db.find()
devuelve una colección de algún tipo de promesas, y su apply(Document doc)
son devoluciones de llamada asincrónicas. Eso significa que su userAdapter siempre se construye con matriz vacía.
Pero funciona en modo de depuración debido a las devoluciones de llamada asincrónicas han trabajado y valores de retorno en el momento en que haga clic en el botón "Paso" en la línea de construcción adaptador.
No se pudo encontrar la documentación para ello (ni siquiera existe eso?), Por lo que añade al proyecto y encontré que se puede añadir OnCompleteListener
a la RemoteFindIterable
. Ese debe ser el lugar para hacer un adaptador.
docs.forEach(new Block<Document>() {
@Override
public void apply(Document document) {
username = document.getString("username");
imageURL = document.getString("imageURL");
User user = new User(username, imageURL);
mUsers.add(user);
}
}).addOnSuccessListener(new OnSuccessListener() {
@Override
public void onSuccess(Object o) {
userAdapter = new UserAdapter(getContext(), mUsers);
recyclerView.setAdapter(userAdapter);
}
});
Además, considerar la fijación de un adaptador para RecyclerView
en onCreateView
, pero en onSuccessListener
llamar notifyDataSetChanged()
en él.