Android Firebase Realtime Database - 3 ListView Examples.


Android Firebase Realtime Database - 3 ListView Examples.

This is an android Firebase Realtime Database with ListView examples. We see how to add and retrieve data and show in ListViews.

1. Android Firebase - ListView - Save,Retrieve,Show

So lets cover android firebase listview example.How to save from edittext,retrieve that particular data and of course show in a simple listview.

ListView is one of the most popular adapterviews while Firebase is probably the most popular database backend service currently in the market.

These two are easy to use and provides us with powerful opportunities to create amazing apps.

The Plan

This android firebase listview tutorial.This is what we do :

  • Save from edittext to google firebase database using methods setValue() and push();
  • Fetch that particular data by attaching a childEventListener to a databaseReference instance.
  • Read the children of a dataSnapshot.
  • Fill Simple ArrayList
  • Bind the arraylist to ListView

1. Setup

(a). Create Basic Activity Project
  1. First create a new project in android studio. Go to File --> New Project.
(b). Create Firebase and Download Configuration File

Head over to Firebase Console, create a Firebase App, Register your app id and download the google-services.json file. Add it to your app folder.

Add Config File

(c). Add Google services classpath and maven url

Add classpath 'com.google.gms:google-services:3.1.0'. This you do in the project level build.gradle. You may use later versions.

Also add the google maven url in you respositories. Firebase will be fetched from that url.

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'com.google.gms:google-services:3.1.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com" // Google's Maven repository
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
(c). Add Firebase Dependencies

Add FirebaseDatabase dependencies in your app level build.gradle. You may use later versions than me. Then sync the project to download them and add them as part of your project.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'

    compile 'com.google.firebase:firebase-core:11.8.0'
    compile 'com.google.firebase:firebase-database:11.8.0'
}
apply plugin: 'com.google.gms.google-services'

Make sure you apply plugin: 'com.google.gms.google-services' as above.

(d). AndroidManifest.xml
  • Add this to your androidmainfest.xml file. This because to access Firebase we need internet connection hence we have to specify a permission. Add it under the <manifest>..</manifest> tag.
<manifest>
...
    <uses-permission android:name="android.permission.INTERNET"/>
 ...   
 </manifest>   

5. Create User Interface

User interfaces are typically created in android using XML layouts as opposed by direct java coding.

(a). activity_main.xml
  • This layout gets inflated to MainActivity user interface.
  • It includes the content_main.xml.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.tutorials.hp.firebasesimplelistview.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
(b). content_main.xml

This layout will get interpolated into our activity_main.xml.

Here are the roles of this layout:

No. Responsibility
1. Define a ListView identified by a unique id. That ListView is our adapterview and will render our realtime data from Firebase.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.tutorials.hp.firebasesimplelistview.MainActivity"
    tools:showIn="@layout/activity_main">

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
</RelativeLayout>
(c). input_dialog.xml
  • InputDialog.xml

This is our input form layout.

Here are it's roles:

No. Responsibility
1. Define an EditText for writing data to firebase. Wrap that edittext in a TextInputLayout to give it a material design feel.
2. Define a Button to be used as our action button to for saving data to firebase.
3. Align all these widgets in a vertical manner with the help of a LinearLayout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="?attr/actionBarSize"
        android:orientation="vertical"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        android:paddingTop="10dp">

        <android.support.design.widget.TextInputLayout
            android:id="@+id/nameLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/nameEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:hint= "Name" />
        </android.support.design.widget.TextInputLayout>

        <Button android:id="@+id/saveBtn"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Save"
            android:clickable="true"
            android:background="@color/colorAccent"
            android:layout_marginTop="20dp"
            android:textColor="@android:color/white"/>

    </LinearLayout>

</LinearLayout>

Our Java Classes

(a). Our Model Class : Spacecarft.java
  • Data object
  • Represents a single spacecraft and its properties.

It has the following responsibilities:

No. Responsibility
1. Define one private field which will be the sole property of our spacecraft. That is : name property.
2. Define one empty constructor which is require by Firebase.
3. Expose our instance field for modification or data retrieval via setter and getter methods respectively.
package com.tutorials.hp.firebasesimplelistview.m_Model;

public class Spacecraft {

    String name;

    public Spacecraft() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

(b). Our FirebaseHelper class

  • Perform basic Write to Firebase database
  • Read from Firebase database.
  • Fill simple arraylist

Here are the major responsibilities of this class:

No. Responsibility
1. Maintain three instance fields: a DatabaseReference, a Boolean and an ArrayList.
2. Obtain a DatabaseReference via the parameter from outside and assign it to the one we maintain locally.
3. Define a public method save() that receives a Spacecraft object, then attempt to save it to Firebase and return either true or false based on the success. To save data we use db.child("Spacecraft").push().setValue(spacecraft).
4. Define a private helper method called fetchData() that receives a com.google.firebase.database.DataSnapshot object. Then loop through the children of this DataSnapshot getting the value of each DataSnapshot child via datasnapshotChild.getValue(Spacecraft.class). Add these values into our private ArrayList.
5. Define a method retrieve(). Add child event listeners to our private DatabaseReference we had maintained. When any DataSnapshot child changes or gets added, call our fetchData() passing in that DataSnapshot as a parameter. This is how fetch data. Then return the filled arraylist.
package com.tutorials.hp.firebasesimplelistview.m_FireBase;

import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseException;
import com.google.firebase.database.DatabaseReference;
import com.tutorials.hp.firebasesimplelistview.m_Model.Spacecraft;

import java.util.ArrayList;

public class FirebaseHelper {

    DatabaseReference db;
    Boolean saved=null;
    ArrayList<String> spacecrafts=new ArrayList<>();

    public FirebaseHelper(DatabaseReference db) {
        this.db = db;
    }

    //WRITE
    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;
    }

    //READ
    public ArrayList<String> 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;
    }

    private void fetchData(DataSnapshot dataSnapshot)
    {
        spacecrafts.clear();

        for (DataSnapshot ds : dataSnapshot.getChildren())
        {
            String name=ds.getValue(Spacecraft.class).getName();
            spacecrafts.add(name);
        }
    }
}
(c). Our MainActivity class
  • Launcher activity
  • Where we bind to listview to our data using arrayadapter
  • Initialize DatabaseReference
  • Show input dialog

It derives from android.support.v7.app.AppCompatActivity.

Here are it's major responsibilities:

No. Responsibility
1. Allow itself to become an android activity component by deriving from android.support.v7.app.AppCompatActivity.
2. Listen to activity creation callback by overrding the onCreate() method.
3. Invoke the onCreate() method of the parent Activity class and tell it of a Bundle we've received.
4. Inflate the activity_main.xml into a View object and set it as the content view of this activity.
5. Search for a toolbar by it's id and set it as our actionbar.
6. Host an input dialog that will be used to save data into Firebase Realtime database.
7. Search for the EditText and Button from our layout and return them as view objects.These widgets will help users perform this data insertion. This by saving data from these EditTexts when the save button is clicked.
8. Find ListView by its id from our layouts.
9. Obtain a com.google.firebase.database.FirebaseDatabase instance then obtain a DatabaseReference from that instance then assign it to our local DatabaseReference private field.
10. Instantiate our CustomAdapter, pass it our data then set the adapter to our ListView.
11. Reference our FloatingActionButton from our activity_main.xml, then listen to its onClick events, then when it's clicked display our input Dialog.
package com.tutorials.hp.firebasesimplelistview;

import android.app.Dialog;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.tutorials.hp.firebasesimplelistview.m_FireBase.FirebaseHelper;
import com.tutorials.hp.firebasesimplelistview.m_Model.Spacecraft;

public class MainActivity extends AppCompatActivity {

    ListView lv;
    ArrayAdapter<String> adapter;
    DatabaseReference db;
    FirebaseHelper helper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        lv= (ListView) findViewById(R.id.lv);

        //SETUP FIREBASE
        db= FirebaseDatabase.getInstance().getReference();
        helper=new FirebaseHelper(db);

        //ADAPTER
        adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,helper.retrieve());
        lv.setAdapter(adapter);

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(MainActivity.this, helper.retrieve().get(position), Toast.LENGTH_SHORT).show();
            }
        });

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                  displayInputDialog();
            }
        });
    }

    private void displayInputDialog()
    {
        Dialog d=new Dialog(this);
        d.setTitle("Save To Firebase");
        d.setContentView(R.layout.input_dialog);

        final EditText nameEditTxt= (EditText) d.findViewById(R.id.nameEditText);
        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();

                //SET DATA
                Spacecraft s=new Spacecraft();
                s.setName(name);

                //VALIDATE
                if(name.length()>0 && name != null)
                {
                    if(helper.save(s))
                    {
                        nameEditTxt.setText("");
                        adapter=new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,helper.retrieve());
                        lv.setAdapter(adapter);

                    }
                }else
                {
                    Toast.makeText(MainActivity.this, "Name cannot be empty", Toast.LENGTH_SHORT).show();
                }

            }
        });

        d.show();
    }

}

Download

Resource Link
GitHub Browse Browse
GitHub Download Link Download

2. Android Firebase - ListView Multiple Fields - Save,Retrieve then Show

Android Firebase Database ListView Tutorial.

This is an android firebase ListView tutorial. We see how to save data to firebase,retrieve then show that data in a custom ListView.

  • Save data from edittext to google firebase database.
  • Retrieve the data by attaching events to a DatabaseReference instance.
  • Bind the data to a custom gridview using Subclass.
(a). Create Basic Activity Project
  1. First create a new project in android studio. Go to File --> New Project.
(b) Create Firebase App

Go to Firbese Console and create a Firebase App. Then register add your android application ID into that app and download the google-services.json file.

There is a wizard that will guide you through this process inside the Firebase Console dashboard.

Add Config File

(c). Add Google services classpath and maven url

Add classpath 'com.google.gms:google-services:3.1.0'. This you do in the project level build.gradle. You may use later versions.

Also add the google maven url in you respositories. Firebase will be fetched from that url.

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'com.google.gms:google-services:3.1.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com" // Google's Maven repository
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
(d). Add Firebase Dependencies

Add FirebaseDatabase dependencies in your app level build.gradle. You may use later versions than me. Then sync the project to download them and add them as part of your project.

apply plugin: 'com.android.application'

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'
    compile 'com.android.support:cardview-v7:23.3.0'

    compile 'com.google.firebase:firebase-core:11.8.0'
    compile 'com.google.firebase:firebase-database:11.8.0'
}
apply plugin: 'com.google.gms.google-services'

Make sure you apply plugin: 'com.google.gms.google-services' as above.

(e). AndroidManifest.xml
  • Remember to add permission for internet in your manifest file. This is because Firebase is cloud based and we need internet connection permission to access internet in android.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutorials.hp.firebaselistviewmulti_items">

    <uses-permission android:name="android.permission.INTERNET"/>
    ...
</manifest>

2. XML Layouts

Here are our layouts for this project:

(a). activity_main.xml
  • This layout gets inflated to MainActivity user interface.
  • It includes the content_main.xml.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.tutorials.hp.firebaselistviewmulti_items.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>

 

(b). ContenMain.xml

This is alayout that will get included as part of our activity_main.xml layout.

Here are the roles of this layout:

No. Responsibility
1. Define a ListView identified by a unique id. That ListView is our adapterview and will render our realtime data from Firebase.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.tutorials.hp.firebaselistviewmulti_items.MainActivity"
    tools:showIn="@layout/activity_main">

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
         />
</RelativeLayout>

 

(c). InputDialog.xml

This is our input form layout.

Here are it's roles:

No. Responsibility
1. Define three EditTexts for writing data to firebase. Wrap those edittexts in a TextInputLayout to give them a material design feel.
2. Define a Button to be used as our action button to for saving data to firebase.
3. Align all these widgets in a vertical manner with the help of a LinearLayout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="?attr/actionBarSize"
        android:orientation="vertical"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        android:paddingTop="50dp">

        <android.support.design.widget.TextInputLayout
            android:id="@+id/nameLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/nameEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:hint= "Name" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:id="@+id/propLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/propellantEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:hint= "Propellant" />

        <android.support.design.widget.TextInputLayout
            android:id="@+id/descLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/descEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:hint= "Description" />
        </android.support.design.widget.TextInputLayout>

        </android.support.design.widget.TextInputLayout>

        <Button android:id="@+id/saveBtn"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Save"
            android:clickable="true"
            android:background="@color/colorAccent"
            android:layout_marginTop="40dp"
            android:textColor="@android:color/white"/>

    </LinearLayout>

</LinearLayout>
(d). Model.xml

This is our ListView row model layout.

It has the following responsibilities:

No. Responsibility
1. Define three TextViews for displaying each spacecraft's details.
2. Align those TextViews vertically using a LinearLayout.
3. Define a root CardView to wrap all these under one roof.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_margin="10dp"
    card_view:cardCornerRadius="5dp"
    card_view:cardElevation="5dp"
    android:layout_height="200dp">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:text="Name"
                android:id="@+id/nameTxt"
                android:padding="10dp"
                android:textColor="@color/colorAccent"
                android:textStyle="bold"
                android:layout_alignParentLeft="true"
                />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:text="Description....................."
                android:lines="3"
                android:id="@+id/descTxt"
                android:padding="10dp"
                android:layout_alignParentLeft="true"
                />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:text="Propellant"
                android:textStyle="italic"
                android:id="@+id/propellantTxt" />

    </LinearLayout>

</android.support.v7.widget.CardView>

Java Classes

(a). Spacecraft.java
  • This is our Data Object class
  • Note that it Must Have an empty constructor.
  • You can create,pass data to and use other constructors

This is our ListView row model layout.

It has the following responsibilities:

No. Responsibility
1. Define three private fields which will act as the properties of this spacecraft. These include: name,propellant and description.
2. Define one empty constructor which is requireb by Firebase.
3. Expose our instance fields for modifications or data retrieval via setters and getters respectively.
package com.tutorials.hp.firebaselistviewmulti_items.m_Model;

public class Spacecraft {
    String name,propellant,description;

    public Spacecraft() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPropellant() {
        return propellant;
    }

    public void setPropellant(String propellant) {
        this.propellant = propellant;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
(b). Our FirebaseHelper Class
  • Basically,our CRUD class.
  • Here we perform reads and writes to Firebase database.
  • To persist data we use setValue().
  • Prior to calling setValue() method,we call push() to ensure we append data to database,not replace.
  • We fill an arraylist with model objects.

Here are the major responsibilities of this class:

No. Responsibility
1. Maintain three instance fields: a DatabaseReference, a Boolean and an ArrayList.
2. Obtain a DatabaseReference via the parameter from outside and assign it to the one we maintain locally.
3. Define a public method save() that receives a Spacecraft object, then attempt to save it to Firebase and return either true or false based on the success. To save data we use db.child("Spacecraft").push().setValue(spacecraft).
4. Define a private helper method called fetchData() that receives a com.google.firebase.database.DataSnapshot object. Then loop through the children of this DataSnapshot getting the value of each DataSnapshot child via datasnapshotChild.getValue(Spacecraft.class). Add these values into our private ArrayList.
5. Define a method retrieve(). Add child event listeners to our private DatabaseReference we had maintained. When any DataSnapshot child changes or gets added, call our fetchData() passing in that DataSnapshot as a parameter. This is how fetch data. Then return the filled arraylist.
package com.tutorials.hp.firebaselistviewmulti_items.m_FireBase;

import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseException;
import com.google.firebase.database.DatabaseReference;
import com.tutorials.hp.firebaselistviewmulti_items.m_Model.Spacecraft;

import java.util.ArrayList;

/*
 * 1.SAVE DATA TO FIREBASE
 * 2. RETRIEVE
 * 3.RETURN AN ARRAYLIST
 */
public class FirebaseHelper {

    DatabaseReference db;
    Boolean saved;
    ArrayList<Spacecraft> spacecrafts=new ArrayList<>();

    /*
 PASS DATABASE REFRENCE
  */
    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);
        }
    }

    //RETRIEVE
    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) {

            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });

        return spacecrafts;
    }

}
(c). : Our CustomAdapter class

Our adaoter class.

  • Responsible for Layout Inflation.
  • Also for data binding to views.
  • Handling ItemClicks as well
  • This class subclasses BaseAdapter

Here are it's roles:

No. Responsibility
1. Accept the responsibilities of an adapter by deriving from the android.widget.BaseAdapter.
2. Maintain private Context and ArrayList instance fields.
3. Receive a Context and an ArrayList from outside and assign them to the ones we maintain locally.
4. Return the count of items to be rendered by our adapter. We do this using the getCount() method.
5. Return a particular spacecraft from via the getItem() method as long as you pass us it's position.
6. Use individual spacecraft's positions in the adapter as their unique ids.
7. Inflate our model.xml using the LayoutInflater class and return the resultant view object. All these are done inside the getView() method.
8. Listen to each inflated view's row click events thus showing a Toast message.
package com.tutorials.hp.firebaselistviewmulti_items.m_UI;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.tutorials.hp.firebaselistviewmulti_items.R;
import com.tutorials.hp.firebaselistviewmulti_items.m_Model.Spacecraft;

import java.util.ArrayList;

/*
 * 1. where WE INFLATE OUR MODEL LAYOUT INTO VIEW ITEM
 * 2. THEN BIND DATA
 */
public class CustomAdapter extends BaseAdapter{
    Context c;
    ArrayList<Spacecraft> spacecrafts;

    public CustomAdapter(Context c, ArrayList<Spacecraft> spacecrafts) {
        this.c = c;
        this.spacecrafts = spacecrafts;
    }

    @Override
    public int getCount() {
        return spacecrafts.size();
    }

    @Override
    public Object getItem(int position) {
        return spacecrafts.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView==null)
        {
            convertView= LayoutInflater.from(c).inflate(R.layout.model,parent,false);
        }

        TextView nameTxt= (TextView) convertView.findViewById(R.id.nameTxt);
        TextView propTxt= (TextView) convertView.findViewById(R.id.propellantTxt);
        TextView descTxt= (TextView) convertView.findViewById(R.id.descTxt);

        final Spacecraft s= (Spacecraft) this.getItem(position);

        nameTxt.setText(s.getName());
        propTxt.setText(s.getPropellant());
        descTxt.setText(s.getDescription());

        //ONITECLICK
        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(c,s.getName(),Toast.LENGTH_SHORT).show();
            }
        });
        return convertView;
    }
}
(d). Our MainActivity
  • Launcher activity.
  • Reference ListView and set its adapter.
  • Shows Input Dialog on FAB button click.
  • Sets up our Firebase's by initializing the DatabaseReference.

It derives from android.support.v7.app.AppCompatActivity.

Here are it's major responsibilities:

No. Responsibility
1. Allow itself to become an android activity component by deriving from android.support.v7.app.AppCompatActivity.
2. Listen to activity creation callback by overrding the onCreate() method.
3. Invoke the onCreate() method of the parent Activity class and tell it of a Bundle we've received.
4. Inflate the activity_main.xml into a View object and set it as the content view of this activity.
5. Search for a toolbar by it's id and set it as our actionbar.
6. Host an input dialog that will be used to save data into Firebase Realtime database.
7. Search for the various EditTexts and Buttons from our layout and return them as view objects.These widgets will help users perform this data insertion. Then save data from these EditTexts when the save button is clicked.
8. Find ListView by its id from our layouts.
9. Obtain a com.google.firebase.database.FirebaseDatabase instance then obtain a DatabaseReference from that instance then assign it to our local DatabaseReference private field.
10. Instantiate our CustomAdapter, pass it our data then set the adapter to our ListView.
11. Reference our FloatingActionButton from our activity_main.xml, then listen to its onClick events, then when it's clicked display our input Dialog.
package com.tutorials.hp.firebaselistviewmulti_items;

import android.app.Dialog;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.tutorials.hp.firebaselistviewmulti_items.m_FireBase.FirebaseHelper;
import com.tutorials.hp.firebaselistviewmulti_items.m_Model.Spacecraft;
import com.tutorials.hp.firebaselistviewmulti_items.m_UI.CustomAdapter;

/*
1.INITIALIZE FIREBASE DB
2.INITIALIZE UI
3.DATA INPUT
 */
public class MainActivity extends AppCompatActivity {

    DatabaseReference db;
    FirebaseHelper helper;
    CustomAdapter adapter;
    ListView lv;
    EditText nameEditTxt, propTxt, descTxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        lv = (ListView) findViewById(R.id.lv);

        //INITIALIZE FIREBASE DB
        db = FirebaseDatabase.getInstance().getReference();
        helper = new FirebaseHelper(db);

        //ADAPTER
        adapter = new CustomAdapter(this, helper.retrieve());
        lv.setAdapter(adapter);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                displayInputDialog();
            }
        });
    }

    //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);
        propTxt = (EditText) d.findViewById(R.id.propellantEditText);
        descTxt = (EditText) d.findViewById(R.id.descEditText);
        Button saveBtn = (Button) d.findViewById(R.id.saveBtn);

        //SAVE
        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);

                //SIMPLE VALIDATION
                if (name != null && name.length() > 0) {
                    //THEN SAVE
                    if (helper.save(s)) {
                        //IF SAVED CLEAR EDITXT
                        nameEditTxt.setText("");
                        propTxt.setText("");
                        descTxt.setText("");

                        adapter = new CustomAdapter(MainActivity.this, helper.retrieve());
                        lv.setAdapter(adapter);

                    }
                } else {
                    Toast.makeText(MainActivity.this, "Name Must Not Be Empty", Toast.LENGTH_SHORT).show();
                }

            }
        });

        d.show();
    }
}

10. Reminders

  • Remember to add permission for internet in your manifest file. This is because Firebase is cloud based and we need internet connection permission to access internet in android.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutorials.hp.firebaselistviewmulti_items">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

4. Download

Resource Link
GitHub Browse Browse
GitHub Download Link Download

3. Android Firebase - ListView Master Detail - Save,Retrieve,Show [Open Activity]

Android Firebase ListView Master Detail  Tutorial.

*his is an Android Firebase ListView Master Detail tutorial. We see how to save to Firebase from our android app, retrieve data, and show in a ListView.

The ListView will be rendered in our Master View.

Then when a ListView item is clicked we open a new activity, our detail activity. Our ListView will comprise a List of Spacecraft objects.

So in the detail view we show the details of the clicked Spacecraft.

  • Save data from edittext to google firebase database.
  • Retrieve the data by attaching events to a DatabaseReference instance.
  • Bind the data to a custom ListView using a BaseAdapter subclass.
  • Handle the ListView's itemClicks.
  • Open new Activity when a grid item is clicked.
  • Pass data to that new activity

Project Summary

Here's the Project Summary

No. File Major Responsibility
1. Spacecraft.java Represents a single Spacecraft and it's properties like name,propellant and description.
2. FirebaseHelper.java This class has allows us perform Firebase CRUD operations.
3. CustomAdapter.java Our adapter class
4. DetailActivity.java Our Detail Activity to show a single spacecraft's details.
5. MainActivity.java Our Master Activity. It shows the list of Spacecrafts
6. activity_main.xml Our Master Activity's layout.
7. content_main.xml Our Master Activity's content detail.
8. activity_detail.xml Our Detail Activity's main layout.
9. content_detail.xml Our Detail Activity's content layout.
10. input_dialog.xml Our input dialog layout.
11. model.xml Each ListView's grid model.

Setting Up

(a). Create Basic Activity Project
  1. First create a new project in android studio. Go to File --> New Project.
(b). Create Firebase and Download Configuration File

Head over to Firebase Console, create a Firebase App, Register your app id and download the google-services.json file. Add it to your app folder.

Add Config File

(c). Specify Maven repository URL

Head over to project level(project folder) build.gradle and

  1. Add Google services classpath as below
  2. Add maven repository url
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'com.google.gms:google-services:3.1.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com" // Google's Maven repository
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
(c). Add Firebase Dependencies

Add them in you app level(app folder) build.gradle, then

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'
    compile 'com.android.support:cardview-v7:23.3.0'

    compile 'com.google.firebase:firebase-core:11.8.0'
    compile 'com.google.firebase:firebase-database:11.8.0'
}
apply plugin: 'com.google.gms.google-services'

Make sure you apply plugin: 'com.google.gms.google-services' as above.

(d). AndroidManifest.xml
  • Remember to add permission for internet in your manifest file.
<manifest>
....
    <uses-permission android:name="android.permission.INTERNET" />
....
</manifest>

Here's mine in full:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutorials.hp.firebaselistviewmdetail">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".DetailActivity"
            android:label="Detail View"
            android:theme="@style/AppTheme.NoActionBar"></activity>
    </application>

</manifest>

Our Classes.

So now we look at the Java classes. Basically we have 5 classes; one data object, one adapter class, one FirebaseHelper class and two activities.

(a). Spacecraft.java

This is our data object class. It represents a single Spacecraft. It's our POJO class. Here's its responsibilities:

No. Responsibility
1. Represents a Single Spacecraft
2. Set Spacecraft properties: name,propellant and description.
3. Get Spacecraft properties: name,propellant and description.
  • Is our Data Object class
  • Must Have an empty constructor.
  • You can create,pass data to and use other constructors
package com.tutorials.hp.firebaselistviewmdetail.m_Model;

/*
 * 1. OUR MODEL CLASS
 */
public class Spacecraft {

    String name,propellant,description;

    public Spacecraft() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPropellant() {
        return propellant;
    }

    public void setPropellant(String propellant) {
        this.propellant = propellant;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
(b). Our FirebaseHelper Class
  • Basically,our CRUD class.
  • Here we perform reads and writes to Firebase database.
  • To persist data we use setValue().
  • Prior to calling setValue() method,we call push() to ensure we append data to database,not replace.
  • We fill an arraylist with spacecraft objects.

This class allows us perform save and retrieve data to Firebase Realtime database.

No. Responsibility
1. Keep hold of three Objects: DatabaseReference,a Boolean saved value, and an ArrayList of Spacecrafts.
2. Obtain a DatabaseReference object via the constructor and Assign it to our local db data member.
3. Take a Spacecraft object and save it to Firebase this returning a Boolean indicating success or failure.
4. Loop through DataSnapshot children nodes obtaining all the Spacecraft objects from Firebase and fill our local arraylist with those objects.
5. Listen to Firebase Children mutation events like when a DataSnapshot child has been added, moved, removed, changed or cancelled. This allows us to fetch data in realtime.
package com.tutorials.hp.firebaselistviewmdetail.m_FireBase;

import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseException;
import com.google.firebase.database.DatabaseReference;
import com.tutorials.hp.firebaselistviewmdetail.m_Model.Spacecraft;

import java.util.ArrayList;

/
 * 1.SAVE DATA TO FIREBASE
 * 2. RETRIEVE
 * 3.RETURN AN ARRAYLIST
 */
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 BY HOOKING ONTO DATABASE OPERATION CALLBACKS
    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) {

            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });

        return spacecrafts;
    }
}
(c). Our CustomAdapter class
  • Responsible for Layout Inflation.
  • Also for data binding to views.
  • Then opens new activity and passes data to it via android.Content.Intent.

This is our adapter class. It derives from BaseAdapter.

No. Responsibility
1. This class will maintain a Context object that will be used to during layout inflation. Furthermore we declare an ArrayList of Spacecrafts that will be bound to our listview.
2. Receive a Context and ArrayList of Spacecrafts from outside and assign them to our local instance fields.
3. Return data list count,Item and Item Identifier.
4. Inflate our model.xml layout and return it as a View when the getView() is called.
5. Listen to the inflated View click event and open our Master activity.
6. Pass the clicked spacecraft's details to the Detail Activity.
package com.tutorials.hp.firebaselistviewmdetail.m_UI;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.tutorials.hp.firebaselistviewmdetail.DetailActivity;
import com.tutorials.hp.firebaselistviewmdetail.R;
import com.tutorials.hp.firebaselistviewmdetail.m_Model.Spacecraft;

import java.util.ArrayList;

/*
 * 1. where WE INFLATE OUR MODEL LAYOUT INTO VIEW ITEM
 * 2. THEN BIND DATA
 */
public class CustomAdapter extends BaseAdapter {
    Context c;
    ArrayList<Spacecraft> spacecrafts;

    public CustomAdapter(Context c, ArrayList<Spacecraft> spacecrafts) {
        this.c = c;
        this.spacecrafts = spacecrafts;
    }

    @Override
    public int getCount() {
        return spacecrafts.size();
    }

    @Override
    public Object getItem(int pos) {
        return spacecrafts.get(pos);
    }

    @Override
    public long getItemId(int pos) {
        return pos;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {
        if(convertView==null)
        {
            convertView= LayoutInflater.from(c).inflate(R.layout.model,viewGroup,false);
        }

        TextView nameTxt= (TextView) convertView.findViewById(R.id.nameTxt);
        TextView propTxt= (TextView) convertView.findViewById(R.id.propellantTxt);
        TextView descTxt= (TextView) convertView.findViewById(R.id.descTxt);

        final Spacecraft s= (Spacecraft) this.getItem(position);

        nameTxt.setText(s.getName());
        propTxt.setText(s.getPropellant());
        descTxt.setText(s.getDescription());

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //OPEN DETAIL
                openDetailActivity(s.getName(),s.getDescription(),s.getPropellant());
            }
        });

        return convertView;
    }
    //OPEN DETAIL ACTIVITY
    private void openDetailActivity(String...details)
    {
        Intent i=new Intent(c,DetailActivity.class);
        i.putExtra("NAME_KEY",details[0]);
        i.putExtra("DESC_KEY",details[1]);
        i.putExtra("PROP_KEY",details[2]);

        c.startActivity(i);
    }
}
(d). Our MainActivity

This is our MainActivity. Our project has two activities and this is the main one. It will be the one launched when we launch our application.

It is also our Master View and will contain a list of Spacecraft objects.

  • Launcher activity.
  • Reference ListView set its adapter.
  • Shows Input Dialog on FAB button click.
  • Sets up our Firebase's by initializing the DatabaseReference.
No. Responsibility
1. It will maintain a couple of objects as instance fields including: DatabaseReference,FirebaseHelper,CustomAdapter, ListView and three EditTexts.
2. Define a method to instantiate our Dialog object, set it's title, set its ConteView and finally show it.This dialog is our input dialog with edittexts and save/retrieve buttons.
3. Search all the input widgets defined in input_dialog.xml and assign them to their respective instance objects.These include EditTexts and Buttons.
4. Listen to Save button click events, then obtain edittext values, assign those values to a Spacecraft object and with the help of FirebaseHelper instance send that object to Firebase realtime database.
5. Override the onCreate() method,call it's super equivalence.
6. Find Toolbar in our layout and use it as our actionbar.
7. Get FirebaseDatabase instance then it's reference and pass it to our FirebaseHelper constructor.
8. Instantiate CustomAdapter, find listview from our layout, then assign the adapter to the listview.
9. Listen to FAB button click event and show the input dialog.
package com.tutorials.hp.firebaselistviewmdetail;

import android.app.Dialog;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.Toast;

import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.tutorials.hp.firebaselistviewmdetail.m_FireBase.FirebaseHelper;
import com.tutorials.hp.firebaselistviewmdetail.m_Model.Spacecraft;
import com.tutorials.hp.firebaselistviewmdetail.m_UI.CustomAdapter;

/*
1.INITIALIZE FIREBASE DB
2.INITIALIZE UI
3.DATA INPUT
 */
public class MainActivity extends AppCompatActivity {

    DatabaseReference db;
    FirebaseHelper helper;
    CustomAdapter adapter;
    ListView lv;
    EditText nameEditTxt,propTxt,descTxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        lv = (ListView) findViewById(R.id.lv);

        //INITIALIZE FIREBASE DB
        db= FirebaseDatabase.getInstance().getReference();
        helper=new FirebaseHelper(db);

        //ADAPTER
        adapter=new CustomAdapter(this,helper.retrieve());
        lv.setAdapter(adapter);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                displayInputDialog();
            }
        });
    }

    //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);
        propTxt= (EditText) d.findViewById(R.id.propellantEditText);
        descTxt= (EditText) d.findViewById(R.id.descEditText);
        Button saveBtn= (Button) d.findViewById(R.id.saveBtn);

        //SAVE
        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);

                //SIMPLE VALIDATION
                if(name != null && name.length()>0)
                {
                    //THEN SAVE
                    if(helper.save(s))
                    {
                        //IF SAVED CLEAR EDITXT
                        nameEditTxt.setText("");
                        propTxt.setText("");
                        descTxt.setText("");

                        adapter=new CustomAdapter(MainActivity.this,helper.retrieve());
                        lv.setAdapter(adapter);

                    }
                }else
                {
                    Toast.makeText(MainActivity.this, "Name Must Not Be Empty", Toast.LENGTH_SHORT).show();
                }

            }
        });

        d.show();
    }

}
(e). Our DetailActivity

Go ahead create a SecondActivity that will be used as the Detail View.

It will display selected Spacecraft details.

We'll look at its source later. However note that it will add two XML layouts: activity_detail and content_detail to our layout resources.

  • The DetailActivity will show our details.
  • Receives data from MainActivity via Intent.
  • Shows the data in TextViews.

Here's it's responsibilities and how it works:

No. Responsibility
1. Maintain three TextView objects as private instance fields that will be used to show Spacecraft details.
2. Override the onCreate() method. Call the super class version of onCreate() as well.
3. Inflate the activity_detail via the setContentView() to a View object and set it as the detail Activity's main UI.
4. Find the toolbar from activity_detail and set it as the actionbar of our SecondActivity.
5. Find TextViews defined in the content_detail.xml and assign them to our local TextView objects.
6. Retrieve the Intent assoicated with our DetailActivity via the getIntent() call.
7. Obtain name, description and propellant of our Spacecraft via the getExtras() method calls of our Intent.Then set those values to our TextView objects.
package com.tutorials.hp.firebaselistviewmdetail;

import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.TextView;

public class DetailActivity extends AppCompatActivity {

    TextView nameTxt,descTxt, propTxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

        nameTxt = (TextView) findViewById(R.id.nameDetailTxt);
        descTxt= (TextView) findViewById(R.id.descDetailTxt);
        propTxt = (TextView) findViewById(R.id.propellantDetailTxt);

        //GET INTENT
        Intent i=this.getIntent();

        //RECEIVE DATA
        String name=i.getExtras().getString("NAME_KEY");
        String desc=i.getExtras().getString("DESC_KEY");
        String propellant=i.getExtras().getString("PROP_KEY");

        //BIND DATA
        nameTxt.setText(name);
        descTxt.setText(desc);
        propTxt.setText(propellant);

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

}

3. Our Layouts

(a). activity_main.xml
  • This layout gets inflated to MainActivity user interface.
  • It includes the content_main.xml.
  • MainActivity is our Master View.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.tutorials.hp.firebaselistviewmdetail.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
(b). ContentMain.xml

This layout gets included in your activity_main.xml. We define our ListView here.

  • Our Master View
  • Holds our ListView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.tutorials.hp.firebaselistviewmdetail.MainActivity"
    tools:showIn="@layout/activity_main">

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
         />
</RelativeLayout>
(c). InputDialog.xml

This is layout will get inflated into a Dialog.

The dialog will have a couple of EditTexts and a Button for saving data to Firebase.

Basically this will be our input dialog.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="?attr/actionBarSize"
        android:orientation="vertical"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        android:paddingTop="50dp">

        <android.support.design.widget.TextInputLayout
            android:id="@+id/nameLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/nameEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:hint= "Name" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:id="@+id/propLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/propellantEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:hint= "Propellant" />

        <android.support.design.widget.TextInputLayout
            android:id="@+id/descLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/descEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:hint= "Description" />
        </android.support.design.widget.TextInputLayout>

        </android.support.design.widget.TextInputLayout>

        <Button android:id="@+id/saveBtn"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Save"
            android:clickable="true"
            android:background="@color/colorAccent"
            android:layout_marginTop="40dp"
            android:textColor="@android:color/white"/>
    </LinearLayout>
</LinearLayout>
(c).Model.xml

This is the custom row model for our ListView. It basically defines how each ListViewItem will appear.

In our case we have multiple TextViews to display the properties of each Spacecraft. At the root we have a CardView:

 <?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_margin="10dp"
    card_view:cardCornerRadius="5dp"
    card_view:cardElevation="5dp"
    android:layout_height="200dp">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:text="Name"
                android:id="@+id/nameTxt"
                android:padding="10dp"
                android:textColor="@color/colorAccent"
                android:textStyle="bold"
                android:layout_alignParentLeft="true"
                />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:text="Description....................."
                android:lines="3"
                android:id="@+id/descTxt"
                android:padding="10dp"
                android:layout_alignParentLeft="true"
                />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:text="Propellant"
                android:textStyle="italic"
                android:id="@+id/propellantTxt" />
    </LinearLayout>
</android.support.v7.widget.CardView>

(d). activity_detail.xml

This is the main layout for our SecondActivity.java which is our DetailActivity. This layout is basically similar to activity_main.xml.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.tutorials.hp.firebaselistviewmdetail.DetailActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_detail" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
(e).ContentDetail.xml

This layout will get included in the activity_detail.xml.

We add a CardView with a couple of TextViews here that will be used to render data from the Master activity.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.tutorials.hp.firebaselistviewmdetail.DetailActivity"
    tools:showIn="@layout/activity_detail">

    <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal" android:layout_width="match_parent"
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:layout_margin="5dp"
        card_view:cardCornerRadius="10dp"
        card_view:cardElevation="5dp"

        android:layout_height="match_parent">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:weightSum="1">

            <LinearLayout
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <ImageView
                    android:id="@+id/articleDetailImg"
                    android:layout_width="320dp"
                    android:layout_height="wrap_content"
                    android:paddingLeft="10dp"
                    android:layout_alignParentTop="true"
                    android:scaleType="centerCrop"
                    android:src="@drawable/spitzer" />

                <LinearLayout
                    android:orientation="vertical"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                    <TextView
                        android:id="@+id/nameDetailTxt"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textAppearance="?android:attr/textAppearanceLarge"
                        android:padding="5dp"
                        android:minLines="1"
                        android:textStyle="bold"
                        android:textColor="@color/colorAccent"
                        android:text="Title" />

                </LinearLayout>
            </LinearLayout>

            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="match_parent"
                android:layout_marginTop="?attr/actionBarSize"
                android:orientation="vertical"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:paddingTop="5dp">

                <TextView
                    android:id="@+id/propellantDetailTxt"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceLarge"
                    android:padding="5dp"
                    android:minLines="1"
                    android:text="DATE" />
                <TextView
                    android:id="@+id/descDetailTxt"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceLarge"
                    android:padding="5dp"
                    android:textColor="#0f0f0f"
                    android:minLines="4"
                    android:text="Space craft details...." />

                <TextView
                    android:id="@+id/linkDetailTxt"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceMedium"
                    android:padding="5dp"
                    android:textColor="@color/colorPrimaryDark"
                    android:textStyle="italic"
                    android:text="Link" />

            </LinearLayout>

        </LinearLayout>
    </android.support.v7.widget.CardView>

</RelativeLayout>

4. Download

Resource Link
GitHub Browse Browse
GitHub Download Link Download
Video Tutorial Video

How To Run

  1. Download the project.
  2. You'll get a zipped file,extract it.
  3. Open the Android Studio.
  4. Now close, already open project.
  5. From the Menu bar click on File >New> Import Project.
  6. Now Choose a Destination Folder, from where you want to import project.
  7. Choose an Android Project.
  8. Now Click on “OK“.
  9. Done, your done importing the project,now edit it.
  10. You'll need to head over to Firebase Console, create app, then download configuration file and add to your project in the app folder.You also have to allow writes and reads from the FirebaseDatabase without authentication.

How do You Feel after reading this?

According to scientists, we humans have 8 primary innate emotions: joy, acceptance, fear, surprise, sadness, disgust, anger, and anticipation. Feel free to tell us how you feel about this article using these emotes or via the comment section. This feedback helps us gauge our progress.

Help me Grow.

I set myself some growth ambitions I desire to achieve by this year's end regarding this website and my youtube channel. Am halfway. Help me reach them by:




Recommendations


What do You Think


Previous Post Next Post