Firebase

Be comfortable with
– making a simple mobile application
– basic command line
– calling a web or cloud API

FriendlyChat
APP, DB, FILE

package com.google.firebase.xxxx.friendlychat;
public class FriendlyMessage {
	private String text;
	private String name;
	private String photoUrl;

	public FriendlyMessage(){
	}

	public FriendlyMessage(String text, String name, String photoUrl){
		this.text = text;
		this.name = name;
		this.photoUrl = photoUrl;
	}

	public String getText(){
		return text;
	}

	public void setText(string text){
		this.text = text;
	}

	public String getName(){
		return name;
	}

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

	public void setPhotoUrl(String photoUrl){
		this.photoUrl = photoUrl;
	}
}
package com.google.firebase.xxxx.friendlychat;

import android.os.Bundle;
import android.support.v7.app.AppCompactActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.ProgressBar;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends(Bundle savedInstanceState){
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);

	mUsername = ANONYMOUS;

	mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
	mMessageListView = (ListView) findViewById(R.id.messageListView);
	mPhotoPickerButton = (ImageButton) findViewById(R.id.photoPickerButton);
	mMessageEditText = (EditText) findViewById(R.id.messageEditText);
	mSendButton = (Button) findViewById(R.id.sendButton);

	List<FriendlyMessage> friendlyMessages = new ArrayList<>();
	mMessageAdapter = new MessageAdapter(this, R.layout.item_message, friendlyMessages);
	mMessageListView.setAdapter(mMessageAdapter);

	mProgressBar.setVisibility(ProgressBar.INVISIBLE);

	mPhotoPickerButton.setOnClickListener(new View.OnClickListener(){
		@Override
		public void onClick(View view){

		}
	});

	mMessageEditText.addTextChangedListener(new TextWatcher(){
		@Override
		public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2){			
		}

		@Override
		public void onTestChanged(CharSequence charSequence, int i, int i1, int i2){
			if (charSequence.toString().trim().length() > 0){
				mSendButton.setEnable(true);
			} else {
				mSendButton.setEnabled(false);
			}
		}

		@Override
		public void afterTextChanged(Editable editable){
		}
	});
	mMessageEditText.setFilter(new InputFilter[]{new InputFilter.LengthFilter(DEFALT_MSG_LENGTH_LIMIT)});

	mSendButton.setOnClickListener(new View.OnClickListener(){
		@Override
		public void onClick(View view){
			mMessageEditText.setText("");
		}
	});

	@Override
	public boolean onCreateOptionsMenu(Menu menu){
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.main_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item){
		return super.onOptionsItemSelected(item);
	}
}

Create the Empty View

<red lines>
	<!-- Empty view for the list -->
	<RelativeLayout
		android:id="@+id/empty_view"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:layout_centerInParent="true">

		<ImageView
			android:id="@+id/empty_shelter_image"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:layout_centerHorizontal="true"
			android:src="@drawable/ic_empty_shelter" />

		<TextView
			android:id="@+id/empty_title_text"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:layout_below="@+id/empty_shelter_image"
			android:layout_centerHorizontal="true"
			android:fontFamily="sans-serif-medium"
			android:paddingTop="16dp"
			android:text="@string/empty_view_title_text"
			android:textAppearance="?android:textAppearanceMedium" />

		<TextView
			android:id="@+id/empty_subtitle_text"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:layout_below="@+id/empty_title_text"
			android:layout_centerHorizontal="true"
			android:fontFamily="sans-serif"
			android:paddingTop="8dp"
			android:text="@string/empty_view_subtitle_text"
			android:textAppearance="?android:textAppearanceSmall"
			android:textColor="#A2AAB0">
	</RelativeLayout>

Using a CursorLoader
Activity -> LoaderCallbacks -> onCreate() ->getLoaderManager().initLoader()->onCreateLoader() -> onLoadFinished() swapCursor(cursor -> onLoaderReset() swapCursor(null)

CursorAdapter

ArrayAdapter
Data source: ArrayList of words
Data source: Cursor of pets

public class PetCursorAdapter extends CursorAdapter {

	public PetCursorAdapter(Context context, Cursor c){
		super(context, c, 0);
	}

	public view newView(Context context, Cursor c, ViewGroup parent){
		// create and return new blank list item
	}

	public void bindView(View view, Context context, Cursor c){
		// Populate list item view with pet data
	}
}

ContentProvider Update()

public class PetProvider extends ContentProvider {

	...

	@Override
	public int update(Uri uri, ContentValues contentValues, String selection,
		String[] selectionArgs){
		final int match = sUriMatcher.match(uri);
		switch (match){
			case PETS:
				return updatePet(uri, contentValues, selection, selectionArgs);
			case PET_ID:
				selection = PetEntry._ID + "=?";
				selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri))};
				return updatePet(uri, contentValues, selection, selectionArgs);
			default:
				throw new IllegalArgumentException("Update is not supported for " + uri);
		}
	}
}

Implement ContentProvider

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
		String sortOrder){
	SQLiteDatabase database = mDbHelper.getReadableDatabase();

	Cursor cursor;

	int match = sUriMatcher.match(uri);
	switch(match){
		case PETS:
			// 
			break;
		case PET_ID:
			selection = PetEntry._ID + "=?";
			selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri))};
			cursor = database.query(PetEntry.TABLE_NAME, projection, selection, selectionArgs,
				null, null, sortOrder);
			break;
		default:
			throw new IllegalArgumentException("Cannot query unknown URI " + uri);
	}
	return cursor;
}
public class PetProvider extends ContentProvider {

	@Override
	public Uri insert(Uri uri, ContentValues contentValues){
		final int match = sUriMatcher.match(uri);
		switch (match){
			case PETS:
				return insertPet(uri, contentValues);
			default:
				throw new IllegalArgumentException("Insertion is not supported for " + uri);
		}
	}

	private Uri insertPet(Uri uri, ContentValues values){
		return ContentUris.withAppendedId(uri, id):
	}
}
private Uri insertPet(Uri uri, ContentValues values){
	String name = values.getAsString(PetEntry.COLUMN_PET_NAME);
	if (name == null){
		throw new IllegalArgumentException("Pet requires a name");
	}

	SQLiteDatabase database = mDbHelper.getWritableDatabse();

	long id = database.insert(PetEntry.TABLE_NAME, null, values);
	if (id == -1){
		Log.e(LOG_TAG, "Failed to insert row for " + uri);
		return null;
	}

	return ContentUris.withAppendedId(uri, id);
}

Content Provider

UI Code is directory interacting with database

CatalogActivity ->
EditorActivity -> Content Provider -> PetDbHelper (Pet with ID 1 has weight 7)

Manage access to a structured set of data
-good abstraction layer between data source & UI code (can add data validation, can modify how data is stored UI code is unaffeted)
-work well with other Android framework classes

UI code
Catalog Activity, Content Resolver, Pet Provider, PetDbHelper SQLiteDatabase

Contacts provider
content://com.android.contacts/contacts
Calendar provider
content://com.android.calendar/events
User Dictionary provider
content://user_dictionary/words

Scheme, Content Authority, Type of data

content authority

<provider
	android:name=".data.PetProvider"
	android:authorities="com.example.android.pets"
	android:exported="false" />
int match = sUriMatcher.match(uri);
if (match == CONTACTS){
	// Act on the contacts table
} else if (match == CONTACTS_ID){
	// Act on a single contact in contacts table
}
public class PetProvider extends ContentProvider {

	private static final int PETS = 100;
	private static final int PET_ID = 101;

	private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
	static {
		sUriMatcher.addURI(PetContract.CONTENT_AUTHORITY, PetContract.PATH_PETS,PETS);
		sUriMatcher.addURI(PetContract.CONTENT_AUTHORITY,PetContract.PATH_PETS + ""/, PETS_ID);
	}
	...
}

Read values from Cursor

Read

Cursor c = db.query(PetEntry.TABLE_NAME,projection,
		selection, selectionArgs,
		null, null, null);
while (cursor.moveToNext()){
	int currentID = cursor.getInt(idColumnIndex);
	String currentName = cursor.getString(nameColumnIndex);
	displayView.append(("\n" + currentId + " - " +
		currentName));
}

Insert Dummy pet from menu item

1. Get pet attributes from user input fields
2. Insert new pet with those attributes into the database

SELECT name, breed FROM pets;
SELECT * FROM pets;
SELECT * FROM pets WHERE _id = 1;

String selection = PetEntry._ID = "=?";
String[] selectionArgs = {"1"};

In Java;

String[] projection = { PetEntry.COLUMN_PET_BREED,
	PetEntry.COLUMN_PET_WEIGHT };
String selection = PetEntry.COLUMN_PET_GENDER + "=?";
String selectionArgs = new String[] { PetEntry.GENDER_FEMALE };

Cursor c = db.query(PetEntry.TABLE_NAME, projection,
	selection, selectionArgs,
	null, null, null);

SELECT breed, weight FROM pets WHERE gender = 1

Handling a cursor object
-moveToFirst: moves the cursor to the first row that’s in the result set
-moveToLast: moves the cursor to the last row that’s in the result set
-moveToPosition(int position): moves the cursor to a specific position; for example, saying “moveToPosition(3)” would move it to the fourth row.

abstract float, abstract int, abstract long, abstract short, abstract String, abstract int

cusor.moveToPosition(3);
int nameColumnIndex =
	cusor.getColumnIndex(PetEntry.COLUMN_PET_NAME);
String name = cursor.getString(nameColumnIndex);
cusor.moveToFirst();
cusor.moveToNext();
cusor.moveToNext();

int nameColumnIndex = cusor.getColumnIndex(PetEntry.COLUMN_PET_NAME);
int weightColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_WEIGHT);

int result = cursor.getInt(weightColumnIndex);

Getting a database connection

UI -> I want a readable database
EditorActivity, CatalogActivity

SQLiteDatabase db = mDbHelper.getReadableDatabase();

PetContract

PetDbHelper

PetDbHelper mDbHelper = new PetDbHelper(this);

Is there a database? no -> Make a database using onCreate() code

SQLiteDatabase

Create Update Delete
->SQLiteDatabase db = mDbHelper.getWritableDatabase();

Select
->SQLiteDatabase db = mDbHelper.getWritableDatabase();

INSERT INTO <table name>(
	<column_name_1>,
	<column_name_2>,
	...)
VALUES (
	<values_1>,
	<values_2>
	...)

INSERT INTO pets (
	_id,
	name,
	breed,
	weight)
VALUES (
	1,
	"Tommy",
	1,
	4);

Inserting Data: Content Values
Key – Value, COLUMN_PET_NAME – “Garfield”, COLUMN_PET_BREED – “Tabby”, COLUMN PET GENDER – GENDER_MALE, COLUMN_PET_WEIGHT – 14

ContentValues values = new ContentValues();
values.put(PetEntry.COLUMN_PET_NAME, "Garfield");
values.put(PetEntry.COLUMN_PET_BREED, "Tabby");
values.put(PetEntry.COLUMN_PET_GENDER, PetEntry.GENDER_MALE);
values.put(PetEntry.COLUMN_PET_WEIGHT, 14);

SQLiteOpenHelper

-Create a class that extends from SQLiteOpenHelper
-Create constants for database name and database version
-Create a constructor
-Implement the onCreate() method – this method is for when the database is first created
-Implement onUpgrade() – this method is for when the database schema of the database changes
(ex:adding a different column)

public class FeedReaderDbHelper extends SQLiteOpenHelper {

	public static final int DATABASE_VERSION = 1;
	public static final String DATABASE_NAME = "FeedReader.db";

	public FeedReaderDbHelper(Context context){
		super(context, DATABASE_NAME, null, DATABASE_VERSION);
	}
	public void onCreate(SQLiteDatabase db){
		db.execSQL(SQL_CREATE_ENTRIES);
	}
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
		db.execSQL(SQL_DELETE_ENTRIES);
		onCreate db;
	}
	public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion){
		onUpgrade db oldVersion, newVersion;
	}
}