This is my ArrayAdapter:
public class SackViewAdapter extends ArrayAdapter<PostInfo> {
private ArrayList<PostInfo> postInfo;
private Context context;
private LayoutInflater inflater;
public SackViewAdapter(#NonNull Context context, int resource,ArrayList<PostInfo> postInfo) {
super (context, resource);
this.context = context;
this.postInfo = postInfo;
inflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
Log.e ("Size", String.valueOf (postInfo.size ()));
return postInfo.size ();
}
#Nullable
#Override
public PostInfo getItem(int i) {
return postInfo.get (i);
}
#NonNull
#Override
public View getView(int i, View view, #NonNull ViewGroup parent) {
view = inflater.inflate (R.layout.card_sack_view, parent,false);
SelectableRoundedImageView imageView = view.findViewById (R.id.image_view);
TextView name = view.findViewById (R.id.nameCards);
TextView username = view.findViewById (R.id.usernameCards);
imageView.setDrawingCacheEnabled (true);
name.setText (postInfo.get (i).name);
username.setText (postInfo.get (i).username);
try{
Glide.with (context).load (postInfo.get (i).Url).into (imageView);
}catch (Exception e){
Toast.makeText (context, e.getMessage (), Toast.LENGTH_SHORT).show ();
}
Log.e ("i", String.valueOf (i));
return view;
}
}
This is my Main Activity:
public class WallActivity extends AppCompatActivity {
FloatingActionButton newFloatingButton;
SackViewAdapter baseAdapter;
ArrayList<PostInfo> postInfos;
DatabaseReference reference = FirebaseDatabase.getInstance ().getReference ();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_wall);
postInfos = new ArrayList<PostInfo> ();
String isDirectly = getIntent ().getStringExtra ("directly");
if(isDirectly.equals ("yes")){
AuthAsyncTask authAsyncTask = new AuthAsyncTask (WallActivity.this);
authAsyncTask.execute ();
}
getData ();
CardStackView cardStackView = findViewById(R.id.cardView);
newFloatingButton = findViewById(R.id.newFloatingButton);
newFloatingButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(WallActivity.this, NewItemActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.slide_up, R.anim.slide_down);
}
});
cardStackView.setCardEventListener(new CardStackView.CardEventListener() {
#Override
public void onCardDragging(float percentX, float percentY) {
}
#Override
public void onCardSwiped(SwipeDirection direction) {
}
#Override
public void onCardReversed() {
}
#Override
public void onCardMovedToOrigin() {
}
#Override
public void onCardClicked(int index) {
Toast.makeText(WallActivity.this, "Clicked", Toast.LENGTH_SHORT).show();
}
});
baseAdapter = new SackViewAdapter (WallActivity.this,android.R.layout.simple_list_item_1, postInfos);
cardStackView.setAdapter(baseAdapter);
}
public void getData(){
reference.addValueEventListener (new ValueEventListener () {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
DataSnapshot posts = dataSnapshot.child ("Posts");
for (DataSnapshot time: posts.getChildren ()){
DataSnapshot url = time.child ("Url");
DataSnapshot name = time.child ("Name");
DataSnapshot username = time.child ("Username");
DataSnapshot date = time.child ("Date");
PostInfo postInfo = new PostInfo (String.valueOf (url.getValue ()), String.valueOf (name.getValue ()), String.valueOf (username.getValue ()), String.valueOf (date.getValue ()));
postInfos.add (postInfo);
}
baseAdapter.notifyDataSetChanged ();
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText (WallActivity.this, "Error 411: " + databaseError.getMessage (), Toast.LENGTH_SHORT).show ();
}
});
}
}
When I get all the data from getData() function I update my Array Adapter but after updating real size of the array list comes out to be 7 but the getView function takes the value of i from 0 to 2 only. It is not adding all the values from the ArrayList and it is showing same values again and again rather than showing different values.This is the log when the screen loads as I have added Log.e in getView:
04-06 13:04:26.797 10246-10246/lifeline.learn.com.hotornot E/Value of i: 0
04-06 13:04:26.804 10246-10246/lifeline.learn.com.hotornot E/Value of i: 1
04-06 13:04:26.814 10246-10246/lifeline.learn.com.hotornot E/Value of i: 2
It is not going over 2. But when I Log in getCount it returns 7.
Currently, your adapter's getCount() returns the size of urls.size (); but you are passing other 2 arraylists as well, which will only take the size of urls arraylist.
If you pass an Arraylist<UserObject>, you could add all the data to this object and then return the size as userObjects.size();
So the better approach would be to create an object, say UserObject and create an arraylist with this object like Arraylist<UserObject>
UserObject.java
public class UserObject {
String urls;
String names;
String usernames;
String dates;
public UserObject(String urls, String names, String usernames, String dates) {
this.urls = urls;
this.names = names;
this.usernames = usernames;
this.dates = dates;
}
}
Declare an arraylist
ArrayList<UserObject> userData=new ArrayList<>();
Now, change like this
public void onDataChange(DataSnapshot dataSnapshot) {
DataSnapshot posts = dataSnapshot.child ("Posts");
for (DataSnapshot time: posts.getChildren ()){
DataSnapshot url = time.child ("Url");
DataSnapshot name = time.child ("Name");
DataSnapshot username = time.child ("Username");
DataSnapshot date = time.child ("Date");
UserObject user=new UserObject(String.valueOf (url.getValue ()),String.valueOf (name.getValue ()),String.valueOf (username.getValue ()),String.valueOf (date.getValue ()));
userData.add(user);
}
baseAdapter.notifyDataSetChanged ();
}
Your adapter constructor will be like this
public SackViewAdapter(#NonNull Context context, int resource,ArrayList<UserObject> userObjects)
Please do not call these in getData()
You have already initialised it onCreate(), and addValueEventListener is called everytime there is a change
urls.clear ();
usernames.clear ();
dates.clear ();
times.clear ();
Also Its better if you use custom object arraylist rather than using three separate lists of type string and manage them
check your url size if their size two then take only 0 to 2.
because you add in adapter in size..
#Override
public int getCount() {
return urls.size (); // in that provide large size of your data.
}
then after when you bind adapter then after used ..
notifyDataSetChanged ();
Related
I'm creating a simple chat app wherein every chatbubbles will be shown in a RecyclerView, now I noticed that every time ill enter a new data coming from Firebase RealTime Database, the old data's / or let's say the old chat bubbles will disappear and reappear once the newly added data has been displayed. I would like the old chat bubbles to not behave just like that, I would like it to remain appeared the whole time.
Here's my method to load every chatbubbles:
private void LoadChat() {
Query orderPosts = ChatRef.orderByChild("servertimestamp");
options = new FirebaseRecyclerOptions.Builder<Chat>().setQuery(orderPosts, Chat.class).build();
adapter = new FirebaseRecyclerAdapter<Chat, MyViewHolder12>(options) {
#Override
protected void onBindViewHolder(#NonNull MyViewHolder12 holder, int position, #NonNull Chat model) {
final String userpower = model.getPower();
final String pow = "Admin";
if (userpower.equals(pow)){
holder.chat_userpower.setVisibility(View.VISIBLE);
holder.chat_userpower.setText(model.getPower());
}
else{
holder.chat_userpower.setVisibility(View.GONE);
}
final String quotedc = model.getQuotedchat();
final String quotedn = model.getQuotedname();
if (quotedc == null){
holder.quotedchatbox.setVisibility(View.GONE);
holder.quotedchatboxlayout.setVisibility(View.GONE);
holder.quotedchatdescription.setVisibility(View.GONE);
}
else{
holder.quotedchatboxlayout.setVisibility(View.VISIBLE);
holder.quotedchatbox.setVisibility(View.VISIBLE);
holder.quotedchatdescription.setVisibility(View.VISIBLE);
holder.quotedchatdescription.setText("Quoted "+ model.getQuotedname() +" " + model.getQuotedchat());
}
holder.chat_usercomment.setText(model.getChat());
Picasso.get().load(model.getProfileimage()).placeholder(R.drawable.profile).into(holder.chat_userimage);
holder.chat_userdep.setText(model.getDep());
holder.chat_date.setText(model.getDate());
holder.chat_username.setText(model.getUsername());
holder.nestedchat_reply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
quote = true;
quotedname = model.getUsername();
//CommentKey = getRef(holder.getAdapterPosition()).getKey();
quoting.setVisibility(View.VISIBLE);
quotedchat = model.getChat();
quoting.setText("Quoting "+ quotedname + ": " + model.getChat());
quoting.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
quote = false;
quoting.setVisibility(View.GONE);
}
});
}
});
}
#NonNull
#Override
public MyViewHolder12 onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.allchatlayout, parent, false);
return new MyViewHolder12(view);
}
};
adapter.startListening();
allchatlist.setAdapter(adapter);
}
here's my layoutmanager:
LinearLayoutManager lm = new LinearLayoutManager(this);
lm.setReverseLayout(false);
lm.setStackFromEnd(false);
allchatlist.setNestedScrollingEnabled(false);
allchatlist.setLayoutManager(lm);
here's my code calling the method:
ChatRef = FirebaseDatabase.getInstance().getReference().child("Forums").child(ChatRoomNameKey).child("Forum ChatRoom");
ChatRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()){
LoadChat();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
To achieve that you will have to use RecyclerView DiffUtill class, more info here:
https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil
In a nutshell you have to create a diff util class:
class CustomItemDiffUtils(
private val oldList: List<CustomItem>,
private val newList: List<CustomItem>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].data == newList[newItemPosition].data
}
}
And use this diff class in your adapter fro example with a method which can be called from the view:
fun updateList(newList: List<CustomItem>) {
val diffResult = DiffUtil.calculateDiff(CustomItemDiffUtils(oldList, newList))
oldList = newList
diffResult.dispatchUpdatesTo(this)
}
Hope this helps.
I fixed the problem by removing the line:
Query orderPosts = ChatRef.orderByChild("servertimestamp");
options = new FirebaseRecyclerOptions.Builder<Chat>().setQuery(orderPosts, Chat.class).build();
Removing that 2 lines of code from that method and putting it somewhere else inside the Activity fixed the blinking problem of my app when a new data has been added.
How do I remove all null and empty string values from an object in JSON java android from retrofit?
Filter out any items where "name" is blank or null.
this is my Main Activity
Api api = retrofit.create(Api.class);
Call<List<MainData>> call = api.getData();
call.enqueue(new Callback<List<MainData>>() {
#Override
public void onResponse (Call<List<MainData>> call, Response<List<MainData>> response) {
if (!response.isSuccessful()) {
Toast.makeText(MainActivity.this, response.code(), Toast.LENGTH_SHORT).show();
return;
}
List<MainData> postList = response.body();
// Filter out any items where "name" is blank or null.
List<MainData> tempList = new ArrayList<>();
for(MainData data :postList)
{
if(null!= data.getName() && !data.getName().isEmpty()) {
//sort by name
Collections.sort(tempList, (mainData, t1) -> mainData.getName().compareTo(t1.getName()));
//sort by ListId
Collections.sort(tempList, (mainData, t1) -> mainData.getListId().compareTo(t1.getListId()) );
tempList.add(data);
}
}
RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(tempList, MainActivity.this);
recyclerView.setAdapter(recyclerViewAdapter);
}
#Override
public void onFailure (Call<List<MainData>> call, Throwable t) {
Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
This Is My Adpater
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
//initialize variables
List<MainData> dataArrayList;
Context context;
//create constructor
public RecyclerViewAdapter (Context context, List<MainData> dataArrayList) {
this.dataArrayList = dataArrayList;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder (#NonNull ViewGroup parent, int viewType) {
//this method recycling the view holder
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder (#NonNull ViewHolder holder, int position) {
//initialize Main data
MainData data = dataArrayList.get(position);
//set name on text view
holder.listId.setText(String.format("list_id : %s", data.getListId()));
holder.name.setText(String.format("name : %s", data.getName()));
holder.id.setText(String.format("id : %s", data.getId()));
}
#Override
public int getItemCount () {
return dataArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
//initialize variables
TextView listId, name, id;
public ViewHolder (#NonNull View itemView) {
super(itemView);
//assign variables
listId = itemView.findViewById(R.id.list_id);
name = itemView.findViewById(R.id.name);
id = itemView.findViewById(R.id.id);
}
}
}
this is the Data
public class MainData {
public String listId, name, id;
public String getListId () {
return listId;
}
public String getName () {
return name;
}
public String getId () {
return id;
}
}
And this is the Api
public interface Api {
#GET("hiring.json")
Call<List<MainData>> getData();
}
And this is my app I want to remove nulls and emp
enter image description here
There are two ways
(1) While inflating the data you can filter these unwanted values
(2) Create a temporary list and add only required values from the main list.
sample code:
List<MainData> tempList = new ArrayList<>();
for(MainData data :postList)
{
if(null!= data.getName() && !data.getName().isEmpty())
{ tempList.add(data);
}
}
And then pass this tempList to the adapter.
Final code would look like this.
Api api = retrofit.create(Api.class);
Call<List<MainData>> call = api.getData();
call.enqueue(new Callback<List<MainData>>() {
#Override
public void onResponse (Call<List<MainData>> call, Response<List<MainData>> response) {
if (!response.isSuccessful()) {
Toast.makeText(MainActivity.this, response.code(), Toast.LENGTH_SHORT).show();
return;
}
List<MainData> postList = response.body();
//sort by ListId
Collections.sort(postList, (mainData, t1) -> mainData.getListId().compareTo(t1.getListId()));
// Filter out any items where "name" is blank or null.
List<MainData> tempList = new ArrayList<>();
for(MainData data :postList)
{
if(null!= data.getName() && !data.getName().isEmpty())
{ tempList.add(data);
}
}
RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(MainActivity.this, tempList );
recyclerView.setAdapter(recyclerViewAdapter);
}
#Override
public void onFailure (Call<List<MainData>> call, Throwable t) {
Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
Feel free to ask if something is unclear.
I am retrieving all the users from firebase database and displaying them in a recyclerView. It displays the town,username and image. I am able to retrieve but it only displays one user instead of all the users.The database has many users but only one is being displayed.Any suggestions will really help.
Here is the bit that retrieves the users
public void showUsersList() {
mdatabaseRef = FirebaseDatabase.getInstance ().getReference ( "Users" );
mdatabaseRef.addValueEventListener ( new ValueEventListener () {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mcontacts.clear ();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren ()) {
Contacts contactsz = dataSnapshot1.getValue (Contacts.class);
mcontacts.add ( contactsz );
}
mAdapter = new UsersAdapter ( getApplicationContext () , mcontacts );
recyclerView.setAdapter ( mAdapter );
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText ( FindFriendsActivity.this , " " , Toast.LENGTH_SHORT ).show ();
}
}
}
This the Adapter class
private Context mcontext;
private List<Contacts> mcontacts;
public UsersAdapter(Context context, List<Contacts> contacts){
mcontext = context;
mcontacts = contacts;
}
#NonNull
#Override
public UsersViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup , int i) {
View v = LayoutInflater.from ( mcontext ).inflate ( R.layout.users_display_layout, viewGroup, false );
return new UsersViewHolder ( v );
}
#Override
public void onBindViewHolder(#NonNull UsersViewHolder usersViewHolder , int i) {
Contacts contactsCurrent = mcontacts.get ( i );
usersViewHolder.nameOfUser.setText ( contactsCurrent.getName () );
usersViewHolder.nameOfTown.setText ( contactsCurrent.getTownname () );
Picasso.get ().load ( contactsCurrent.getImage () ).into ( usersViewHolder.usersImage );
}
#Override
public int getItemCount() {
return mcontacts.size ();
}
public class UsersViewHolder extends RecyclerView.ViewHolder{
public TextView nameOfUser;
public TextView nameOfTown;
public CircleImageView usersImage;
public UsersViewHolder(#NonNull View itemView) {
super ( itemView );
nameOfUser = itemView.findViewById ( R.id.user_profile_name );
nameOfTown = itemView.findViewById ( R.id.user_town_name );
usersImage = itemView.findViewById ( R.id.users_profile_image );
}
}
}
`````````````````````````````````````````````````````````````````
Here is the Contacts class
public class Contacts {
public String Name,townname,image;
public Contacts(){
}
public Contacts(String name , String townname , String image) {
Name = name;
this.townname = townname;
this.image = image;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getTownname() {
return townname;
}
public void setTownname(String townname) {
this.townname = townname;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
}
[1]: https://i.stack.imgur.com/dFD6z.jpg
I dont think Firebase lets you fetch all User Account info, Here is what i did when working in a project, where I used readtime DataBase to save user information when they signed up in this format(can update info later using Uid), then fetch this database field for recyclerView.
Note : User Authentication UID should be used for fetching data.
also try this method for recyclerView and not onDataChange for this scenario.
mFirebaseDatabaseRef.child("Users").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String retrievename = String.valueOf((String) dataSnapshot.child("Name").getValue());
String retrievecity = String.valueOf((String) dataSnapshot.child("townname").getValue());
String retrieveProfileImage = String.valueOf((String) dataSnapshot.child("image").getValue());
if (!retrievename.equals("null")) {
usersnames.setText ( retrievename );
userstown.setText ( retrievecity );
Picasso.get().load ( retrieveProfileImage ).into ( circleImageView );
}
mAdapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) { }
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) { }
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) { }
#Override
public void onCancelled(DatabaseError databaseError) { }
});
}
For me, I will store all the child item into a list, then pass the list to recyclerView adapter inside onDataChange method.
Edit
From you latest code, you are not adding return object into mcontacts list. Check below code.
for (DataSnapshot npsnapshot : dataSnapshot.getChildren()){
Contacts contacts =npsnapshot.getValue(Contacts.class);
mcontacts.add(contacts); // you miss this line
}
mAdapter = new UsersAdapter ( getApplicationContext () , mcontacts );
recyclerView.setAdapter ( mAdapter );
My suggation is create class of user
class User
{
//filds like name,image etc
}
Now you recyclerView adapter class
class RcUsersAdapter extends RecyclerView.Adapter<RcUsersAdapter.ViewHolder>
{
public ArrayList<User> userList;
public RcUsersAdapter(Context context,ArrayList<Users> userList)
{
this.context = context;
this.userList = userList;
}
//... other methods
}
Know in your Activity or Fragment class initialize the adapter with
RcUsersAdapter rcUsersAdapter = new RcUsersAdapter(context,new ArrayList<User>());
Know when you get the data
rcUsersAdapter.userList.add(UserClassObject);
rcUsersAdapter.notifyItemInserted(rcUsersAdapter.getItemCount());
How about use FirebaseRecyclerAdapter(FirebaseRecyclerOptions).
Your code is not complete as comment #HemendraGangwar. And as #JohnJoe wrote you need to add every child in method onDataChange(). I suggest you to make something like this:
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exist) {
for (DataSnapshot ds : dataSnapshot.getChildren ()){
// Create your object wrapper with fields that you have in db.
MyUser user = ds.getValue(MyUser.class);
// Method in adapter that will add the user to list
// and run notifyItemInserted(insertedPosition);
adapter.addUser(user);
}
}
}
Set your usersnames.setText() via DP ViewHolder in adapter method onBindViewHolder like: holder.usersnames.setText(user.getName());.
I am working on an android application, and I am using Firebase database,
this database showing an Items list.
This is my code.
private DatabaseReference root;
ListView elementList;
ArrayAdapter<mdlItem> adapter;
ArrayList<mdlItem> itemsList;
Context context;
private void loadFireDataBase() {
root = FirebaseDatabase.getInstance().getReference().child("Offers");
root.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Add_Chat(dataSnapshot, "Add");
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Add_Chat(dataSnapshot, "Edit");
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Add_Chat(dataSnapshot , "Delete");
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
//Log.i(tag, "onCreateView");
return creatList(inflater, container);
}
private View creatList(LayoutInflater inflater, #Nullable ViewGroup container) {
loadFireDataBase();
context = getActivity();
itemsList = new ArrayList<mdlItem>();
View view;
view = inflater.inflate(R.layout.freg_main_content, container, false);
elementList = (ListView) view.findViewById(R.id.customListView);
Collections.sort(itemsList, new Comparator<mdlItem>() {
#Override
public int compare(mdlItem data1, mdlItem data2) {
if (data1.getOfferIndex() > data2.getOfferIndex())
return 1;
else
return 0;
}
});
adapter = new offersArrayAdapter(context, R.layout.item_list_layout, itemsList);
elementList.setAdapter(adapter);
elementList.setOnItemClickListener(this);
return view;
}
private void Add_Chat(DataSnapshot dataSnapshot, String theCase) {
Map<String, Object> question = null;
try {
String theOfferCode = dataSnapshot.getKey();
question = (Map<String, Object>) dataSnapshot.getValue();
mdlItem mdl = new mdlItem();
mdl.setOfferCode(theOfferCode);
mdl.setRestCode(Integer.parseInt(String.valueOf(question.get("itemCode"))));
mdl.setRestName(question.get("itmeName").toString());
switch (theCase) {
case "Add":
itemsList.add(mdl);
break;
case "Delete":
itemsList.remove(mdl);
break;
case "Edit":
//??
break;
}
adapter.notifyDataSetChanged();
} catch (Exception ex) {
Toast.makeText(context, ex.getMessage(), Toast.LENGTH_LONG).show();
}
}
The problem is I can't get any node index through 'dataSnapshot' object, to control the list when I make Delete and Update.
And another thing how to use Add_Chat method to add the mdl item in the top of other items list.
I already catch the Edit, delete and add in the database root but I can't control how to use these events in the right way
I think I need to get the 'dataSnapshot' object to remove it or set an update on it, or if there is another solution
Can any one help me in this.
Firebase snapshots are not index-based. If you need a mapping from the key in the database to the index in your adapter, you will need to maintain this mapping yourself.
For a simple version of this, have a look at the FirebaseArray class in the FirebaseUI library. It maintains a list of all snapshots that are currently in the array:
private final List<DataSnapshot> mSnapshots = new ArrayList<>();
And then in the onChildAdded methods adds, determines where the new item fits in the list and adds it:
public void onChildAdded(#NonNull DataSnapshot snapshot, #Nullable String previousChildKey) {
int index = 0;
if (previousChildKey != null) {
index = getIndexForKey(previousChildKey) + 1;
}
mSnapshots.add(index, snapshot);
notifyOnChildChanged(ChangeEventType.ADDED, snapshot, index, -1);
}
It does the equivalent for all other onChild... methods, so that it can look up the index for a specific key when needed with its getIndexForKey method:
private int getIndexForKey(#NonNull String key) {
int index = 0;
for (DataSnapshot snapshot : mSnapshots) {
if (snapshot.getKey().equals(key)) {
return index;
} else {
index++;
}
}
throw new IllegalArgumentException("Key not found");
}
Just For recording, This is the correct solution
int index = -1;
for (mdlItem item: itemsList) {
if (item.getIndex() == mdl.getIndex()) {
index = itemsList.indexOf(item);
}
}
I use Volley in the onCreate of my Activity which gets a string on my server, then I convert this string to an arraylist,checkedContactsAsArrayList, and I pass it over to my custom adapter using sharedpreferences, which does stuff with the arraylist in the listview.
But the custom adapter keeps getting the previous arraylist in sharedpreferences, not the one I've just got from the server. The Volley call is too late or something - I can see in logcat the latest values are put after they are got, if you know what I mean.
For example:
VolleyCall 1 putString: 1,2,3
VolleyCall 2 putString: 4,5,6
VolleyCall 3 putString: 7,8,9
Custom Adapter 1 getString: gets values of the last time app was used
Custom Adapter 2 getString: 1,2,3
Custom Adapter 3 getString: 4,5,6
Any idea how to fix this? I could try doing the Volley call in the getView of my custom adapter but I've read on Stackoverflow that's bad practice.
Here are the relvant parts of my code - I've slimmed it down a bit, as there's a lot of stuff in there irrelevant to this issue.
Here's the code of my activity, ViewContact:
public class ViewContact extends AppCompatActivity implements android.widget.CompoundButton.OnCheckedChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(activity_view_contact);
//selectPhoneContacts is an empty array list that will hold our SelectPhoneContact info
selectPhoneContacts = new ArrayList<SelectPhoneContact>();
listView = (ListView) findViewById(R.id.listviewPhoneContacts);
StringRequest stringRequest = new StringRequest(Request.Method.POST, ViewContact_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//toast the response of ViewContact.php, which has been converted to a
//JSON object by the Php file with JSON encode
Toast.makeText(ViewContact.this, "OnResponse is" + response, Toast.LENGTH_LONG).show();
System.out.println("ViewContact: And the response is " + response);
try {
//checkedContacts is a String
String checkedContacts = responseObject.getString("checkedcontacts");
//convert the checkedContacts string to an arraylist
checkedContactsAsArrayList = new ArrayList<String>(Arrays.asList(checkedcontacts.split(",")));
System.out.println("ViewContact: checkedContactsAsArrayList is " + checkedContactsAsArrayList);
//we want to bring the checkedContactsAsArrayList array list to our SelectPhoneContactAdapter.
// It looks like Shared Preferences
//only works easily with strings so best way to bring the array list in Shared Preferences is with
//Gson.
//Here, we PUT the arraylist into the sharedPreferences
SharedPreferences sharedPreferencescheckedContactsAsArrayList = PreferenceManager.getDefaultSharedPreferences(getApplication());
SharedPreferences.Editor editorcheckedContactsAsArrayList = sharedPreferencescheckedContactsAsArrayList.edit();
Gson gsoncheckedContactsAsArrayList = new Gson();
String jsoncheckedContactsAsArrayList = gsoncheckedContactsAsArrayList.toJson(checkedContactsAsArrayList);
editorcheckedContactsAsArrayList.putString("checkedContactsAsArrayList", jsoncheckedContactsAsArrayList);
editorcheckedContactsAsArrayList.commit();
System.out.println("ViewContact: jsoncheckedContactsAsArrayList is " + jsoncheckedContactsAsArrayList);
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(ViewContact.this, error.toString(), Toast.LENGTH_LONG).show();
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
//we are posting review_id into our ViewContact.php file, which
//we get when a row is clicked in populistolistview
//to get matching details
params.put("review_id", review_id);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//checkBoxforContact.setChecked(true);
}
//******for the phone contacts in the listview
// Load data in background
class LoadContact extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
//we want to delete the old selectContacts from the listview when the Activity loads
//because it may need to be updated and we want the user to see the updated listview,
//like if the user adds new names and numbers to their phone contacts.
selectPhoneContacts.clear();
SelectPhoneContact selectContact = new SelectPhoneContact();
selectContact.setName(phoneNameofContact);
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
adapter = new SelectPhoneContactAdapter(selectPhoneContacts, ViewContact.this,0);
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
#Override
protected void onResume() {
super.onResume();
// getPrefs();
ViewContact.LoadContact loadContact = new ViewContact.LoadContact();
loadContact.execute();
Toast.makeText(ViewContact.this, "resuming!", Toast.LENGTH_SHORT).show();
}
}
And my custom adapter, SelectPhoneContactAdapter :
public class SelectPhoneContactAdapter extends BaseAdapter {
//define a list made out of SelectPhoneContacts and call it theContactsList
public List<SelectPhoneContact> theContactsList;
//define an array list made out of SelectContacts and call it arraylist
private ArrayList<SelectPhoneContact> arraylist;
Context _c;
ArrayList<String> MatchingContactsAsArrayList;
ArrayList<String> checkedContactsAsArrayList;
ArrayList <String> allNamesofContacts;
String contactToCheck;
//we will run through different logic in this custom adapter based on the activity that is passed to it
private int whichactivity;
String phoneNumberofContact;
String[] phoneNumberofContactStringArray;
String ContactsString;
Intent intent;
public SelectPhoneContactAdapter(final List<SelectPhoneContact> selectPhoneContacts, Context context, int activity) {
theContactsList = selectPhoneContacts;
_c = context;
this.arraylist = new ArrayList<SelectPhoneContact>();
this.arraylist.addAll(theContactsList);
whichactivity = activity;
//we are fetching the array list checkedContactsAsArrayList, created in ViewContact.
//with this we will put a tick in the checkboxes of contacts the review is being shared with
SharedPreferences sharedPreferencescheckedContactsAsArrayList = PreferenceManager.getDefaultSharedPreferences(_c);
Gson gsoncheckedContactsAsArrayList = new Gson();
String jsoncheckedContactsAsArrayList = sharedPreferencescheckedContactsAsArrayList.getString("checkedContactsAsArrayList", "");
Type type2 = new TypeToken<ArrayList<String>>() {
}.getType();
checkedContactsAsArrayList = gsoncheckedContactsAsArrayList.fromJson(jsoncheckedContactsAsArrayList, type2);
System.out.println("SelectPhoneContactAdapter checkedContactsAsArrayList :" + checkedContactsAsArrayList);
}
}
#Override
public int getCount() {
return arraylist.size();
}
#Override
public Object getItem(int i) {
return arraylist.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
static class ViewHolder {
//In each cell in the listview show the items you want to have
//Having a ViewHolder caches our ids, instead of having to call and load each one again and again
TextView title, phone;
CheckBox check;
Button invite;
}
#Override
public View getView(final int i, View convertView, ViewGroup viewGroup) {
//this is the SelectPhoneContact object; consists of textboxes, buttons, checkbox
final SelectPhoneContact data = (SelectPhoneContact) arraylist.get(i);
ViewHolder holder = null;
if (convertView == null) {
//if there is nothing there (if it's null) inflate the view with the layout
LayoutInflater li = (LayoutInflater) _c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.phone_inflate_listview, null);
holder = new ViewHolder();
//So, for example, title is cast to the name id, in phone_inflate_listview,
//phone is cast to the id called no etc
holder.title = (TextView) convertView.findViewById(R.id.name);
holder.phone = (TextView) convertView.findViewById(R.id.no);
holder.invite = (Button) convertView.findViewById(R.id.btnInvite);
holder.check = (CheckBox) convertView.findViewById(R.id.checkBoxContact);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//in the listview for contacts, set the name
holder.title.setText(data.getName());
//in the listview for contacts, set the number
holder.phone.setText(data.getPhone());
holder.check.setTag(data);
return convertView;
}
}
Call this: loadContact.execute();
After you call .commit();
ViewContact.LoadContact loadContact = new ViewContact.LoadContact();
loadContact.execute();