I have an activity for searching in firebase, it contains edittext for typing the text and button when I press the button The results supposed to appear in the recyclerview but when I press the button the first time nothing appears unless I press the button for the second time
the code of findDataActivity
public class FindDataActivity extends AppCompatActivity {
DatabaseReference db;
FirebaseHelper helper;
MyAdapter adapter;
RecyclerView rv;
EditText findETxt;
Button findBtn;
ArrayList<Paints> p;
String s;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_find_data);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//SETUP RECYCLER
rv = (RecyclerView) findViewById(R.id.rvsearch);
rv.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
//INITIALIZE FIREBASE DB
db = FirebaseDatabase.getInstance().getReference("Database");
adapter = new MyAdapter(FindDataActivity.this, p);
rv.setAdapter(adapter);
findBtn = (Button) findViewById(R.id.find_btn);
helper = new FirebaseHelper(db);
}
public void search(View view) {
db.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
findETxt = (EditText) findViewById(R.id.findETxt);
s = findETxt.getText().toString();
p=helper.retrieveSearch(s);
adapter = new MyAdapter(FindDataActivity.this, p);
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id=item.getItemId();
if(id == android.R.id.home){
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}
the code of firebase
public class FirebaseHelper {
DatabaseReference db;
Boolean saved=null;
Boolean saved1=null;
ArrayList<Paints> paints=new ArrayList<>();
ArrayList<String> keys=new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//READ THEN RETURN ARRAYLIST FOR SEARCH ITEMS IN CASE OF SEARCHING ABOUT ITEM
public ArrayList<Paints> retrieveSearch(final String item) {
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchDataSearch(dataSnapshot,item);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchDataSearch(dataSnapshot,item);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return paints;
}
//IMPLEMENT FETCH DATA AND FILL ARRAYLIST FOR SEARCH
private void fetchDataSearch( DataSnapshot dataSnapshot,String item)
{
paints.clear();
//sorting and searching
final DatabaseReference myRef = db.child("items");
Query query = myRef.orderByChild("type").startAt(item)
.endAt(item + "\uf8ff");
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
Paints paint=messageSnapshot.getValue(Paints.class);
paints.add(paint);
//Toast.makeText(FindDataActivity.this, "found " + type + " unit: " + unit + " price " + price, Toast.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
In your MyAdapter class you must create a method like this:
public void updateAdapter(ArrayList<Paints> paint){
this.paint= paint;
notifyDataSetChanged();
}
In your search method replace adapter.notifyDataSetChanged(); for adapter.updateAdapter(p);
Related
I am currently working on a chat application and have come across an issue. My Chat Fragment contains my Recyclerview which populates data from Firebase DB. I am able to obtain the data, but I am running into an issue. When I open my Chat Activity and send a message, a new push id is created with the information stored in the child. The data obtained by my recyclerview is it gets the last push id and retrieves the last message that was sent. The problem is, when I go back into my fragment, the recyclerview re-populates and adds the new push id last message that was created, and creates another item instead of just refreshing the original item.
So essentially, I will load my app, go into the Chat Fragment, my recyclerview will display the other user and the last message that was sent, no problem, then I will click on that item, open the chat activity, send a message then go back. Now when I am back into the chat fragment I will have two or three or however many messages that were sent displaying in the recyclerview. Not sure on how to fix this, my code is below:
DATABASE STRUCTURE
Chat Fragment
public class Fragment_MatchChats extends Fragment {
private RecyclerView mRecyclerView, mRecyclerViewChat;
private RecyclerView.Adapter mMatchesAdapter, mChatAdapter;
private String currentUserID;
private DatabaseReference mDatabaseChat;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag_match_chat, container, false);
currentUserID = FirebaseAuth.getInstance().getCurrentUser().getUid();
mDatabaseChat = FirebaseDatabase.getInstance().getReference().child("Chat");
LinearLayoutManager layoutManagerChat = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
mRecyclerViewChat = (RecyclerView) v.findViewById(R.id.recyclerViewChat);
mRecyclerViewChat.setHasFixedSize(true);
mRecyclerViewChat.setLayoutManager(layoutManagerChat);
mChatAdapter = new RecyclerViewChatAdapter(getDataSetChat(), getContext());
getUserMatchId();
return v;
}
//this method will get the user ID in the database that you matched with. It will run through the matches child and get all the user IDs
private void getUserMatchId() {
DatabaseReference matchDB = FirebaseDatabase.getInstance().getReference().child("Users").child(currentUserID).child("swipes").child("matches");
matchDB.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
for(DataSnapshot match : dataSnapshot.getChildren()){
CheckChatID(match.getKey());
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void CheckChatID(final String chat) {
DatabaseReference ChatDB = FirebaseDatabase.getInstance().getReference().child("Users").child(currentUserID).child("swipes").child("matches")
.child(chat).child("ChatID");
ChatDB.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
String ChatID = dataSnapshot.getValue().toString();
ChatIDExist(ChatID, chat);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void ChatIDExist(final String chatID, final String oppUserID) {
final DatabaseReference ChatDB = mDatabaseChat.child(chatID);
final Query lastQuery = ChatDB.orderByKey().limitToLast(1);
ChatDB.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
lastQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot child: dataSnapshot.getChildren()){
String key = child.child("text").getValue().toString();
FetchChatInfo(oppUserID,key);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void FetchChatInfo(String key, final String chatID) {
DatabaseReference userDB = FirebaseDatabase.getInstance().getReference().child("Users").child(key);
userDB.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
String matched_userID = dataSnapshot.getKey();
String matches_userName = "";
String matches_userProPic = "";
String match_CHATID = chatID;
if(dataSnapshot.child("name").getValue() != null){
matches_userName = dataSnapshot.child("name").getValue().toString();
}
if(dataSnapshot.child("profilePicURL").getValue() != null){
matches_userProPic = dataSnapshot.child("profilePicURL").getValue().toString();
}
RecyclerViewChatReference chat_obj = new RecyclerViewChatReference(matched_userID, matches_userName, matches_userProPic, match_CHATID);
resultsChats.add(chat_obj);
mRecyclerViewChat.setAdapter(mChatAdapter);
mChatAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private ArrayList<RecyclerViewChatReference> resultsChats = new ArrayList<RecyclerViewChatReference>();
private List<RecyclerViewChatReference> getDataSetChat() {
return resultsChats;
}
Chat Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
matchId = getIntent().getExtras().getString("matchID");
currentUserID = FirebaseAuth.getInstance().getCurrentUser().getUid();
mDatabaseUser = FirebaseDatabase.getInstance().getReference().child("Users").child(currentUserID)
.child("swipes").child("matches").child(matchId).child("ChatID");
mDatabaseChat = FirebaseDatabase.getInstance().getReference().child("Chat");
getChatId();
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setHasFixedSize(false);
mChatLayoutManager = new LinearLayoutManager(ChatActivity.this);
mRecyclerView.setLayoutManager(mChatLayoutManager);
mChatAdapter = new ChatAdapter(getDataSetChat(), ChatActivity.this);
mRecyclerView.setAdapter(mChatAdapter);
mSendEditText = findViewById(R.id.message);
mSendButton = findViewById(R.id.send);
mSendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendMessage();
}
});
}
private void sendMessage() {
String sendMessageText = mSendEditText.getText().toString();
if(!sendMessageText.isEmpty()){
DatabaseReference newMessageDb = mDatabaseChat.push();
Map newMessage = new HashMap();
newMessage.put("createdByUser", currentUserID);
newMessage.put("text", sendMessageText);
newMessageDb.setValue(newMessage);
}
mSendEditText.setText(null);
}
private void getChatId(){
mDatabaseUser.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
chatId = dataSnapshot.getValue().toString();
mDatabaseChat = mDatabaseChat.child(chatId);
getChatMessages();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void getChatMessages() {
mDatabaseChat.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if(dataSnapshot.exists()){
String message = "";
String createdByUser = "";
if(dataSnapshot.child("text").getValue()!=null){
message = dataSnapshot.child("text").getValue().toString();
}
if(dataSnapshot.child("createdByUser").getValue()!=null){
createdByUser = dataSnapshot.child("createdByUser").getValue().toString();
}
if(message!=null && createdByUser!=null){
Boolean currentUserBoolean = false;
if(createdByUser.equals(currentUserID)){
currentUserBoolean = true;
}
ChatObject newMessage = new ChatObject(message, currentUserBoolean);
resultsChat.add(newMessage);
mChatAdapter.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) {
}
});
}
private ArrayList<ChatObject> resultsChat = new ArrayList<ChatObject>();
private List<ChatObject> getDataSetChat() {
return resultsChat;
}
}
I am trying to update a listview realtime from my firebase database. The data uploads to database without any issues and a toast which displays the newly added data also works. But I could not get the listview to work. Here is my code:
public class MainActivity extends AppCompatActivity {
private ListView list;
private Button btnadd;
private EditText ettext;
private DatabaseReference mDatabase;
private ArrayList<String> arrayList= new ArrayList<>();
private ArrayAdapter<String> adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list=findViewById(R.id.liston);
list.setAdapter(adapter);
btnadd=findViewById(R.id.button);
ettext=findViewById(R.id.ed);
btnadd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mDatabase.push().setValue(ettext.getText().toString());
}
});
mDatabase= FirebaseDatabase.getInstance().getReference();
adapter= new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, arrayList);
mDatabase.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String string =dataSnapshot.getValue(String.class);
arrayList.add(string);
adapter.notifyDataSetChanged();
Toast.makeText(getApplicationContext(),
"Name: " + dataSnapshot.getValue(), Toast.LENGTH_LONG)
.show();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
String string =dataSnapshot.getValue(String.class);
arrayList.remove(string);
adapter.notifyDataSetChanged();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
The updation of the database also happens from within the app using an "edittext" and a button.
In below code I am getting list of users by their blood type and locality. This is working very fine. I want to get a list of their tokens. So how can I do that. I try using firebaseRecyclerAdapter.getItemCount() and a loop but it did not help. So what should I do now? I want to put token in an string array.
public class SearchActivity extends AppCompatActivity {
private Toolbar mToolbar;
private String bloodgroup;
private String locality;
private RecyclerView allUsersList;
private Query allDatabaseUserReference;
private String[] TokenList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
bloodgroup = getIntent().getStringExtra("bt");
locality = getIntent().getStringExtra("pa");
allDatabaseUserReference = FirebaseDatabase.getInstance().getReference().child("Users").orderByChild("user_search").equalTo(bloodgroup + ", " + locality);
mToolbar = (Toolbar) findViewById(R.id.search_activity_app_bar);
setSupportActionBar(mToolbar);
getSupportActionBar().setTitle("Search Result");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
allUsersList = (RecyclerView) findViewById(R.id.all_users_list);
allUsersList.setHasFixedSize(true);
allUsersList.setLayoutManager(new LinearLayoutManager(this));
}
#Override
protected void onStart() {
super.onStart();
FirebaseRecyclerAdapter<AllUsers,AllUsersViewHolder> firebaseRecyclerAdapter
= new FirebaseRecyclerAdapter<AllUsers, AllUsersViewHolder>
(
AllUsers.class,
R.layout.all_users_display_layout,
AllUsersViewHolder.class,
allDatabaseUserReference
)
{
#Override
protected void populateViewHolder(AllUsersViewHolder viewHolder, AllUsers model, final int position) {
viewHolder.setUser_name(model.getUser_name());
viewHolder.setUser_blood(model.getUser_blood());
viewHolder.setUser_mobile(model.getUser_mobile());
viewHolder.setUser_thumb_image(getApplicationContext(),model.getUser_thumb_image());
viewHolder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view)
{
String visit_user_id = getRef(position).getKey();
Intent profileIntent = new Intent(SearchActivity.this, ProfileActivity.class);
profileIntent.putExtra("visit_user_id",visit_user_id);
startActivity(profileIntent);
}
});
}
};
allUsersList.setAdapter(firebaseRecyclerAdapter);
}
public static class AllUsersViewHolder extends RecyclerView.ViewHolder
{
View mView;
public AllUsersViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void setUser_name(String user_name)
{
TextView name = (TextView) mView.findViewById(R.id.all_users_username);
name.setText(user_name);
}
public void setUser_blood(String user_blood)
{
TextView blood = (TextView) mView.findViewById(R.id.all_users_blood);
blood.setText(user_blood);
}
public void setUser_mobile(String user_mobile)
{
TextView mobile = (TextView) mView.findViewById(R.id.all_users_phone);
mobile.setText(user_mobile);
}
public void setUser_thumb_image(Context ctx, String user_thumb_image)
{
CircleImageView thumb_image = (CircleImageView) mView.findViewById(R.id.all_users_profile_image);
Picasso.with(ctx).load(user_thumb_image).placeholder(R.drawable.default_profile).into(thumb_image);
}
}
}
you can do it by applying childEventListner on your reference allDatabaseUserReference
allDatabaseUserReference.addChildEventListener(childEventListener);
and here's your childEventListener
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if(dataSnapshot!=null){
if(dataSnapshot.hasChild("device_token")){
tokenList.add(dataSnapshot.child("device_token").getValue().toString());
}
}
}
#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) {}
};
In FirebaseHelper Class I declare retrieve ArrayList method witch return spacecrafts ArrayList and it call fetchData method to add new Item in spacecrafts , In MainActivity I fill my adapter with helper.retrieve on the onCreate method , and make Dialog to add user Items when click saveBtn witch fill my adapter with helper.retrieve also , but adapter is fill with nothing , I make Toast to detect the problem and found that spacecrafts.size is fill every time with new Item but helper.retrieve().size every time =0 , Can anyone Shows me my mistake ?
here is FirebaseHelper Class :
class FirebaseHelper {
private DatabaseReference db;
private ArrayList<Spacecraft> spacecrafts=new ArrayList<>();
int x;
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
public Boolean save(Spacecraft spacecraft)
{
Boolean saved ;
if(spacecraft==null)
{
saved =false;
}else
{
try
{
db.child("Spacecraft").push().setValue(spacecraft);
saved =true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved =false;
}
}
return saved;
}
private void fetchData(DataSnapshot dataSnapshot)
{
spacecrafts.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Spacecraft spacecraft=ds.getValue(Spacecraft.class);
spacecrafts.add(spacecraft);
x=spacecrafts.size();
}
}
ArrayList<Spacecraft> retrieve()
{
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return spacecrafts;
}
}
and here is Main Activity class :
public class MainActivity extends AppCompatActivity {
DatabaseReference db;
FirebaseHelper helper;
MyAdapter adapter;
private RecyclerView rv;
EditText nameEditTxt,propTxt,descTxt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
rv= (RecyclerView) findViewById(R.id.rv);
rv.setLayoutManager(new LinearLayoutManager(this));
db= FirebaseDatabase.getInstance().getReference();
helper=new FirebaseHelper(db);
adapter=new MyAdapter(this,helper.retrieve());
rv.setAdapter(adapter);
Toast.makeText(MainActivity.this, "helper.retrieve().size() = " + helper.retrieve().size(), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "spacecrafts.size() = " + helper.x, Toast.LENGTH_SHORT).show();
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
displayInputDialog();
Toast.makeText(MainActivity.this, "spacecrafts.size() = " + helper.x, Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "helper.retrieve().size() = " + helper.retrieve().size(), Toast.LENGTH_SHORT).show();
}
});
}
private void displayInputDialog()
{
final Dialog d=new Dialog(this);
d.setTitle("Save To Firebase");
d.setContentView(R.layout.input_dialog);
nameEditTxt= (EditText) d.findViewById(R.id.nameEditText);
propTxt= (EditText) d.findViewById(R.id.propellantEditText);
descTxt= (EditText) d.findViewById(R.id.descEditText);
Button saveBtn= (Button) d.findViewById(R.id.saveBtn);
saveBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//GET DATA
String name=nameEditTxt.getText().toString();
String propellant=propTxt.getText().toString();
String desc=descTxt.getText().toString();
//SET DATA
Spacecraft s=new Spacecraft();
s.setName(name);
s.setPropellant(propellant);
s.setDescription(desc);
if(name.length() > 0)
{
if(helper.save(s))
{
nameEditTxt.setText("");
propTxt.setText("");
descTxt.setText("");
adapter=new MyAdapter(MainActivity.this,helper.retrieve());
Toast.makeText(MainActivity.this, "spacecrafts.size() = " + helper.x, Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "helper.retrieve().size() = " + helper.retrieve().size(), Toast.LENGTH_SHORT).show();
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();
d.hide();
}
}else
{
Toast.makeText(MainActivity.this, "Name Must Not Be Empty", Toast.LENGTH_SHORT).show();
}
}
});
d.show();
}
}
Firebase operations are run asynchronously that means they are run on a separate thread, So your method ArrayList<Spacecraft> retrieve() returns the list before it is populated.
I try this and its work
private void fetchData(DataSnapshot dataSnapshot)
{
// spacecrafts.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Spacecraft spacecraft=ds.getValue(Spacecraft.class);
spacecrafts.add(spacecraft);
x=spacecrafts.size();
}
}
ArrayList<Spacecraft> retrieve()
{
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
// try to clear spacecrafts here
spacecrafts.clear();
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
// and here
spacecrafts.clear();
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return spacecrafts;
}
}
I'm using Firebase to populate my RecyclerView, but the problem is that every time I open the app, I need to swipe down to refresh and then the list of items is available.
Here is my code
public class MainActivity extends AppCompatActivity {
private static final int RC_PHOTO_PICKER = 2;
DatabaseReference db;
FirebaseHelper helper;
MyAdapter adapter;
RecyclerView rv;
EditText nameEditTxt,grpTxt,descTxt,linkTxt;
FirebaseAuth.AuthStateListener authListener;
SwipeRefreshLayout swipeRefresh;
Uri downloadUrl;
String Admin_code;
FirebaseStorage mfirebaseStorage;
private StorageReference mEventPhotoReference;
FloatingActionButton fab;
SharedPreferences sharedPreferences;
ProgressBar spinner;
static boolean calledAlready=false;
public MyAdapter adapter1;
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
spinner = (ProgressBar)findViewById(R.id.progressBar);
spinner.setVisibility(View.GONE);
mfirebaseStorage=FirebaseStorage.getInstance();
if(!calledAlready){
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
calledAlready=true;
}
swipeRefresh=(SwipeRefreshLayout)findViewById(R.id.swiperefresh);
//SETUP RECYCLER
rv = (RecyclerView) findViewById(R.id.rv);
rv.setLayoutManager(new LinearLayoutManager(this));
//INITIALIZE FIREBASE DB
db= FirebaseDatabase.getInstance().getReference();
mEventPhotoReference=mfirebaseStorage.getReference().child("Event Photos");
helper=new FirebaseHelper(db);
//ADAPTER
adapter=new MyAdapter(this,helper.retrieve());
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
rv.setAdapter(adapter);
swipeRefresh.setRefreshing(false);
}
});
sharedPreferences= PreferenceManager.getDefaultSharedPreferences(this);
Admin_code=sharedPreferences.getString(getString(R.string.Admin_code),getString(R.string.Admin_default_value));
Log.e("MainActivity","" + Admin_code);
fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
displayInputDialog();
}
});
fab.setVisibility(View.GONE);
showBtn();
}
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
protected void onResume() {
showBtn();
super.onResume();
}
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void showBtn(){
Admin_code=sharedPreferences.getString(getString(R.string.Admin_code),getString(R.string.Admin_default_value));
if(Objects.equals(Admin_code, "28011996")){
fab.setVisibility(View.VISIBLE);
}
else
fab.setVisibility(View.GONE);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_logout) {
FirebaseAuth.getInstance().signOut();
startActivity(new Intent(MainActivity.this, LoginActivity.class));
return true;
}
if(id==R.id.settings){
Intent settingsIntent=new Intent(this,Settings.class);
startActivity(settingsIntent);
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if ((requestCode& 0xffff) == RC_PHOTO_PICKER && resultCode == RESULT_OK) {
Uri selectedImageUri = data.getData();
StorageReference photoRef=mEventPhotoReference.child(selectedImageUri.getLastPathSegment());
photoRef.putFile(selectedImageUri)
.addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() {
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
// When the image has successfully uploaded, we get its download URL
downloadUrl = taskSnapshot.getDownloadUrl();
Toast.makeText(MainActivity.this,"Photo selected successfully",Toast.LENGTH_LONG).show();
}
}).addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this,"there was a problem uploading photo",Toast.LENGTH_LONG).show();
}
});
}
}
//DISPLAY INPUT DIALOG
private void displayInputDialog()
{
Dialog d=new Dialog(this);
d.setTitle("Save To Firebase");
d.setContentView(R.layout.input_dialog);
nameEditTxt= (EditText) d.findViewById(R.id.nameEditText);
grpTxt= (EditText) d.findViewById(R.id.propellantEditText);
descTxt= (EditText) d.findViewById(R.id.descEditText);
Button saveBtn= (Button) d.findViewById(R.id.saveBtn);
Button photoBtn=(Button)d.findViewById(R.id.photoBtn);
linkTxt = (EditText) d.findViewById(R.id.linkEditText);
photoBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent=new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
startActivityForResult(Intent.createChooser(intent, "Complete action using"), RC_PHOTO_PICKER);
}
});
//SAVE
saveBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//GET DATA
String name=nameEditTxt.getText().toString();
String propellant=grpTxt.getText().toString();
String desc=descTxt.getText().toString();
String link=linkTxt.getText().toString();
Long tsLong = System.currentTimeMillis()/1000;
String ts = tsLong.toString();
//SET DATA
Spacecraft s=new Spacecraft();
s.setName(name);
s.setPropellant(propellant);
s.setDescription(desc);
s.setLink(link);
s.setImageUrl(downloadUrl.toString());
s.setTimestamp(ts);
//SIMPLE VALIDATION
if(name != null && name.length()>0)
{
//THEN SAVE
if(helper.save(s))
{
//IF SAVED CLEAR EDITXT
nameEditTxt.setText("");
grpTxt.setText("");
descTxt.setText("");
linkTxt.setText("");
downloadUrl=null;
adapter=new MyAdapter(MainActivity.this,helper.retrieve());
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}else
{
Toast.makeText(MainActivity.this, "Name Must Not Be Empty", Toast.LENGTH_SHORT).show();
}
}
});
d.show();
}
After Searching for a while, I found out that I should use notifyDataSetChanged(); but it doesn't work.
Here is my helper class where I'm fetching data:
public class FirebaseHelper {
DatabaseReference db;
Boolean saved=null;
ArrayList<Spacecraft> spacecrafts=new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//WRITE IF NOT NULL
public Boolean save(Spacecraft spacecraft)
{
if(spacecraft==null)
{
saved=false;
}else
{
try
{
db.child("Spacecraft").push().setValue(spacecraft);
saved=true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved=false;
}
}
return saved;
}
//IMPLEMENT FETCH DATA AND FILL ARRAYLIST
private void fetchData(DataSnapshot dataSnapshot)
{
spacecrafts.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Spacecraft spacecraft=ds.getValue(Spacecraft.class);
spacecrafts.add(spacecraft);
}
}
//READ THEN RETURN ARRAYLIST
public ArrayList<Spacecraft> retrieve() {
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
fetchData(dataSnapshot);
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return spacecrafts;
}
It'll be great if someone could help me out here. This is the last problem in my project.
The problem is due to the adapter not knowing about the data that has been fetched asynchronously. Let's try to look at your code step-by-step:
adapter = new MyAdapter(this, helper.retrieve());
helper.retrieve() will initiate an asynchronous request to fetch data from firebase and immediately returns an empty ArrayList (as the data from firebase hasn't reached the app yet).
rv.setAdapter(adapter);
This line sets the adapter to recyclerView, which has an empty arraylist as data, so it won't show anything on the UI.
After the data is received from firebase, ArrayList<Spacecraft> spacecrafts is updated with new data. But the adapter is not notified about this new data. Ideally, adapter.notifyDataSetChanged() should be called after new data is put into the array list.
Hence, when you swipe to refresh after the initial call, the adapter is set to recycler view, leading to an internal call to notifyDataSetChanged(), which in turn loads the new data on to the UI.
Easiest solution is to notify the adapter when new data is received from Firebase. Below is the pseudo code for it -
Create an interface OnFirebaseDataChanged and add a method void dataChanged(); to it.
MainAcitivty should implement this interface and the implementation of that method should call adapter.notifyDataSetChanged()
helper = new FirebaseHelper(db); should be changed to helper = new FirebaseHelper(db, this);
FirebaseHelper's constructor should have a 2nd parameter of type OnFirebaseDataChanged and should save it in a field called dataChangeListener.
Add a line at the end of fetchData method in FirebaseHelper dataChangeListener.dataChanged();
The ideal solution would be to architect the code differently, but that topic is out of scope of this question.