I am trying to implement firebase into my Android app and I want to be able to pull all the entries in firebase in the order they display in into one string array to be put into a ListView
Here is the raw JSON:
[ 5, "quot", "waaaaa", "also a quote", "oh this one is a little longer man", "gosh really long. wow. im very inspired. golly gee wiz" ]
and the code I am using to try and get it:
public class MyActivity extends ListActivity {
ArrayList<String> LIST = new ArrayList<String>();
Boolean wow = true;
Context context = this;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Firebase.setAndroidContext(context);
updateList();
}
public void makeList(ArrayList<String> input){
setListAdapter(new ArrayAdapter<String>(this, R.layout.mylist,input));
ListView listView = getListView();
listView.setTextFilterEnabled(true);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// When clicked, show a toast with the TextView text
Toast.makeText(getApplicationContext(),
((TextView) view).getText(), Toast.LENGTH_SHORT).show();
}
});
}
public void updateList() {
Firebase myFirebaseRef = new Firebase("https://admin1.firebaseio.com/");
myFirebaseRef.child("0").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println(snapshot.getValue());
int length = Integer.parseInt(snapshot.getValue().toString());
Firebase myFirebaseRef = new Firebase("https://admin1.firebaseio.com/");
for(int i=1; i<length; i++) {
String doIt = Integer.toString(i);
myFirebaseRef.child(doIt).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println(snapshot.getValue());
LIST.add(snapshot.getValue().toString());
}
#Override
public void onCancelled(FirebaseError error) {
}
});
}makeList(LIST);
}
#Override
public void onCancelled(FirebaseError error) {
}
});
}
}
I was thinking that I could set the first (0th) object to be the number of entries and then cycle through the entire file using .getValue but when this is run I get out of memory exceptions and the app force closes. All I am sure of is that the relevant firebase stuff is the issue and not the ListView. Thanks for any tips.
Firstly, your data is stored in a JSON data object (i.e. not an array). You do not want to store sequential, numeric ids in distributed data.
To listen for the first n objects, utilize the query methods and limitToFirst.
int n = 10;
String URL = "https://<your instance>.firebaseio.com";
Firebase ref = new Firebase(URL);
Query queryRef = ref.orderByKey().limitToFirst(n);
queryRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot snapshot, String previousChild) {
Map<String, String> value = (Map<String, String)snapshot.getValue();
System.out.println(snapshot.getKey() + " was " + value.get("message"));
}
// ....
});
Related
I want to select finance Name and after clicked finance Name i want to get code of same finance. The finance Name is listed into listview.
My Firebase database structure is below:
financeRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
//Map<String, Object> data = (Map<String, Object>) snapshot.getValue();
String value = new Gson().toJson(snapshot.getValue());
progressBar.setVisibility(View.GONE);
try {
JSONObject object = new JSONObject(String.valueOf(value));
f = object.getString("Finance Name");
name = snapshot.getKey();
} catch (JSONException e) {
e.printStackTrace();
}
financeName.add(f);
adapter.notifyDataSetChanged();
}
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(FinanceNameListActivity.this, CodeAndNameActivity.class);
String abc = (String) ((TextView) view).getText();
intent.putExtra("Name",abc);
startActivity(intent);
finish();
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Get response from firebase and set it to model call or hashmap or array up to you then implement interface for list view click event or simple click event with get position and get value from where you set firebase response.
I am building an Android shopping list app following a Angga Risky tutorial.
Code running Error free, but the list I have created is not being populated by the firebase real-time database it is connected to. Below is the mainactivity
public class MainActivity extends AppCompatActivity {
TextView titlepage, subtitlepage, endpage;
DatabaseReference reference;
RecyclerView ourlist;
ArrayList < MyList > list;
ListAdapter listAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
titlepage = findViewById(R.id.titlepage);
subtitlepage = findViewById(R.id.subtitlepage);
endpage = findViewById(R.id.endpage);
//working with data
ourlist = findViewById(R.id.ourlist);
ourlist.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList < MyList > ();
//get data from firebase
reference = FirebaseDatabase.getInstance().getReference().child("compshopper3");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//set code to retrieve data and replace layout
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren()) {
MyList p = dataSnapshot1.getValue(MyList.class);
list.add(p);
}
listAdapter = new ListAdapter(MainActivity.this, list);
ourlist.setAdapter(listAdapter);
listAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
// set code to show an error
Toast.makeText(getApplicationContext(), "Dude Where's My Data???", Toast.LENGTH_SHORT).show();
}
});
}
}
Here is look at the firebase data
Here is a shot of the emulator output.
First change the reference to refer to the parent node:
reference = FirebaseDatabase.getInstance().getReference().child("CompShopperApp");
Then remove the for loop inside onDataChange() and make sure that your model class contains the fields price1, price2, price3 and itemtitle:
reference.addValueEventListener( new ValueEventListener () {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
MyList p = dataSnapshot.getValue(MyList.class);
list.add(p);
listAdapter = new ListAdapter(MainActivity.this, list);
ourlist.setAdapter(listAdapter);
listAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
// set code to show an error
Toast.makeText(getApplicationContext(), "Dude Where's My Data???", Toast.LENGTH_SHORT).show();
}
In addition to #peter-haddad's answer, make sure your firebase database rules allow you to access the data without authentication, in case you're trying to do that (which we usually do during dev testing).
Firebase console -> Database (Realtime Database) -> Rules ->
{
"rules": {
".read": true,
".write": true
}
}
I'm working on a chat app where user can see last message of conversation. But I am stuck with this situation where i am unable to get last message.
I have tried this query like
DatabaseReference getLastMessageRef =
FirebaseDatabase.getInstance().getReference("FriendsMessages");
Query query1 = getLastMessageRef.child(common.currentUser.getPhone()).child(id).orderByKey().limitToLast(1);
Where common.currentUser.getPhone is number/id of current user and id is id of other person.
And database structure is like DATABASE STRUCTURE PICTURE
private void getAllMessages() {
Query query = FirebaseDatabase.getInstance().getReference("FriendsMessages").child(common.currentUser.getPhone());
FirebaseRecyclerOptions<MessageModel> options = new FirebaseRecyclerOptions.Builder<MessageModel>()
.setQuery(query,MessageModel.class)
.build();
adapter = new FirebaseRecyclerAdapter<MessageModel, ShowAllMessageViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final ShowAllMessageViewHolder holder, int position, #NonNull final MessageModel model) {
String id = adapter.getRef(position).getKey();
DatabaseReference getFriendDataRef = FirebaseDatabase.getInstance().getReference("User");
DatabaseReference getLastMessageRef = FirebaseDatabase.getInstance().getReference("FriendsMessages");
getFriendDataRef.child(id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
String dp = dataSnapshot.child("img").getValue().toString();
String name = dataSnapshot.child("name").getValue().toString();
holder.MessageName.setText(name);
Picasso.with(getBaseContext()).load(dp).into(holder.messageDp);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Query query1 = getLastMessageRef.child(common.currentUser.getPhone()).child(id).orderByKey().limitToLast(1);
query1.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String mesaage = (String) dataSnapshot.child("message").getValue();
Toast.makeText(mContext, ""+mesaage, Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#NonNull
#Override
public ShowAllMessageViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_message_view,parent,false);
return new ShowAllMessageViewHolder(view);
}
};
showAllMessages.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
I am getting null string.
One thing to remember is that Firebase keys are always Strings. And when strings are ordered, are ordered lexicographically.
If you want to get the last element, add to each message object a new property that can hold a timestamp. This is how you can add it to the database and get it back. In the end, simply create a query and order the elements according to this new timestamp property and call limitToLast(1). That's it!
I am currently programin a test QuizApp. The gameplay is pretty easy I just want an online database of questions and a user can answer them.
This is what the database looks like:
That collection questions contains an unique ID and a custom Object (questionObject) named 'content'. The number is only something easy I can query/search for.
This is my questionAdder and query UI. It's only a small test App.
public class questionAdder extends AppCompatActivity {
EditText pQuestion, pAnwerA, pAnswerB, pAnswerC, pAnswerD, number;
Button pAdd, query;
private DatabaseReference databaseReference;
private FirebaseFirestore firebaseFirestore;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addquestion);
firebaseFirestore = FirebaseFirestore.getInstance();
pQuestion = (EditText) findViewById(R.id.question);
pAnwerA = (EditText) findViewById(R.id.answerA);
pAnswerB = (EditText) findViewById(R.id.answerB);
pAnswerC = (EditText) findViewById(R.id.answerC);
pAnswerD = (EditText) findViewById(R.id.answerD);
number = (EditText) findViewById(R.id.number);
pAdd = (Button) findViewById(R.id.addQuestion);
pAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
readQuestionStore();
}
});
query = (Button) findViewById(R.id.query);
query.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CollectionReference questionRef = firebaseFirestore.collection("questions");
questionRef.whereEqualTo("content.number", "20").get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
questionObject pContent = queryDocumentSnapshots.toObjects(questionObject.class);
}
});
}
});
}
public void readQuestionStore(){
Map<String, Object> pContent = new HashMap<>();
pContent.put("question", pQuestion.getText().toString());
pContent.put("Corr Answer", pAnwerA.getText().toString());
pContent.put("AnswerB", pAnswerB.getText().toString());
pContent.put("AnswerC", pAnswerC.getText().toString());
pContent.put("AnswerD", pAnswerD.getText().toString());
questionObject content = new questionObject(pContent, number.getText().toString()); //document("Essen").collection("Katalog")
firebaseFirestore.collection("questions").add(content).addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(DocumentReference documentReference) {
Toast.makeText(questionAdder.this, "Klappt", Toast.LENGTH_LONG).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(questionAdder.this, "Klappt nicht", Toast.LENGTH_LONG).show();
}
});
}
}
And this is how my questionObject looks like:
public class questionObject{
private Map<String, Object> content;
private String number;
public questionObject(){
}
public questionObject(Map<String, Object> pContent, String pNumber) {
this.content = pContent;
this.number = pNumber;
}
public Map<String, Object> getContent() {
return content;
}
public void setContent(Map<String, Object> content) {
this.content = content;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
Problem In that questionAdder class in the onClickListener I receive an "incompatible types" Error (Found: java.utils.list Required: questionObject).
query.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CollectionReference questionRef = firebaseFirestore.collection("questions");
questionRef.whereEqualTo("content.number", "20").get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
questionObject pContent = queryDocumentSnapshots.toObjects(questionObject.class);
}
});
}
});
If if I change that to a List it is empty. So the actual question is, how do I get the CustomObject into my code using the Database. Thanks!
The reason you are getting this error in because the QuerySnapshot is a type which "contains" multiple documents. Firestore won't decide for you whether there are a bunch of objects to return as a result, or just one.
This is why you can take two different approaches:
Put the data in a custom object's list:
List<questionObject> questionsList=new ArrayList<>();
if (!documentSnapshots.isEmpty()){
for (DocumentSnapshot snapshot:queryDocumentSnapshots)
questionsList.add(snapshot.toObject(questionObject.class));
}
If you're sure that your gonna get only one queried object, you can just get the first object from the returned queryDocumentSnapshots:
questionObject object=queryDocumentSnapshots.getDocuments().get(0).toObject(questionObject.class);
A few more things you should be aware of:
Why do you write content.number instead of just number?
It seems like number is a separated field in your question document, so your code should be as follows:
CollectionReference questionRef = firebaseFirestore.collection("questions");
questionRef.whereEqualTo("number", "20").get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
questionObject pContent = queryDocumentSnapshots.toObjects(questionObject.class);
}
});
In addition, try to change your number field to int, because it's not a String but a just a number.
By the way, it is more acceptable to write classes' names with a capital letter at a beginning, for example: QuestionObject question=new QuestionObject();
So basically I'm collecting data from a json url in my listview. It's a chatroom type of app and in the lists I want to sync the chatroom contact lists with latest message and timestamps.
When the json gets updated I'm calling the fuction.
public void addGroupAdapter() {
Firebase jsonurl = new Firebase("firebase url");
jsonurl.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ContactListAdapter adapter = new ContactListAdapter(getContext(),dataSnapshot);
try {
Log.i("Response Array fire",new JSONArray(dataSnapshot.getValue(String.class)).toString());
if (!adapted){
chatLists.setAdapter(adapter);
adapted = true;
}else {
Log.i("update",dataSnapshot.getValue(String.class));
adapter.setContactList(dataSnapshot);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
That Json data is stored in the firebase database .
chatLists.setAdapter(adapter) works well.
But when I try to update. notifyDataSetChanged(); doesn't work.
new ContactListAdapter(getContext(),dataSnapshot).notifyDataSetChanged();
I also tried invalidateviews method and same result. So where am I doing wrong?
After reading answers I tried this. SO now this my adapter class,
class ContactListAdapter extends BaseAdapter {
Context c;
List lists;
Type type = new TypeToken<List<ChatroomLists>>(){}.getType();
JsonParser parser = new JsonParser();
ArrayList<ChatroomLists> ob1 = new ArrayList<ChatroomLists>();
public void setContactList(DataSnapshot dataSnapshot) {
Type listType = new TypeToken<ArrayList<ChatroomLists>>() {
}.getType();
ob1 = new Gson().fromJson((JsonArray)parser.parse(dataSnapshot.getValue(String.class)),listType);
Log.i("setContactList",dataSnapshot.getValue(String.class));
notifyDataSetChanged();
}
ContactListAdapter(Context c, DataSnapshot group_name) {
this.c = c;
this.groupids = group_name;
Type listType = new TypeToken<ArrayList<ChatroomLists>>() {
}.getType();
ob1 = new Gson().fromJson((JsonArray)parser.parse(group_name.getValue(String.class)),listType);
}
#Override
public int getCount() {
return ob1.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View row = convertView;
GroupChat.viewHolder holder = null;
if (row == null) {
LayoutInflater inflater = (LayoutInflater) c.getSystemService (Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate (R.layout.chat_list_style, parent, false);
holder = new GroupChat.viewHolder(row);
row.setTag (holder);
} else {
holder = (GroupChat.viewHolder) row.getTag ();
}
ChatroomLists chatroomLists = ob1.get(position);
Iterator<ChatroomLists> iter = ob1.iterator();
String id = chatroomLists.getId();
String time = chatroomLists.getTimestamp();
Log.i("updated data",id + time);
viewHolder finalHolder = holder;
Firebase chatlink = new Firebase ("firebase link");
chatlink.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot d: dataSnapshot.getChildren()){
finalHolder.user_message.setText (dataSnapshot.child(d.getKey()).child("message").getValue(String.class));
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
Firebase imageurl = new Firebase("firebase link");
imageurl.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Glide.with (getActivity ())
.load (dataSnapshot.getValue(String.class))
.error (R.drawable.man)
.into (finalHolder.user_img);
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
holder.user_name.setText (id);
row.setOnClickListener (new View.OnClickListener () {
#Override
public void onClick(View v) {
Intent intent = new Intent (getActivity (), ChatRoom.class);
intent.putExtra ("group_name", id);
startActivity (intent);
}
});
registerForContextMenu (row);
return row;
}
}
But it's still not updating.. :(
UPDATE: Listview was so buggy in this case. And I changed to Recyclerview. Now everything is working smoothly.
This is because you are creating new adapter instance instead of updating data on existing adapter which is set on list/recyclerview.
private ContactListAdapter mAdatper;
public void addGroupAdapter() {
Firebase jsonurl = new Firebase("firebase url");
jsonurl.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
try {
Log.i("Response Array fire",new JSONArray(dataSnapshot.getValue(String.class)).toString());
if (!adapted){
mAdatper = new ContactListAdapter(getContext(),dataSnapshot);
chatLists.setAdapter(mAdapter);
adapted = true;
}else {
Log.i("update",dataSnapshot.getValue(String.class));
mAdatper.setContactList(dataSnapshot);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
In your adapter, add setter method.
public void setContactList(DataSnapshot dataSnapshot) {
// set contactList here
notifyDataSetChanged();
}
Hope it might be helpful for you.
You are calling notifyDataSetChanged() on a new instance of the adapter everytime. You should call it on the same adapter that you set on the list. And you should update the data in that particular instance of the adapter
In your else case you are creating a new ContactListAdapter but you are not attaching that adapter to your chatLists. Anyway, you do not need to create a new CustomAdapter instance, just create a update method within your CustomAdapter and call it passing new dataSnapshot data.
You can Try something as the following inside your CustomAdapter.java:
public void updateData(Data data) {
this.dataList = data;
notifyDataSetChanged();
}
Then back into your addGroupAdapter method just call that method