SQL COMMANDS FOR APP

SELECT FROM ;
->
SELECT * FROM pets;
* indicates “all rows and all columns”
“pets” specifies we want data from the pets table

INSERT INTO pets (_id, name, bread, gender, weight)
	VALUES(1, "TOMMY", "Pomeranian", 1, 4);
sqlite> .tables
pets   pets2
sqlite> SELECT * FROM pets;
sqlite> INSERT INTO pets (_id, name, breed, gender, weight)
   ...>         VALUES(1, "TOMMY", "Pomeranian", 1, 4);
Error: table pets has no column named breed
sqlite> INSERT INTO pets (_id, name, bread, gender, weight)
   ...>         VALUES(1, "TOMMY", "Pomeranian", 1, 4);
sqlite> INSERT INTO pets (_id, name, bread, gender, weight)
   ...>         VALUES(2, "Garfield", "Tabby", 1, 8);
sqlite> SELECT * FROM pets;
1|TOMMY|Pomeranian|1|4
2|Garfield|Tabby|1|8

CRUD

Create, Read, Update, Delete

In order to open and see the list of all the pets in the shelter taking read actions on the table.
Tapping on the entry in the CatalogActivity in order to see information about specific pet require Read.
From the EditorActivity, changing the weight of a specific pet requires taking Update actions on the table.
Using the option from the overflow menu that removes incorrectly entered pets requires Delete.
Selecting the “Insert Pet” option from the overflow menu to insert a list of default information requires taking Create actions on the table.

Types in SQLite

storage class, data types
NULL, INTEGER, REAL, TEXT, BLOB

No booleans, use INTEGER instead
Ex:
false = 0
true = 1

attribute
Name TEXT
Price INTEGER
Style INTEGER
In Stock INTEGER
Description TEXT

CREATE TABLE headphones (_id INTEGER, name TEXT,
	price INTEGER,
	style INTEGER,
	in_stock INTEGER,
	description TEXT);

CREATE TABLE pets (_id INTEGER, 
	name TEXT,
	bread TEXT,
	gender INTEGER,
	weight INTEGER);

Computer Memory

Temporary Storage:Short term
-can be used for calculations or displaying data on screen
-quick to access
-short-lived
e.g.
-computer RAM

Permanent Storage:Long term
-can be used for storing user data
-slower to save and access data
-stick around forever(until deleted)
e.g.
-Hard disk, Flash drives

Different Data Storage Options
Files: good for saving large media files
SharedPreferences: Good for in-app user preferences, key and value, Unique String and primitive types and strings
SQLight Databases: Good for organizing a lot of related and structured data for easy access: Row, Column
commonly used for text data, easily grows in size and easily searchable

PS C:\Users\xxx> sqlite3 -version
3.15.0 2016-10-14 10:20:30 707875582fcba352b4906a595ad89198d84711d8

PS C:\Users\xxx> sqlite3
SQLite version 3.15.0 2016-10-14 10:20:30
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open pets.db
sqlite>

Verify Loader Behavior

add log message to
initLoader(), onCreateLoader() callback, Loader startLoading()method
onLoadFinished() callback, Loader loadInBackground() method
onLoaderReset() callback, queryUtils fetchEarthquakeData() method

<RelativeLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
	android:layout_height="match_parent">

	<ListView
		android:id="@+id/list"
		android:orientation="vertical"
		android:layout_width="match_parent"
		android:layout_height="match_parent"
		android:divider="@null"
		android:dividerHeight="0dp"/>

	<TextView
		android:id="@+id/empty_view"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:layout_centerInParent="true"
		android:textAppearance="?android:textAppearanceMedium"/>

</RelativeLayout>
private TextView mEmptyStateTextView;

@Override
protected void onCreate(Bundle savedInstanceState){
	mEmptyStateTextView = (TextView) findViewById(R.id.empty_view);
	earthquakeListView.setEmptyView(mEmptyStateTextView);
}

@Override
public void onLoadFinished(Loader<List<Earthquake>> loader, List<Earthquake> earthquakes){
	mEmptyStateTextView.setText(R.string.no_earthquakes);
}

Async Task In Quake Report App

private class EarthquakeAsyncTask extends
AsyncTask<String, Void, List<Earthquake>>{
	...
}

https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=earthquake&orderby=time&minmag=6&limit=10

Loader
https://developer.android.com/guide/components/loaders.html?utm_source=udacity&utm_medium=course&utm_campaign=android_basics

Loader manager
https://developer.android.com/reference/android/app/LoaderManager.html?utm_source=udacity&utm_medium=course&utm_campaign=android_basics

Loader callback
https://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html?utm_source=udacity&utm_medium=course&utm_campaign=android_basics

package com.example.android.quakereport;

import android.content.AsyncTaskLoader;
import android.content.Context;

import java.util.List;

public class EarthquakeLoader extends AsyncTaskLoader<List<Earthquake>>{
	private static final String LOG_TAG = EarthquakeLoader.class.getName();

	private String mUrl;

	public EarthquakeLoader(Context context, String url){
		super(context);
		mUrl = url;
	}

	@Override
	protected void onStartLoading(){
		forceLoad();
	}

	@Override
	public List<Earthquake> loadInBackground(){
		if (mUrl == null){
			return null;
		}

		List<Earthquake> earthquakes = QueryUtils.fetchEarthquakeData(mUrl);
		return earthquakes;
	}
}

Handle Empty or Null Cases

protected Event doInBackground(String... urls){
	if (urls.length < 1 || urls[0] == null){
		return null;
	}

	Event result = Utils.fetchEarthquakeData(urls[0]);
	return result;
}
protected void onPostExecute(Event result){
	if (result == null){
		return;
	}
	updateUi(result);
}
private class EarthquakeAsyncTask extends AsyncTask {

	protected Event doInBackground(String... urls){
		if (urls.length < 1 || urls[0] == null){
			return null;
		}

		Event result = Utils.fetchEarthquakeData(urls[0]);
		return result;
	}

	protected void onPostExecute(Event result){
		if (result == null){
			return;
		}

		updateUi(result);
	}

}

Asynctask callback methods

onPreExecute(): before the task is executed, Main
doInBackground(Params…): After onPreExecute, Background
onProgressUpdate(Progress…): After publishProgress() is called, while doInBackground is executing, Main
OnPostExecute(Result): After doInBackground() finishes, Main

Review of generics
ArrayList
add(E e)->requires object of type E as input
get(int index)->returns object of type E
ArrayAdapter

private class DownloadFileTask extends AsyncTask{
	protected Long doInBackground(RUL... urls){
		int count = urls.length;
		long totalSize = 0;
		for(int i = 0; i < count; i++){
			totalSize += Downloader.downloadFile(url[i]);
			publishProgress((int)((i/(float) count)* 100));
			if(isCancelled()) break;
		}
		return totalSize;
	}
	protected void onProgressUpdate(Integer... progress){
		setProgressPercent(progress[0]);
	}
	protected void onPostExecute(long result){
		showDialog("Downloaded " + result + " bytes");
	}
}
private class DownloadWebpageTask extends AsyncTask<String, Void, String>{
	@Override
	protected String doInBackground(String... urls){
		try {
			return downloadUrl(urls[0]);
		} catch (IOException e){
			return "Unable to retrieve web page. URL may be invalid.";
		}
	}

	@Override
	protected void onPostExecute(String result){
		textView.setText(result);
	}
}

Main Thread vs Background Thread

Background Thread(In) -> Perform Network Request -> Out
Main Thread(In) -> Click Button -> Out

Asynctask to the rescue
Async -> 非同期
https://developer.android.com/reference/android/os/AsyncTask.html

 private class DownloadFilesTask extends AsyncTask {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

concrete class
abstract class
interface

public class Main Activity extends Activity {
	onCreate(){

	}
	onCreate(){

	}
}

public class EarthquakeAsyncTask extends AsyncTask {
	doInBackground(){
		
	}
}

Threads & Parallelism

Event.java

package com.example.android.didyoufeelit;

public class Event {
	public final String title;

	public final String numOfPeople;

	public final String perceivedStrength;

	public Event(String eventTitle, String eventNumOfPeople, String eventPerceivedStrength){
		title = eventTitle;
		numOfPeople = eventNumOfPeople;
		perceivedStrength = eventPerceivedStrength;
	}
}
package com.example.android.didyoufeelit;

import android.os.Bundle;
import android.support.v7.app.AppCompactActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
	private static final String USGS_REQUEST_URL =
		"http://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2016-01-01&endtime=2016-05-02&minfelt=50&minmagnitude=5";

	@Override
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Event earthquake = Utils.fetchEarthquakeData(USGS_REQUEST_URL);

		updateUi(eqrthquake);
	}

	private void updateUi(Event earthquake){
		TextView titleTextView = (TextView) findViewById(R.id.title);
		titleTextView.setText(earthquake.title);

		TextView tsunamiTextView = (TextView) findViewById(R.id.number_of_people);
		tsunamitextView.setText(getString(R.string.num_people_felt_it, earthquake.numOfPeople));

		TextView magnitudeTextView = (TextView) findViewById(R.id.perceive_magnitude);
		magnitudeTextView.setText(earthquake.perceivedStrength);
	}	
}