I recently started learning Firebase for Android. I've been completing the Udacity Firebase Weekend course where I created a chat using the database and storage. But I wanted to learn more and try to make it more interactive and at this point I'm struggling with something technically simple and I'd love tips and feedback on how to go on.
I have a class CityList
where I display all the cities added to the database using ListView. I also have a floating button that upon clicking opens an EditCity
activity where I can submit another city and its description (plus photos but that's not taken care of yet). It works fine, and the new cities show up in the CityList
immediately. However what I want to do is click on one city name and have it open another activity, with that specific item, that would display the name + description + photo. To do that, I created another activity SingleCase
.
I've been reading all about it and I know there are many answers to this question on here but I feel like I tried all of them and a) it's not working, usually because the code is the older version and no longer supported, b) I can't really understand it.
CityList.java
public class CityList extends AppCompatActivity {
FirebaseDatabase mFirebaseDatabase;
DatabaseReference mDatabaseReference;
private ListView mListView;
private CityAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cities);
mListView= (ListView) findViewById(R.id.messageListView);
List<City> cities = new ArrayList<>();
mAdapter = new CityAdapter(this, R.layout.item, cities);
mListView.setAdapter(mAdapter);
getData();
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(CityList.this, EditCity.class));
}
});
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String value = (String) parent.getItemAtPosition(position);
startActivity(new Intent(CityList.this, SingleCase.class) .putExtra("value", value));
}
});
}
public void getData() {
mFirebaseDatabase = FirebaseDatabase.getInstance();
mDatabaseReference = mFirebaseDatabase.getReference().child("cities");
mDatabaseReference.addChildEventListener(new ChildEventListener(){
@Override
public void onChildAdded (@NonNull DataSnapshot dataSnapshot, @Nullable String s){
City city = dataSnapshot.getValue(City.class);
key = dataSnapshot.getKey();
mAdapter.add(city);
}
@Override
public void onChildChanged (@NonNull DataSnapshot dataSnapshot, @Nullable String s){
}
@Override
public void onChildRemoved (@NonNull DataSnapshot dataSnapshot){
}
@Override
public void onChildMoved (@NonNull DataSnapshot dataSnapshot, @Nullable String s){
}
@Override
public void onCancelled (@NonNull DatabaseError databaseError){
}
});
}
}
City.java
public class City {
private String title;
private String desc;
public City() {
}
public City(String title, String desc) {
this.title = title;
this.desc = desc;
}
public String getText() {
return title;
}
public void setText(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
CityAdapter.java
public class CityAdapter extends ArrayAdapter<City> {
public CityAdapter(Context context, int resource, List<City> objects) {
super(context, resource, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = ((Activity) getContext()).getLayoutInflater().inflate(R.layout.item, parent, false);
}
TextView messageTextView = (TextView) convertView.findViewById(R.id.titleTextView);
TextView descTextView = (TextView) convertView.findViewById(R.id.descTextView);
City city = getItem(position);
messageTextView.setVisibility(View.VISIBLE);
messageTextView.setText(city.getText());
descTextView.setText(city.getDesc());
return convertView;
}
}
SingleCase.java
public class SingleCase extends AppCompatActivity{
FirebaseDatabase mFirebaseDatabase;
DatabaseReference mDatabaseReference;
private ListView mListView;
private CityAdapter mAdapter;
private String position;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.single_case);
position = getIntent().getStringExtra("value");
mListView= (ListView) findViewById(R.id.messageListView);
List<City> cities = new ArrayList<>();
mAdapter = new CityAdapter(this, R.layout.item, cities);
mListView.setAdapter(mAdapter);
getData();
}
public void getData() {
mFirebaseDatabase = FirebaseDatabase.getInstance();
mDatabaseReference = mFirebaseDatabase.getReference().child("cities");
mDatabaseReference.addChildEventListener(new ChildEventListener(){
@Override
public void onChildAdded (@NonNull DataSnapshot dataSnapshot, @Nullable String s){
City city = dataSnapshot.getValue(City.class);
mAdapter.add(city);
}
@Override
public void onChildChanged (@NonNull DataSnapshot dataSnapshot, @Nullable String s){
}
@Override
public void onChildRemoved (@NonNull DataSnapshot dataSnapshot){
}
@Override
public void onChildMoved (@NonNull DataSnapshot dataSnapshot, @Nullable String s){
}
@Override
public void onCancelled (@NonNull DatabaseError databaseError){
}
});
}
}
I've been through countless tutorials/videos/forums and I've read all the similar questions here on stack too, but I'm lost. I think if I understand well, I should use position, and I think I'm getting it (and key) right in CityList
, but I have no idea what to do next in SingleCase
to actually display it. I'm passing the position
value and can pass key
as well but I don't know where to use it next. I've read I can also use keys, but same thing, I tried getting a reference to .child("cities").child(key)
in SingleCase
, but it wasn't working (the app would crash). I'm sorry if it's a simple or too often asked question, but I'm new at this and I absolutely can't grasp the position/key
concept and how to use it in this case. And yes, I've read the docs too. Any help would be great!
If you need me to post anything else from the code, just let me know, thank you.
EDIT: Posting the most crucial parts of code for clarity:
In CityList.java
I'm getting the position
variable (called value
):
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String value = (String) parent.getItemAtPosition(position);
startActivity(new Intent(CityList.this, SingleCase.class) .putExtra("value", value));
}
});
Here I also putExtra
the position (value) and "send" it to SingleCase
. I also get the key
in CityList
from here:
public void onChildAdded (@NonNull DataSnapshot dataSnapshot, @Nullable String s){
City city = dataSnapshot.getValue(City.class);
key = dataSnapshot.getKey();
mAdapter.add(city);
}
When in SingleCase, I have no idea what to do with those two parameters. I suppose they're properly parsed and transferred (key isn't transferred yet but I can do it, I just wasn't sure if position wouldn't be enough to make it work).
The problem is SingleCase.
I feel like I should use key/position here to tell the program that I want only one specific City
item, but I have no idea how.
public void onChildAdded (@NonNull DataSnapshot dataSnapshot, @Nullable String s){
City city = dataSnapshot.getValue(City.class);
mAdapter.add(city);
}