Swift types

import UIKit
import Foundation

class LightSwitch {
	var on: Bool = true
}

var livingRoomSwitch = LightSwitch()
livingRoomSwitch.on
var dollarSign: Character = "$"
var myFirstSwiftString String = "no' money"

Optional and Tuples

let kitchenSwitch = LightSwitch()
let ticketPrice = 13.75
let swiftIsFast = true
let encouragement = “You can do it!”

let ticketPrice = 7.5
let allowance = 10.0
var iceCreamPrice = 3.0

var pic UIImage(named:"Choe.png")!

if allowance >= ticketPrice + iceCreamPrice {
	println("Let's go to the movies!")
} else {
	println("Let's watch a movie at home and eat ice cream")
}
var hungry = true
var vegetarian = false

if hungry {
	println("Let's eat!")
} else {
	println("Let's wait.")
}

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);
	}	
}

Reading from an input stream

the purpose of an InputStream
Represents a stream of bytes (small chunks of data)

the purpose of an BufferedReader
Helps us read text from an InputStream

String: Immutable(can’t change once created)
StringBuilder: Mutable(Can change once created)

StringBuilder builder = new StringBuilder();
builder.append("World");
builder.deleteCharAt(3);
builder.append(" builder").append(".");
String built = builder.toString();

what exception is caught
in the makeHttpRequest() method?
IOException
in the extractFeatureFromJson() method?
JSONException

Reading from an Input

private String readFromStream(InputStream inputStream) throws IOException {
	StringBuilder output = new StringBuilder();
	if (inputStream != null){
		InputStreamReader inputStreamReader =
			new InputStreamReader(inputStream, Charset.forName("UTF-8"));
		BufferedReader reader = new BufferedReader(inputStreamReader);
		String line = reader.readLine();
		while (line != null){
			output.append(line);
			line = reader.readLine();
		}
	}
	return output.toString();
}

HTTP Status Codes

Status code: Description
200: OK, request received, everything normal
301: moved permanently
404: Page not found
500: Internal server error

List of HTTP status codes
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
3xx Redirection
4xx Client Error
5xx Server Error

the request is successful
200
the request is unsuccessful
400

EX

Error 400: Bad Request

Bad endtime value "2014-01-02asdfasdf". Valid values are ISO-8601 timestamps.

Usage details are available from https://earthquake.usgs.gov/fdsnws/event/1

200 response code -> Proceed with reading input stream and parsing the JSON response
Any other response code -> Return empty string for the JSON response