I tried to have in my model the id of the document but when I access it the value of the id is null.
In fragment/activity:
public class MyEventsFragment extends Fragment {
private OnFragmentInteractionListener mListener;
private FirestorePagingAdapter mAdapter;
private FirebaseFirestore mFirebaseFirestore;
public MyEventsFragment() {
// Required empty public constructor
}
public static MyEventsFragment newInstance() {
return new MyEventsFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFirebaseFirestore = FirebaseFirestore.getInstance();
Query query = mFirebaseFirestore.collection("events");
PagedList.Config config = new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setPrefetchDistance(10)
.setPageSize(20)
.build();
FirestorePagingOptions<Event> options = new FirestorePagingOptions.Builder<Event>()
.setLifecycleOwner(this)
.setQuery(query, config, new SnapshotParser<Event>() {
#NonNull
#Override
public Event parseSnapshot(#NonNull DocumentSnapshot snapshot) {
Event evt = new Event(
snapshot.getId(),
snapshot.getString("titre"),
snapshot.getString("sport"),
snapshot.getString("lieu"),
snapshot.get("date", Timestamp.class),
snapshot.get("dateLimit", Timestamp.class));
Log.i("TEST", evt.toString());
return evt;
}
})
.build();
mAdapter = new EventFirestorePagingAdapter(options, getContext());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_list_events, container, false);
RecyclerView mRecyclerView = view.findViewById(R.id.recyclerViewListEvent);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
return view;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
#Override
public void onStart() {
super.onStart();
mAdapter.startListening();
}
#Override
public void onStop() {
super.onStop();
mAdapter.stopListening();
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
}
EventFirestorePagingAdapter (extends FirestorePagingAdapter):
public class EventFirestorePagingAdapter extends FirestorePagingAdapter<Event, EventFirestorePagingAdapter.EventViewHolder> {
private Context mContext;
public EventFirestorePagingAdapter(#NonNull FirestorePagingOptions<Event> options, Context context) {
super(options);
this.mContext = context;
}
public class EventViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView titre, sport, lieu, date;
public EventViewHolder(#NonNull View itemView) {
super(itemView);
titre = itemView.findViewById(R.id.titreRecyclerView);
sport = itemView.findViewById(R.id.sportRecyclerView);
lieu = itemView.findViewById(R.id.lieuRecyclerView);
date = itemView.findViewById(R.id.dateRecyclerView);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
/*for(Map.Entry<String, Object> map: getItem(getAdapterPosition()).getData().entrySet()){
Log.i("TEST", map.getKey());
}*/
Event event = getItem(getAdapterPosition()).toObject(Event.class);
Log.i("TEST", "id = " + event.getId());
Toast.makeText(mContext, "OnClick on position : " + getAdapterPosition() + " \nTest : " + event.getTitre() + "\nId : " + event.getId(), Toast.LENGTH_LONG).show();
}
}
#Override
protected void onBindViewHolder(#NonNull EventViewHolder holder, int position, #NonNull Event model) {
holder.titre.setText(model.getTitre());
holder.sport.setText(model.getSport());
holder.lieu.setText(model.getLieu());
holder.date.setText(model.getDate().toDate().toString());
}
#NonNull
#Override
public EventViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.recyclerview_card_row, viewGroup, false);
return new EventViewHolder(view);
}
}
Event class :
public class Event {
private String id;
private String titre;
private String sport;
private String lieu;
private Timestamp date;
private Timestamp dateLimit;
public Event(){ } // Needed for Firebase
public Event(String id, String titre, String sport, String lieu, Timestamp date, Timestamp dateLimit) {
this.id = id;
this.titre = titre;
this.sport = sport;
this.lieu = lieu;
this.date = date;
this.dateLimit = dateLimit;
}
// ... getters & setters
}
Debug :
1) TEST: Event{id='c5jUGQc4c7SHzbpT6N01', titre='Final PSG/MARSEILLE', sport='Football', lieu='Bercy', date=Timestamp(seconds=1550844000, nanoseconds=0), dateLimit=Timestamp(seconds=1551009600, nanoseconds=0)}
2) TEST: id = null
Firestore database:
Firestore Database
Gist with the same issue
Answer :
SnapshotParser did not work as i expected but i find out how to access to the id of the document in the onClick(). I replaced this line by this following code :
DocumentSnapshot documentSnapshot = getCurrentList().get(getAdapterPosition());
Chat chat = documentSnapshot.toObject(Chat.class);
chat.setId(documentSnapshot.getId());
According to your comment:
yes, but i need to retrieve it later when i click on an item from my recyclerview
Because you are using a FirestorePagingAdapter and you aren't able to use something like this:
String id = getSnapshots().getSnapshot(position).getId(); //Works only with FirestoreRecyclerAdapter
You need to store the id of the document as property of your document. As I see in your Event class, the property id exists but in the database there is no id property that holds the document id. To solve this, you need to pass the id of the document to the Event constructor when you are creating a new object like this:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference eventsRef = rootRef.collection("events");
String id = eventsRef.document().getId();
Event event = new Event(id, titre, sport, lieu, date, dateLimit);
eventsRef.document(id).set(event);
Related
Im creating an app that shows user recipe based on ingredient they have using SpoonAcular API
The app fetched the ingredient user currently have on Firebase Realtime Database and using the data to fetch the recipe. I've created all the adapter needed to fetch the data but the app not showing the recyclerView as its should. Here's my code
RequestManager.java
public class RequestManager {
Context context;
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.spoonacular.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
public RequestManager(Context context){
this.context = context;
}
public void getRecipeByIngredient(RecipeByIngredientListener listener, List <String> IngredientList){
CallRecipeByIngredient callRecipeByIngredient = retrofit.create(CallRecipeByIngredient.class);
Call <List<RecipeIngredResponse>> call = callRecipeByIngredient.callRecipeByIngredient(context.getString(R.string.API), IngredientList, "20");
call.enqueue(new Callback<List<RecipeIngredResponse>>() {
#Override
public void onResponse(Call<List<RecipeIngredResponse>> call, Response<List<RecipeIngredResponse>> response) {
if(!response.isSuccessful()){
listener.didError(response.message());
return;
}
listener.didFetch(response.body(), response.message());
}
#Override
public void onFailure(Call<List<RecipeIngredResponse>> call, Throwable t) {
listener.didError(t.getMessage());
}
});
}
private interface CallRecipeByIngredient{
#GET("recipes/findByIngredients")
Call<List<RecipeIngredResponse>> callRecipeByIngredient(
#Query("apiKey") String apiKey,
#Query("ingredients") List <String> Ingredient,
#Query("number") String number
);
}
}
RecipeByIngredientListener
public interface RecipeByIngredientListener {
void didFetch(List<RecipeIngredResponse> response, String message);
void didError(String message);
}
RecipeByIngredientAdapter
public class RecipeByIngredientAdapter extends RecyclerView.Adapter<RecipeByIngredientViewHolder> {
Context context;
List<RecipeIngredResponse> list;
public RecipeByIngredientAdapter(Context context, List<RecipeIngredResponse> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public RecipeByIngredientViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new RecipeByIngredientViewHolder(LayoutInflater.from(context).inflate(R.layout.list_recipebyingred , parent, false));
}
#SuppressLint("SetTextI18n")
#Override
public void onBindViewHolder(#NonNull RecipeByIngredientViewHolder holder, int position) {
holder.recipeName.setText(list.get(position).title);
holder.missedIngred.setText(list.get(position).missedIngredientCount + " Missed Ingredient");
holder.likes.setText(list.get(position).likes + " Likes");
Picasso.get().load(list.get(position).image).into(holder.recipeImage);
}
#Override
public int getItemCount() {
return list.size();
}
}
class RecipeByIngredientViewHolder extends RecyclerView.ViewHolder{
ImageView recipeImage;
TextView recipeName, missedIngred, likes;
public RecipeByIngredientViewHolder(#NonNull View itemView) {
super(itemView);
recipeImage = itemView.findViewById(R.id.recipeImage);
recipeName = itemView.findViewById(R.id.recipeName);
missedIngred = itemView.findViewById(R.id.missedIngred);
likes = itemView.findViewById(R.id.likes);
}
}
Home.java (Fragment)
RandomRecipeAdapter randomRecipeAdapter;
RequestManager manager;
RecyclerView recyclerView, recyclerFromYourFridge;
RecipeByIngredientAdapter recipeByIngredientAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_home, container, false);
manager = new RequestManager(getContext());
manager.getRandomRecipe(randomRecipeResponseListener);
recyclerFromYourFridge = (RecyclerView) v.findViewById(R.id.recyclerFromYourFridge);
//get ingredient from database
List<String> Ingredient = new ArrayList<>();
FirebaseAuth mAuth = FirebaseAuth.getInstance();
String currentUser = mAuth.getCurrentUser().getUid();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Ingredient").child(currentUser);
reference.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if(task.isSuccessful()){
for (DataSnapshot userSnapshot : task.getResult().getChildren()){
Ingredient.add(userSnapshot.getKey());
}
}
}
});
manager.getRecipeByIngredient(recipeByIngredientListener , Ingredient);
recyclerView = (RecyclerView) v.findViewById(R.id.randomRecipeRecycler);
return v;
}
private final RecipeByIngredientListener recipeByIngredientListener = new RecipeByIngredientListener() {
#Override
public void didFetch(List<RecipeIngredResponse> response, String message) {
recyclerFromYourFridge.setHasFixedSize(true);
recyclerFromYourFridge.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
recipeByIngredientAdapter = new RecipeByIngredientAdapter(getContext(), response);
recyclerFromYourFridge.setAdapter(recipeByIngredientAdapter);
}
#Override
public void didError(String message) {
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
}
};
Pretty sure there's nothing wrong with the app fetching ingredient from Firebase cause i've tested it and the api capable to get recipe by using ArrayList. Is there anything wrong with this code?
The issue is because calls to the Firebase database are asynchronous, if you call the value outside of addOnCompleteListener can be empty
Change the reference.get().addOnCompleteListener to:
reference.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if(task.isSuccessful()){
List<String> Ingredient = new ArrayList<>();
for (DataSnapshot userSnapshot : task.getResult().getChildren()){
Ingredient.add(userSnapshot.getKey());
}
manager.getRecipeByIngredient(recipeByIngredientListener , Ingredient);
}
}
});
Basically, what I am trying to do is use a FirebaseRecyclerAdapter and populate the RecyclerView with my custom designed CardView. The code for newer versions has been changed and therefore, I tried implementing it but didn't work.
This is the code I use to write a year ago, which worked fine and populated my RecyclerView:
FirebaseRecyclerAdapter<DataClass,DataViewHolder> FBRA= new FirebaseRecyclerAdapter<DataClass, DataViewHolder>(
DataClass,
R.layout.myCardView,
DataViewHolder.class,
databaseReference
) {
#Override
protected void populateViewHolder(DataViewHolder viewHolder, DataClass model, int position) {
viewHolder.setTitle(model.gettitle());
viewHolder.setDate(model.getDate());
}
};
myRecyclerView.setAdapter(FBRA);
And now we have to use something like this,
but the problem is this code is not populating my recyclerView (What changes do I need to make here to populate my recyclerView with my cardView?)
#Override
protected void onStart() {
super.onStart();
Query query = FirebaseDatabase.getInstance()
.getReference()
.child("Official_Services");
FirebaseRecyclerOptions<ServiceClass> options = new FirebaseRecyclerOptions.Builder<ServiceClass>()
.setQuery(query, ServiceClass.class)
.build();
FirebaseRecyclerAdapter<ServiceClass, ServiceViewHolder> FBRA = new FirebaseRecyclerAdapter<ServiceClass, ServiceViewHolder>(options) {
#NonNull
#Override
public ServiceViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
View view = LayoutInflater.from(HomeActivity.this).inflate(R.layout.service_card, parent, false);
return new ServiceViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull ServiceViewHolder holder, int position, #NonNull ServiceClass model) {
holder.setServiceName(model.getServiceName());
holder.setServiceCaption(model.getServiceCaption());
}
};
mServiceList.setAdapter(FBRA);
}
Here is my ViewHolder class:
public static class ServiceViewHolder extends RecyclerView.ViewHolder {
public ServiceViewHolder(View itemView) {
super(itemView);
View mView = itemView;
}
public void setServiceName(String serviceName) {
TextView sName = itemView.findViewById(R.id.serviceName);
sName.setText(serviceName);
}
public void setServiceCaption(String serviceCaption) {
TextView sCaption = itemView.findViewById(R.id.serviceCap);
sCaption.setText(serviceCaption);
}
}
And this is my Model class of getters and setters:
public class ServiceClass {
private String serviceName;
private String serviceCode;
private String serviceCaption;
private String serviceIconUrl;
public ServiceClass() {
}
public ServiceClass(String serviceName, String serviceCode, String serviceCaption, String serviceIconUrl) {
this.serviceName = serviceName;
this.serviceCode = serviceCode;
this.serviceCaption = serviceCaption;
this.serviceIconUrl = serviceIconUrl;
}
public String getServiceName() {
return serviceName;
}
public String getServiceCode() {
return serviceCode;
}
public String getServiceCaption() {
return serviceCaption;
}
public String getServiceIconUrl() {
return serviceIconUrl;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public void setServiceCode(String serviceCode) {
this.serviceCode = serviceCode;
}
public void setServiceCaption(String serviceCaption) {
this.serviceCaption = serviceCaption;
}
public void setServiceIconUrl(String serviceIconUrl) {
this.serviceIconUrl = serviceIconUrl;
}
#Override
public String toString() {
return "ServiceClass{" +
"serviceName='" + serviceName + '\'' +
", serviceCode='" + serviceCode + '\'' +
", serviceCaption='" + serviceCaption + '\'' +
", serviceIconUrl='" + serviceIconUrl + '\'' +
'}';
}
}
Now what changes do I need to do?
Here is my entire java file:
public class HomeActivity extends AppCompatActivity {
private RecyclerView mServiceList;
private FirebaseDatabase mDatabase;
private DatabaseReference myRef;
FirebaseRecyclerAdapter<ServiceClass, ServiceViewHolder> FBRA;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
BottomNavigationViewEx bottomNavigationViewEx = findViewById(R.id.navViewBar);
bottomNavigationViewEx.enableAnimation(false);
bottomNavigationViewEx.enableShiftingMode(false);
bottomNavigationViewEx.setTextVisibility(false);
Calligrapher calligrapher = new Calligrapher(this);
calligrapher.setFont(this, "Helvetica.ttf", true);
mServiceList = findViewById(R.id.serviceRV);
mServiceList.setHasFixedSize(true);
mServiceList.setLayoutManager(new LinearLayoutManager(this));
mDatabase = FirebaseDatabase.getInstance();
myRef = mDatabase.getReference().child("Official_Services");
}
#Override
protected void onStart() {
super.onStart();
FBRA.startListening();
Query query = myRef;
FirebaseRecyclerOptions<ServiceClass> options = new FirebaseRecyclerOptions.Builder<ServiceClass>()
.setQuery(query, ServiceClass.class)
.build();
FBRA = new FirebaseRecyclerAdapter<ServiceClass, ServiceViewHolder>(options) {
#NonNull
#Override
public ServiceViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
View view = LayoutInflater.from(HomeActivity.this).inflate(R.layout.service_card, parent, false);
return new ServiceViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull ServiceViewHolder holder, int position, #NonNull ServiceClass model) {
holder.setServiceName(model.getServiceName());
holder.setServiceCaption(model.getServiceCaption());
}
};
mServiceList.setAdapter(FBRA);
}
public static class ServiceViewHolder extends RecyclerView.ViewHolder {
public ServiceViewHolder(View itemView) {
super(itemView);
View mView = itemView;
}
public void setServiceName(String serviceName) {
TextView sName = itemView.findViewById(R.id.serviceName);
sName.setText(serviceName);
}
public void setServiceCaption(String serviceCaption) {
TextView sCaption = itemView.findViewById(R.id.serviceCap);
sCaption.setText(serviceCaption);
}
}
}
In order to be able to display data from the Firebase realtime database you need to start listening for changes and for that you should add the following line of code in the onStart() method:
#Override
protected void onStart() {
super.onStart();
FBRA.startListening();
}
To stop listening foir changes you need add the following line of code in the onStop() method like this:
#Override
protected void onStop() {
super.onStop();
if(FBRA != null) {
FBRA.stopListening();
}
}
Please see my answer from this post where I have explained why you should remove the listener.
P.S. Please also don't forget to make the FBRA a global variable and remove FirebaseRecyclerAdapter<ServiceClass, ServiceViewHolder> from the declaration of the object.
This is more of an advice. If you want to continue using the old method to populate your
recyclerview ie The "populateViewHolder" method instead of the new "onBindViewHolder" method just use this;
implementation 'com.firebaseui:firebase-ui:1.0.1'
instead of upgraded firebase-ui versions
I did the code below, used the adapter to show the list, and a button to add a comment to list item, it shows the logcat "ViewPostIme pointer 0 and ViewPostIme pointer 1", upon clicking the comment button.
Upon compilation it doesn't show any error, I tried to use many references via google but nothing works out.
My basic idea is to call the comment button with an associated list item to perform the comment activity.
Adapter class
public class PostsAdapter extends FirestoreRecyclerAdapter<PostsModel, PostsAdapter.PostsHolder> {
private OnItemClickListener listener;
private View.OnClickListener buttonListener;
private String id;
private static final String TAG = "DocSnippets";
public PostsAdapter(#NonNull FirestoreRecyclerOptions<PostsModel> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull PostsHolder holder, int position, #NonNull PostsModel model) {
//retrieve the fields here
holder.textViewDescription.setText(model.getPostContent());
holder.textViewPriority.setText(String.valueOf(model.getSpinnerC()));
holder.textViewPriority.setText(String.valueOf(model.getTimestamp()));
}
#NonNull
#Override
public PostsHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_list_layout,
parent, false);
return new PostsHolder(v);
}
public void deleteItem(int position) {
getSnapshots().getSnapshot(position).getReference().delete();
}
public void setOnClickListener(OnClickListener postKey) {
}
class PostsHolder extends RecyclerView.ViewHolder {
//first declare here the elements to be displayed in the cardview.
TextView textViewTitle;
TextView textViewDescription;
TextView textViewPriority;
Button commentsbutton;
public PostsHolder(final View itemView) {
super(itemView);
textViewTitle = itemView.findViewById(R.id.post_etPostTitle);
textViewDescription = itemView.findViewById(R.id.post_description);
textViewPriority = itemView.findViewById(R.id.post_time);
commentsbutton = itemView.findViewById(R.id.commenting_button);
commentsbutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION && buttonListener != null) {
buttonListener.onClick(itemView);
}
}
});
}
}
public interface OnClickListener
{
void OnClickListener(DocumentSnapshot documentSnapshot, int position);
}
public void setOnClickListener(View.OnClickListener onClickListener) {
this.buttonListener = onClickListener;
}
public interface OnItemClickListener {
void onItemClick(DocumentSnapshot documentSnapshot, int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
}
Fragment Class
public class HomeFragment extends Fragment {
RelativeLayout mParent;
//FloatingActionButton addButton;
private static final String TAG = "DocSnippets";
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private CollectionReference PostsRef = db.collection("posts");
private PostsAdapter adapter;
private FirestoreRecyclerOptions options;
private FirebaseAuth mAuth;
private String mUserId, id;
private Button commentsbutton;
RecyclerView recyclerView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
//just change the fragment_dashboard
//with the fragment you want to inflate
//like if the class is HomeFragment it should have R.layout.home_fragment
//if it is DashboardFragment it should have R.layout.fragment_dashboard
View view = inflater.inflate(R.layout.fragment_home, container, false);
final FragmentActivity c = getActivity();
LinearLayoutManager layoutManager = new LinearLayoutManager(c);
Query query = PostsRef.orderBy("timestamp", Query.Direction.DESCENDING);
FirestoreRecyclerOptions<PostsModel> options = new FirestoreRecyclerOptions.Builder<PostsModel>()
.setQuery(query, PostsModel.class)
.build();
adapter = new PostsAdapter(options);
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(c));
recyclerView.setAdapter(adapter);
commentsbutton = (Button) view.findViewById(R.id.commenting_button);
mParent =view.findViewById(R.id.relative_home);
mAuth = FirebaseAuth.getInstance();
mUserId = mAuth.getUid();
adapter.setOnItemClickListener(new PostsAdapter.OnItemClickListener() {
#Override
public void onItemClick(DocumentSnapshot documentSnapshot, int position) {
PostsModel note = documentSnapshot.toObject(PostsModel.class);
id = documentSnapshot.getId();
String path = documentSnapshot.getReference().getPath();
Log.d(TAG, "String post Id is: " + id);
}
});
adapter.setOnClickListener(new PostsAdapter.OnClickListener() {
#Override
public void OnClickListener(DocumentSnapshot documentSnapshot, int position) {
PostsModel note = documentSnapshot.toObject(PostsModel.class);
id = documentSnapshot.getId();
String path = documentSnapshot.getReference().getPath();
Log.d(TAG, "String post Id is: " + id);
Intent toCommentActivity = new Intent(getContext(), CommentActivity.class);
toCommentActivity.putExtra("PostKey", id);
getContext().startActivity(toCommentActivity);
}
});
return view;
}
private String getTime(long timestamp){
long ts = timestamp*1000;
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm a");
String time = sdf.format(new Date(ts));
return time;
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
}
I'm using a Cloud Firestore database to populate a RecyclerView in an Android app. I'm getting the data by using a Task in the onAttach method of a Fragment. I need to be able to update the UI, the RecyclerView with data from the Cloud Firestore.
I populated the RecyclerView with dummy data in the onAttach method of the Fragment and that worked, but when I put the same loop that inserts dummy data in the onComplete method of a OnCompleteListener that's used in the Task that pulls data from the Cloud Firestore, the RecyclerView doesn't update and the list stays blank. I need to do it there to eventually insert data from the Cloud Firestore.
Within the Fragment. The data coming back from the Firestore database is correct and I see all of the Log statements in the onComplete method in the Logcat.
ChatListFragment:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_chat_list, container, false);
// Set the adapter
if (view instanceof RecyclerView) {
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
if (mColumnCount <= 1) {
recyclerView.setLayoutManager(new LinearLayoutManager(context));
} else {
recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));
}
chatRecyclerViewAdapter = new ChatRecyclerViewAdapter(ChatList.ITEMS, mListener);
recyclerView.setAdapter(chatRecyclerViewAdapter);
}
return view;
}
...
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnListFragmentInteractionListener) {
mListener = (OnListFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnListFragmentInteractionListener");
}
Log.d(LOG_TAG, "activity attached, creating Firestore instance");
FirebaseFirestore db = FirebaseFirestore.getInstance();
//Worked, but doesn't in OnCompleteListener
/*for (int i = 1; i <= 10; i++) {
ChatList.addItem(ChatList.createDummyItem(i));
}*/
Task<QuerySnapshot> task = db.collection("chats").get();
task.addOnCompleteListener(getActivity(), new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
Log.d(LOG_TAG, "ID = " + document.getId() + " => " + document.getData());
ChatListMessage chatListMessage = document.toObject(ChatListMessage.class);
for (int i = 1; i <= 10; i++) {
Log.d(LOG_TAG, "adding message");
ChatList.addItem(ChatList.createDummyItem(i));
}
Log.d(LOG_TAG, "ChatListMessage members " + chatListMessage.getLastMessage());
}
} else {
Log.w(LOG_TAG, "Error getting documents.", task.getException());
}
}
});
}
Within the ChatList class
public static void addItem(ChatListItem item) {
ITEMS.add(item);
ITEM_MAP.put(item.userId, item);
}
public static ChatListItem createDummyItem(int position) {
return new ChatListItem(String.valueOf(position), R.drawable.profile_circle, makeDetails(position),
new Timestamp(System.currentTimeMillis()));
}
public static class ChatListItem {
public final String userId;
public final int pictureUrl;
public final String lastMessage;
public final Timestamp timeStamp;
public ChatListItem(String userId, int pictureUrl, String details, Timestamp timeStamp) {
this.userId = userId;
this.pictureUrl = pictureUrl;
this.lastMessage = details;
this.timeStamp = timeStamp;
}
#Override
public String toString() {
return userId;
}
public Timestamp getTimeStamp() {
return timeStamp;
}
public String getTLastMessage() {
return lastMessage;
}
}
The custom RecyclerViewAdapter
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder> {
private final List<ChatListItem> mValues;
private final OnListFragmentInteractionListener mListener;
public ChatRecyclerViewAdapter(List<ChatListItem> items, OnListFragmentInteractionListener listener) {
mValues = items;
mListener = listener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.fragment_chat, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
holder.contactImageView.setImageResource(mValues.get(position).pictureUrl);
holder.contactImageView.setScaleType(ImageView.ScaleType.FIT_XY);
holder.mContentView.setText(mValues.get(position).lastMessage);
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (null != mListener) {
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mListener.onListFragmentInteraction(holder.mItem);
}
}
});
}
#Override
public int getItemCount() {
return mValues.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public final ImageView contactImageView;
public final TextView messageMembersTextView;
public final TextView mContentView;
public final TextView timestampView;
public ChatListItem mItem;
public ViewHolder(View view) {
super(view);
mView = view;
messageMembersTextView = view.findViewById(R.id.message_members);
contactImageView = view.findViewById(R.id.contact_imageView);
mContentView = view.findViewById(R.id.content_textView);
timestampView = view.findViewById(R.id.timestamp_textView);
}
#Override
public String toString() {
return super.toString() + " '" + mContentView.getText() + "'";
}
}
}
How can I get the UI to be updated with the onComplete method of the OnCompleteListener?
For this, chatRecyclerViewAdapter.notifyDataSetChanged() needs to be called in the onComplete method of the OnCompleteListener. I forgot to do this outside of the listener since it looks like the list items are pulled in after the onAttach method is called.
how to get ID position in call retrofit
GET https://api.themoviedb.org/3/movie/{movie_id}/credits?api_key=<>
i need to get position id send to server in loadCast function
and in MovieService that's retrofit call i need send postion id befor credits
i don't know how to do that if any one can help me thanks so much for that <3
//this my call retrofit server
public interface MovieService {
#GET("popular?" + Common.API_KEY + "&language=en-US")
Call<MoviesList> getPopular(#Query("api_key") String api_key);
#GET( ListMovieAdapter.SELECTED_MOVIE +"/credits?" + Common.API_KEY +
"&language=en-US")
Call<MovieCast> getCast(
#Query("api_key") String api_key);
----------------------------------------------------------------
package com.example.android.movie;
/**
* Created by yuyu on 12-Nov-18.
*/
public class MovieDetails extends YouTubeBaseActivity {
Result selectedMovie;
private ArrayList<Cast> cast;
private RecyclerView.LayoutManager mLayoutManager;
private RecyclerView mRecyclerView;
private CastMovieAdapter castMovieAdapter;
private TextView name;
private ImageView imageMovie;
private TextView date;
private TextView rating;
private ArrayList<Result> results;
MovieService mService;
private static final String YT_API_KEY = "###";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.movie_details);
selectedMovie =
getIntent().getParcelableExtra(ListMovieAdapter.SELECTED_MOVIE);
mRecyclerView = (RecyclerView) findViewById(R.id.cast_recycler);
mLayoutManager = new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(mLayoutManager);
cast = new ArrayList<>();
castMovieAdapter = new CastMovieAdapter(cast, MovieDetails.this);
mRecyclerView.setAdapter(castMovieAdapter);
results = new ArrayList<>();
mService = Common.getMovieService();
loadTriler();
loadMovies();
loadCast();
}
this function to load movie
private void loadMovies() {
mService.getPopular(Common.API_KEY).enqueue(new Callback<MoviesList>()
{
#Override
public void onResponse(Call<MoviesList> call, Response<MoviesList>
response) {
results.clear();
results.addAll(response.body().getResults());
name = (TextView) findViewById(R.id.name_movie);
rating = (TextView) findViewById(R.id.rating);
date = (TextView) findViewById(R.id.date_det);
imageMovie = (ImageView) findViewById(R.id.imageView);
date.setText(selectedMovie.getReleaseDate());
name.setText(selectedMovie.getTitle());
rating.setText(String.valueOf(selectedMovie.getVoteAverage()));
final String image = Common.IMAGE_LOAD +
selectedMovie.getPosterPath();
Picasso.with(MovieDetails.this)
.load(image)
.into(imageMovie);
}
#Override
public void onFailure(Call<MoviesList> call, Throwable t) {
Log.d("===LoadMovies", "onResponse: " + t);
}
});
}
//i have proplem here in send ID postion
private void loadCast() {
mService.getCast(
ListMovieAdapter.SELECTED_MOVIE+Common.API_KEY).enqueue(new
Callback<MovieCast>() {
#Override
public void onResponse(Call<MovieCast> call, final
Response<MovieCast> response) {
cast.clear();
cast.addAll(response.body().getCast());
mRecyclerView.getAdapter().notifyDataSetChanged();
}
#Override
public void onFailure(Call<MovieCast> call, Throwable t) {
}
});
}
}
package com.example.android.movie.Adapter;
/**
* Created by yuyu on 11-Nov-18.
*/
public class ListMovieAdapter extends
RecyclerView.Adapter<ListMovieAdapter.MyViewHolder> {
private ArrayList<Result> mMovies;
private Context context;
public static final String SELECTED_MOVIE = "selected_movie";
private int lastPosition = -1;
public ListMovieAdapter(ArrayList<Result> mMovies, Context context) {
this.mMovies = mMovies;
this.context = context;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.list_views, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
//Animation Scroll
Animation animation = AnimationUtils.loadAnimation(context,
(position > lastPosition) ? R.anim.up_from_bottom
: R.anim.down_from_top);
holder.itemView.startAnimation(animation);
lastPosition = position;
holder.nameMovie.setText(mMovies.get(position).getTitle());
final String image = Common.IMAGE_LOAD +
mMovies.get(position).getPosterPath();
Picasso.with(context)
.load(image)
.into(holder.imageMovie);
holder.rating.setText(String.valueOf(
mMovies.get(position).getVoteAverage()));
holder.dateMovie.setText(mMovies.get(position).getReleaseDate());
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onClick(View view, int position) {
Intent intent = new Intent(context, MovieDetails.class);
Result result = mMovies.get(position);
intent.putExtra(SELECTED_MOVIE, result);
context.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return mMovies.size();
}
class MyViewHolder extends RecyclerView.ViewHolder implements
View.OnClickListener {
ImageView imageMovie;
TextView nameMovie;
TextView rating;
TextView dateMovie;
ItemClickListener itemClickListener;
public MyViewHolder(View itemView) {
super(itemView);
this.imageMovie = (ImageView)
itemView.findViewById(R.id.image_movie);
this.nameMovie = (TextView) itemView.findViewById(R.id.name_movie);
this.rating = (TextView) itemView.findViewById(R.id.rating);
this.dateMovie = (TextView) itemView.findViewById(R.id.date);
itemView.setOnClickListener(this);
}
public void setItemClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
#Override
public void onClick(View v) {
itemClickListener.onClick(v, getAdapterPosition());
}
}
}
From the Retrofit documentation:
URL MANIPULATION A request URL can be updated dynamically using
replacement blocks and parameters on the method. A replacement block
is an alphanumeric string surrounded by { and }. A corresponding
parameter must be annotated with #Path using the same string.
#GET("group/{id}/users")
Call<List<User>> groupList(#Path("id") int groupId);
https://square.github.io/retrofit/