I am new in programing
and this is my java code below
I want the simplest way to add button to each row of listview and relate it with that row firebase child (like a vote button for example) ...
should I custom simple_list_item_1 ?? or creat a new xml file .. please answer me in detail because like I said I am new in android
tnx for help
public class Main2Activity extends ListActivity {
String us , userId ;
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference();
ArrayList<String> listItems = new ArrayList<>();
ArrayAdapter<String> adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
adapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,listItems);
setListAdapter(adapter);
userId = Profile.getCurrentProfile().getId() ;
us = Profile.getCurrentProfile().getName();
Toast.makeText(Main2Activity.this, "HI "+us,
Toast.LENGTH_SHORT).show();
ProfilePictureView profilePictureView;
profilePictureView = findViewById(R.id.ProfilePicture);
profilePictureView.setProfileId(userId);
ref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
String value = childSnapshot.getValue(String.class);
listItems.add(value);
}
adapter.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) {
}
});
}
}
android.R.layout.simple_list_item_1 is a reference to an built-in XML layout document that is part of the Android OS which containt only one TextView, so if you want to add another view (e.g. button) you need to create your own layout.
Related
Basically the app it's just a simple to do list, but when I add new task to do, it appears on firebase, but not on my app, giving the error
"E/RecyclerView: No adapter attached; skipping layout".
I tried to fix it following the answers here on stackoverflow but none of them helped me, probably I was wrong to adapt the adjustments to my code. I'm just learning and this is my first project, I was following a tutorial to do it.
Anyway, this is the MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonadd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
Intent a = new Intent(MainActivity.this, AggiungiPiattoAttivity.class);
startActivity(a);
}
});
//working with data
ourdoes = findViewById(R.id.ourdoes);
ourdoes.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<MyDoes>();
//get data from firebase
reference = FirebaseDatabase.getInstance(URL).getReference().child("AppLista");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//set code to retrive data and replace layout
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren())
{
MyDoes p = dataSnapshot1.getValue(MyDoes.class);
list.add(p);
}
doesAdapter = new DoesAdapter(MainActivity.this, list);
ourdoes.setAdapter(doesAdapter);
doesAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
//set code to show an error
Toast.makeText(getApplicationContext(), "No Data", Toast.LENGTH_SHORT).show();
}
});
}
This is the class where I add a new to do task:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aggiungi_piatto_attivity);
buttonaddnewpiatto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//insert data to database
reference = FirebaseDatabase.getInstance(URL).getReference().child("BoxDoese").child("Does" + doesNum);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataSnapshot.getRef().child("titledoes").setValue(addnamenewpiattosetted.getText().toString());
dataSnapshot.getRef().child("descdoes").setValue(adddescnewpiattosetted.getText().toString());
dataSnapshot.getRef().child("qualcosaalpostodiunimmagine").setValue(addrecipenewpiattosetted.getText().toString());
Intent a = new Intent( AggiungiPiattoAttivity.this, MainActivity.class);
startActivity(a);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
});
This is my adapter class:
public class DoesAdapter extends RecyclerView.Adapter<DoesAdapter.MyViewHolder> {
Context context;
ArrayList<MyDoes> myDoes;
public DoesAdapter(){
}
public DoesAdapter(Context c, ArrayList<MyDoes> p ){
context = c;
myDoes=p;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_does, viewGroup, false));
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder myViewHolder, int i) {
myViewHolder.titledoes.setText(myDoes.get(i).getTitledoes());
myViewHolder.qualcosaalpostodiunimmagine.setText(myDoes.get(i).getQualcosaalpostodiunimmagine());
myViewHolder.descdoes.setText(myDoes.get(i).getDescdoes());
}
#Override
public int getItemCount() {
return myDoes.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView titledoes, descdoes, qualcosaalpostodiunimmagine;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
titledoes = (TextView) itemView.findViewById(R.id.titledoes);
qualcosaalpostodiunimmagine = (TextView) itemView.findViewById(R.id.qualcosaalpostodiunimmagine);
descdoes = (TextView) itemView.findViewById(R.id.descdoes);
}
}
}
I also have other classes but to not put too much code I avoid to put them, they should not be relevant.
Create an empty adapter the same time you set LayoutManager for the RecyclerView: Save it as field of your class:
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
doesAdapter = new DoesAdapter(MainActivity.this, list);
recyclerView.setAdapter(DoesAdapter);
When data is ready, populate the adapter and notify:
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
/// origin code here
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren())
{
MyDoes p = dataSnapshot1.getValue(MyDoes.class);
list.add(p);
}
// reset data in adapter and not re-creating adapter:
doesAdapter.setItems(list);
doesAdapter.notifyDataSetChanged();
// instead of doesAdapter = new DoesAdapter(MainActivity.this, list);
recyclerView.setAdapter(DoesAdapter);
}
Source: https://stackoverflow.com/a/58251986/12596713
The problem that I am having is that when a user adds a comment the entire list refreshes because I have notifyDataSetChanged(); set on the CommentAdapter. Everything jumps, and refreshes and I want it to be smoother, so I decided to use notifyItemInserted(); instead of notifyDataSetChanged();, but it isn't doing anything different.
notifyItemInserted(); should only update the last item or the newest item added to the list, so why is everything being refreshed/updated...?
Can someone tell me how to fix this? Only want last item added to list to be "added"/"updated"/whatever, not the entire list because if many people start commenting everything is always reloading...
In my readComments(); what I have now is mCommentAdapter.notifyItemInserted(mCommentList.size() - 1);, and what I had before was mCommentAdapter.notifyDataSetChanged();, but they are having the same effect. How can I fix this?
CommentsActivity
public class CommentsActivity extends AppCompatActivity {
private CommentAdapter mCommentAdapter;
private List<Comment> mCommentList;
private RecyclerView mRecyclerView;
EditText mAddComment;
ImageView mImageProfile;
TextView mPost;
String mPostId;
String mPublisherId;
String mNotificationId;
FirebaseUser mFirebaseUser;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comments);
mRecyclerView = findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(linearLayoutManager);
mCommentList = new ArrayList<>();
mCommentAdapter = new CommentAdapter(this, mCommentList, mPostId);
mRecyclerView.setAdapter(mCommentAdapter);
mAddComment = findViewById(R.id.add_comment);
mImageProfile = findViewById(R.id.image_profile);
mPost = findViewById(R.id.post_comment);
mFirebaseUser = FirebaseAuth.getInstance().getCurrentUser();
mPost.setOnClickListener(v -> {
if (mAddComment.getText().toString().equals("")) {
Toast.makeText(CommentsActivity.this, "Can't send empty comments", Toast.LENGTH_SHORT).show();
} else {
addCommentNotification(mPublisherId, mPostId);
}
});
getImage();
readComments();
}
private void getImage() {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Users").child(mFirebaseUser.getUid());
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
if (user != null)
Glide.with(getApplicationContext()).load(user.getImageurl()).into(mImageProfile);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private void readComments() {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Comments").child(mPostId);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
mCommentList.clear();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Comment comment = snapshot.getValue(Comment.class);
mCommentList.add(comment);
}
mCommentAdapter = new CommentAdapter(CommentsActivity.this, mCommentList, mPostId);
mRecyclerView.setAdapter(mCommentAdapter);
mCommentAdapter.notifyItemInserted(mCommentList.size() - 1);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
I am guessing you should be using a ChildEventListener:
Your readComments() must be like this:
private void readComments() {
//your reference
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Comments").child(mPostId);
//the child listener
ChildEventListener listener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
// A new comment has been added
Comment comment = dataSnapshot.getValue(Comment.class);
mCommentList.add(comment);
//Notify adapter
mCommentAdapter.notifyItemInserted(mCommentList.size() - 1);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
//attach the listener
ref.addChildEventListener(listener);
}
I just want my data from fire base to show justified in my list view I tried web views on other places where I used text views but it's super slow and super heavy.
I tried web views but the slow down my application and take a second to display the data, the data on my firebase is text, I found out that android does not support justification, so I removed the text views and used web views but I can't remove my list. I need a method so that I can show justified data into the list.
This is my code and simple list
public class Food extends AppCompatActivity {
private FirebaseDatabase database;
private DatabaseReference reference;
private ListView listView;
private List<DataL> datalist;
private ProgressDialog dialog;
private Bundle bundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_food);
getSupportActionBar().hide();
listView = (ListView)findViewById(R.id.listFood);
bundle = getIntent().getExtras();
int days = Integer.parseInt(bundle.getString("Days"));
datalist = new ArrayList<>();
final DataListAdapter adapter = new DataListAdapter(this,datalist);
listView.setAdapter(adapter);
dialog = new ProgressDialog(this);
dialog.setMessage("Loading");
dialog.show();
database = FirebaseDatabase.getInstance();
if (days <= 120){
reference = database.getReference("food").child("1");
}else if (days <=180){
reference = database.getReference("food").child("2");
}else if (days <=300){
reference = database.getReference("food").child("3");
}else if (days <= 365){
reference = database.getReference("food").child("4");
}else if (days <= 730){
reference = database.getReference("food").child("5");
}else if(days <= 1095){
reference = database.getReference("food").child("6");
}
reference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
DataL dl = dataSnapshot.getValue(DataL.class);
datalist.add(dl);
adapter.notifyDataSetChanged();
dialog.cancel();
}
#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) {
}
});
}
}
Here is the sample database
image of the data base
Hello I'm a beginner in firebase and android studio. I want to get the client_id's key names without its sub keys and values.
For example
098798788
343243209
348987206
My code shows key names but it repeats the same key.
here is my code:
//list view code start ----------------------------------------------------------------;
ListView listView = findViewById(R.id.listview00);
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,usernames);
listView.setAdapter(arrayAdapter);
DatabaseReference myRef = database.getReference("clients/client_id");
myRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
String value = dataSnapshot.getKey();
usernames.add(value);
}
arrayAdapter.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) {
}
});
//list view code end----------------------------------------------------------------
do this:
ListView listView = findViewById(R.id.listview00);
DatabaseReference myRef = database.getReference().child("clients").child("client_id");
myRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
String value = dataSnapshot.getKey();
usernames.add(value);
}
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,usernames);
listView.setAdapter(arrayAdapter);
arrayAdapter.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) {
}
});
I am getting a lot of memory leaks in an application I created. I created a very simple app to reproduce the problem. This application just makes a reference to the FirebaseDatabase and sets up a ChildEventListener. When the user clicks the button it adds a record to the database, and starts a new activity which does System.gc().
Pressing the button multiple times will cause Leak Canary to generate a dump.
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private FirebaseDatabase firebaseDatabase;
private DatabaseReference dbRef;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
firebaseDatabase = FirebaseDatabase.getInstance();
dbRef = firebaseDatabase.getReference("leak");
dbRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
findViewById(R.id.btn_leak).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dbRef.child(UUID.randomUUID().toString()).setValue("Yes");
Intent leakIntent = new Intent(getApplicationContext(), LeakActivity.class);
startActivity(leakIntent);
}
});
}
}
LeakActivity.java:
public class LeakActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.leak);
System.gc();
}
}
Due to the post limit, the leak canary log is here.
Am I doing something wrong in my code, or is this related to Firebase?
EDIT: #qbix's answer seemed to work. For others, here is the working version of MainActivity.java:
public class MainActivity extends AppCompatActivity {
private FirebaseDatabase firebaseDatabase;
private DatabaseReference dbRef;
private ChildEventListener dbListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
firebaseDatabase = FirebaseDatabase.getInstance();
dbRef = firebaseDatabase.getReference("leak");
dbListener = getDbListener();
dbRef.addChildEventListener(dbListener);
findViewById(R.id.btn_leak).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dbRef.child(UUID.randomUUID().toString()).setValue("Yes");
Intent leakIntent = new Intent(getApplicationContext(), LeakActivity.class);
startActivity(leakIntent);
}
});
}
#Override
protected void onStop() {
dbRef.removeEventListener(dbListener);
super.onStop();
}
private ChildEventListener getDbListener(){
return new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
}
#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) {
}
};
}
}
I haven't used LeakCanary, so this is just an educated guess.
ChildEventListeners need to be unregistered when they are no longer needed. Often listeners are added and removed in activity lifecycle methods, such as onCreate() and onDestroy(). Instead of creating an anonymous listener, create an object of that type and remove it using Query.removeEventListener() when no longer needed to see if that eliminates the leak report.
I think that is better to add/remove listeners within the onStart()/onStop() or the onCreate()/onDestroy() callbacks respectively.
If a listener was added in onCreate() and removed in onStop() there could occur a situation when an activity will be restored without of calling the onCreate() but with calling of onStart() and listener will not be set.
https://developer.android.com/images/activity_lifecycle.png