Android Programming

Android Firebase RecyclerView - With Images and Text

NB/= THE CONFIGURATION FOR FIREBASE HAS RECENTLY CHANGED,SO PLEASE YOU BETTER WATCH OUR NEWER FIREBASE TUTORIALS.THE CONCEPT OF IMAGE URL IS STILL RELEVANT,ONLY CONFIGURATION.

Hello friends.Today we Explore Android Firebase RecyclerView - With Images and Text.Our purpose is simple: Store our text data and image urls in Firebase database.

Then retreive them in realtime.We then use Picasso to fetch the image via our newfound URL. I hosted my images in Cloudinary Look guys,if your want detailed explanations of Android Firebase RecyclerView please watch my video tutorial here. And ooh,subscribe and leave us a big like if you don't mind.

1. Create Basic Activity Project

  1. First create a new project in android studio. Go to File --> New Project.

  2. Type the application name and choose the company name. New Project Dialog

  3. Choose minimum SDK. Choose minimum SDK

  4. Choose Basic activity. Choose Empty Activity

  5. Click Finish. Finish

Basic activity will have a toolbar and floating action button already added in the layout

Normally two layouts get generated with this option:

No. Name Type Description
1. activity_main.xml XML Layout Will get inflated into MainActivity Layout.Typically contains appbarlayout with toolbar.Also has a floatingactionbutton.
2. content_main.xml XML Layout Will be included into activity_main.xml.You add your views and widgets here.
3. MainActivity.java Class Main Activity.

In this example I used a basic activity.

The activity will automatically be registered in the android_manifest.xml. Android Activities are components and normally need to be registered as an application component.

If you've created yours manually then register it inside the <application>...<application> as following, replacing the MainActivity with your activity name:


        <activity android:name=".MainActivity">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

You can see that one action and category are specified as intent filters. The category makes our MainActivity as launcher activity. Launcher activities get executed first when th android app is run.

Advantage of Creating Basic Activity project

You can optionally choose empty activity over basic activity for this project.

However basic activity has the following advantages:

No. Advantage
1. Provides us a readymade toolbar which gives us actionbar features yet easily customizable
2. Provides us with appbar layout which implements material design appbar concepts.
3. Provides a FloatinActionButton which we can readily use to initiate quick actions especially in examples like these.
4. Decouples our custom content views and widgets from the templating features like toolbar.

Generated Project Structure

AndroidStudio will generate for you a project with default configurations via a set of files and directories.

Here are the most important of them:

No. File Major Responsibility
1. build/ A directory containing resources that have been compiled from the building of application and the classes generated by android tools. Such a tool is the R.java file. R.java file normally holds the references to application resources.
2. libs/ To hold libraries we use in our project.
3. src/main/ To hold the source code of our application.This is the main folder you work with.
4. src/main/java/ Contains our java classes organized as packages.
5. src/main/res/ Contains our project resources folders as follows.
6. src/main/res/drawable/ Contains our drawable resources.
7. src/main/res/layout/ Contains our layout resources.
8. src/main/res/menu/ Contains our menu resources XML code.
9. src/main/res/values/ Contains our values resources XML code.These define sets of name-value pairs and can be strings, styles and colors.
10. AndroidManifest.xml This file gets autogenerated when we create an android project.It will define basic information needed by the android system like application name,package name,permissions,activities,intents etc.
11. build.gradle Gradle Script used to build the android app.

3. 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

4. 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
}

5. 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.

6. Our MainActivity

This is our main activity.

package com.tutorials.hp.recyclerfirebaseimagestext;

import android.app.Dialog;
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.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.EditText;

import com.tutorials.hp.recyclerfirebaseimagestext.mFireBase.FireBaseClient;

public class MainActivity extends AppCompatActivity {

     final static String DB_URL="https://ourdata.firebaseio.com/";
    EditText nameEditText,urlEditText;
    Button saveBtn;
    RecyclerView rv;

    FireBaseClient fireBaseClient;

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

        rv= (RecyclerView) findViewById(R.id.mRecylcerID);
        rv.setLayoutManager(new LinearLayoutManager(this));

        fireBaseClient=new FireBaseClient(this,DB_URL,rv);

        fireBaseClient.refreshData();

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                displayDialog();
            }
        });
    }

    //SHOW INPUT DIALOG
    private void displayDialog()
    {
        Dialog d=new Dialog(this);
        d.setTitle("Save Online");
        d.setContentView(R.layout.dialoglayout);

        nameEditText= (EditText) d.findViewById(R.id.nameEditText);
        urlEditText= (EditText) d.findViewById(R.id.urlEditText);

        saveBtn= (Button) d.findViewById(R.id.saveBtn);

        saveBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                fireBaseClient.saveOnline(nameEditText.getText().toString(),urlEditText.getText().toString());

                nameEditText.setText("");
                urlEditText.setText("");
            }
        });

        //SHOW
        d.show();
    }

}

7. Our POJO Class

This is our data object class.

package com.tutorials.hp.recyclerfirebaseimagestext.mData;

public class Movie {

    private String name;
    private String url;

    public Movie() {
    }

    public String getName() {
        return name;
    }

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

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

8. Our Picasso Client

  • For loading and cahing images
package com.tutorials.hp.recyclerfirebaseimagestext.mPicasso;

import android.content.Context;
import android.widget.ImageView;

import com.squareup.picasso.Picasso;
import com.tutorials.hp.recyclerfirebaseimagestext.R;

public class PicassoClient {

    public static void downloadImage(Context c,String url,ImageView img)
    {
        if(url != null && url.length()>0)
        {
            Picasso.with(c).load(url).placeholder(R.drawable.placeholder).into(img);
        }else {
            Picasso.with(c).load(R.drawable.placeholder).into(img);
        }
    }
}

9. Our Firebase Client class

  • To talk to our Firebase db
package com.tutorials.hp.recyclerfirebaseimagestext.mFireBase;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;

import com.firebase.client.ChildEventListener;
import com.firebase.client.DataSnapshot;
import com.firebase.client.Firebase;
import com.firebase.client.FirebaseError;
import com.tutorials.hp.recyclerfirebaseimagestext.mData.Movie;
import com.tutorials.hp.recyclerfirebaseimagestext.mRecycler.MyAdapter;

import java.util.ArrayList;

public class FireBaseClient {

    Context c;
    String DB_URL;
    RecyclerView rv;

    Firebase fire;
    ArrayList<Movie> movies=new ArrayList<>();
    MyAdapter adapter;

    public FireBaseClient(Context c, String DB_URL, RecyclerView rv) {
        this.c = c;
        this.DB_URL = DB_URL;
        this.rv = rv;

        //INITIALIZE
        Firebase.setAndroidContext(c);

        //INSTANTIATE
        fire=new Firebase(DB_URL);
    }

    //SAVE
    public void saveOnline(String name,String url)
    {
        Movie m=new Movie();
        m.setName(name);
        m.setUrl(url);

        fire.child("Movie").push().setValue(m);
    }

    //RETRIEVE
    public void refreshData()
    {
        fire.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                getUpdates(dataSnapshot);
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                 getUpdates(dataSnapshot);
            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {

            }

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

            }

            @Override
            public void onCancelled(FirebaseError firebaseError) {

            }
        });
    }

    private void getUpdates(DataSnapshot dataSnapshot)
    {
        movies.clear();
        for(DataSnapshot ds : dataSnapshot.getChildren())
        {
            Movie m=new Movie();
            m.setName(ds.getValue(Movie.class).getName());
            m.setUrl(ds.getValue(Movie.class).getUrl());

            movies.add(m);
        }

        if(movies.size()>0)
        {
            adapter=new MyAdapter(c,movies);
            rv.setAdapter(adapter);
        }else {
            Toast.makeText(c,"No data",Toast.LENGTH_SHORT).show();
        }
    }

}

10. Our ViewHolder class

  • Hold views for recycling
package com.tutorials.hp.recyclerfirebaseimagestext.mRecycler;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.tutorials.hp.recyclerfirebaseimagestext.R;


public class MyHolder extends RecyclerView.ViewHolder {

    TextView nameTxt;
    ImageView img;

    public MyHolder(View itemView) {
        super(itemView);

        nameTxt= (TextView) itemView.findViewById(R.id.nameTxt);
        img= (ImageView) itemView.findViewById(R.id.movieImage);

    }
}

11. Our Adapter class

  • Layout inflation.
  • Then bind data to views
package com.tutorials.hp.recyclerfirebaseimagestext.mRecycler;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.tutorials.hp.recyclerfirebaseimagestext.R;
import com.tutorials.hp.recyclerfirebaseimagestext.mData.Movie;
import com.tutorials.hp.recyclerfirebaseimagestext.mPicasso.PicassoClient;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyHolder> {

    Context c;
    ArrayList<Movie> movies;

    public MyAdapter(Context c, ArrayList<Movie> movies) {
        this.c = c;
        this.movies = movies;
    }

    @Override
    public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.model,parent,false);
        MyHolder holder=new MyHolder(v);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyHolder holder, int position) {
        holder.nameTxt.setText(movies.get(position).getName());

        PicassoClient.downloadImage(c,movies.get(position).getUrl(),holder.img);
    }

    @Override
    public int getItemCount() {
        return movies.size();
    }
}

12. Our Layouts

Our MainActivity Layout

<?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.recyclerfirebaseimagestext.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>

Our ContentMain Layout

<?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.recyclerfirebaseimagestext.MainActivity"
    tools:showIn="@layout/activity_main">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/mRecylcerID"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView>
</RelativeLayout>

Our Model Layout

<?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="10dp"
    card_view:cardElevation="10dp"

    android:layout_height="wrap_content">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/movieImage"
            android:padding="10dp"
            android:src="@drawable/placeholder" />

        <TextView
            android:layout_width="wrap_content"
            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:layout_below="@+id/movieImage"
            android:layout_alignParentLeft="true"
             />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="TV Show"
            android:id="@+id/posTxt"
            android:padding="10dp"

            android:layout_below="@+id/movieImage"
            android:layout_alignParentRight="true" />

        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/chk"
            android:layout_alignParentRight="true"
            />

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

Our CustomDialog layout

<?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/urlLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/urlEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"

                android:hint="Url" />
        </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>

13 Our Manifets

Make sure you add Internet permission in your manifest file:

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

    <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>

Android Firebase RecyclerView with Images and Text