Udacity – Developing Android Apps

An Udacity course Developing Android Apps using Android Studio

Lesson: How to Use a Content Provider

Udacity – Developing Android Apps

Lesson How to Use a Content Provider notes:

  • ContentProvider presents data to external applications as one or more tables that are similar to the tables found in a relational database.
  • Reasons to use ContentProvider
    • Easily change underlying data source
    • Leverage functionality of Android Classes.
    • Allow many apps to access, use and modify a single data source securely.
  • ContentProvider permission are in the AndroidManifest.xml
    • e.g. android.permission.READ_USER_DICTIONARY for read only permission for user dictionary.
  • An application accesses the data from a content provider with a ContentResolver client object. The ContentResolver methods provides query, insert, update, delete functions of persistent storage. ContentResolver calls these corresponding methods on the ContentProvider.
  • Content URI is Uniform Resource Identifier that identifies data in a provider. Content URI include the symbolic name of the entire provider (authority) and a name that points to a table (path).
    • e.g. User.Dictionary.Words.CONTENT = content://user_dictionary/words
    • content:// is standard way Content URI starts (scheme)
    • user_dictionary/ is Content Authority
    • words mean to get list of words
  • Cursor is an Iterator that give access to the underlying data in tabular form.
    • getCount() return the number of rows in the cursor
    • moveToNext() move the cursor to the next row
    • get___(col index). e.g. getString, getInt…etc.
    • getColumnIndex(name of column)
    • call close() to avoid memory leak
  • The Big Picture
    • Your App request a ContentResolver and pass a URI into the resolver
    • The resolver passes the information in the URI to the content providers. The resolver also calls the same method to the provider base on  the method the app called on the resolver.
    • Once Content provider gets the information from the database, it passes a cursor back to the resolver and subsequently pass the cursor back to the app.
  • Cursor Adapter is like an array adapter but take a cursor to populate listview. (see SimpleCursorAdapter)
    • android.R.layout.two_line_list_item is a standard layout
    • use v4 SimpleCursorAdapter for compatibility

References:

Lesson 4a: Lifecycle and Databases

Udacity – Developing Android Apps

Lesson 4a notes:

  • Why We Need an Activity Lifecycle
  • The Android Activity Lifecycle
    • A diagram of the Android Activity Life Cycle
  • Active and Visible Lifetimes
    • Lifecycle Events (Hint)
      • onPause
      • onStop
      • onDestroy
      • onCreate
      • onStart
      • onResume
    • To rotate
      • Linux: CTRL + F12
      • Mac: FN + LEFT CTRL +F12
      • Windows: LEFT CTRL + F11 or LEFT CTRL + F12
  • Activity Termination
    • onPause is called before onStop and should prepare the termination at that call.
  • How to Prepare for TerminationWhat To Do in OnPause/OnStop
    • Some examples of listeners or updates you should disconnect or stop when onPause or onStop are received.
      • Sensor Listeners
      • Location Updates
      • Dynamic Broadcast Receivers
      • Game Physics Engines
  • Maintaining State
    • Active > onSaveInstanceState > onPause > Terminated > onCreate > onRestoreInstantState
  • Bundles to Save App State
  • Storing Data in Android

SQLite Tutorial

  • SQLite Tutorial
    • Get SQLite
    • Create new db
    • list of comands
    • list databases
    • list table
    • find the schema of how the table is created
    • quit
sqlite3 database.db
.help
.databases
.tables
.schema
.quit
  • Create A Database Table
    • CREATE TABLE statement create a new database table
      • column definition is separated by commas (define column name and datatype)
    • SELECT statement return all rows base on the specific criteria. Use * for all rows.
CREATE TABLE weather( _id INTEGER PRIMARY KEY, date TEXT NOT NULL, 
min REAL NOT NULL, max REAL NOT NULL, humidity REAL NOT NULL, pressure REAL NOT NULL);
SELECT * from weather;
  • Insert rows
    • INSERT statement insert new row to the table. e.g.
  • Query rows
    • WHERE clause narrow down the number rows in the result.
    • Other operators
INSERT INTO weather VALUES(1, '20140625', 16,20,0,1029);
SELECT _id,date,min,max FROM weather WHERE date > 20140625 AND date < 20140628;
  • Update rows
    • UPDATE statement update existing rows information
  • Delete rowsDELETE statement delete the row from the table
UPDATE weather SET min = 0, max = 100 where date >= 20140626 AND date <= 20140627;
DELETE FROM weather WHERE humidity != 0;
  • Add columns
    • ALTER TABLE command to alter existing table.
  • Delete table
    • DROP TABLE command delete the table from the database
  • Example: return the max temperature row
ALTER TABLE weather ADD COLUMN description TEXT NOT NULL DEFAULT 'Sunny';
DROP TABLE weather;
SELECT * FROM weather ORDER

Lesson 4a notes cont…:

  • WeatherContract
    • To define an agreement between our data and our view describing how data will be stored.
    • Add package data to encapsulate our data model.
    • Add contract class to store the column information
    • Add entry to define the table and the data.
  • SQLiteOpenHelper help us handle database table
    • Add required method (CTRL-i)
    • Override constructor (CTRL-o)
      • Replace the String name to DATABASE_NAME, factor to null and version to DATABASE_VERSION
    • In onCreate method, create a string to create the weather table.
    • In onUpgrade method, delete the table and re-create the table
  • JUnit Testing
    • create com.example.android.sunshine.app.test package under src/androidTest/java
    • create a new class call FullTestSuite
    • create a new class call TestDb
    • Under app dropdown, add Android Tests and choose app in Module.
    • testInsertReadDb
      • Insert dummy data
      • Use dbHelper to get a writeable database
      • Create ContentValues object that store values and keys
      • Store dummy data in the columns from our LocationEntry contract
      • Insert the data into the db and verify we can get the row back
    • Cursor is the primary interface to the query results. It allow traversal of record in the database.

Lesson 3: New Activities and Intents

Udacity – Developing Android Apps

Lesson 3 notes:

  • ItemClickListener and Toast
    • Toast is a pop-up that displays a message a few second before fading out. It uses for debugging because it indicate status visually without altering the app UI.
    • Put listView.setItemClickListener into forecastFragment onCreateView method
    • Add a Toast when the list item is clicked that contains the weather information. Get the forecast by getting an item from the forecast adapter at the position given by the on item click listener.
    • getActivity() vs parent.getContext(). Since Activity extends Context, sometimes when an activity is required, a context must be cast to an activity. getActivity() is available in fragment.
  • Create New Activity
    • Up vs Back. Up button always bring you one level up the hierarchy of the same app but Back button bring you to the last screen that might go across different apps.
    • Create the DetailActivity and look at how the activity is declared in the AndroidManifest file.
    • Intellij: right click on package > New > Activity > Blank Activity with Fragment. Input Activity name and Hierarchical Parent (MainActivity).
  • Intents Framework
    • Use Intent to start activity from MainActivity to DetailActivity
  • Intent as Envelopes
    • Explicit Intent put a message and send to a specified target activity
    • Implicit Intent put a message of what to do and send it out to whoever can do it. This might be another application. Some common intent example are dialing a number, view a website… etc.
  • Launch DetailActivity
    • Replace Toast with an explicit intent to launch the DetailActivity.
    • Pass in weather forecast data for the detail activity to display
    • Create a new instance of Intent with putExtra to include the weather forecast data as EXTRA_TEXT. Use startActivity(intent) to start the activity.
  • Display Content in DetailActivity
    • Read the forecast data from the Intent and display it in DetailActivity
    • Add a text id detail_text at fragment_detail.xml
    • Pull forecastStr from Intent, find the root view and set the text to the forecastStr.
    • List Item Click Listener
      • What method is used to wire up behavior on a list item when it is clicked?
      • setOnItemClickListener (AdapterView.OnItemClickListener listener)
      • ListView Documentation: Register a callback to be invoked when an item in this AdapterView has been clicked.
  • Setting User Experience
    • Setting Developer Guide Document
    • Use PreferenceActivity Class for Gingerbread, PreferenceFragment Class for Honeycone or later.
    • Add SettingsActivity extends from PreferenceActivity and update AndroidManifest to declare SettingsActivity. Make sure the string name has been define in res/strings.xml.
  • Launch SettingsActivity
    • In both MainActivity and DetailActivity, create startActivity with new intent for settingsActivity in onOptionsItemSelected method.
    • create xml res folder and a preference xml file with PreferenceScreen. In EditTextPreference, add title, key and default value as a previously defined string constant.
  • Modify SettingsActivity
    • In onCreate method, addPreferencesFromResource and bindPreferenceSummaryToValue
  • Use SharedPreferences
    • create a SharedPreferences and using PreferenceManager to getDefaultSharedPreferences.
    • create a location string pair of the location key and the default.
    • Use this string for weatherTask when execute
  • Update Date on Activity Start
  • Temperature Units Setting
    • add ListPreference in pref_general.xml file (instead of EditTextPreference). The list of possible value is pass in as an array (entriesValues, entries).
    • refactor to create updateWeather() method that use SharedPreferences for location string
    • override onStart() method to call updateWeather()
    • pass a empty array list in mForecastAdapter instead of fake forecast data
  • Debug Breakpoints
  • Add Map Location Intent
    • add another menu item in main.xml and define the string for the id
    • read preferred location from sharedPreferences
    • create a view intent indicating its location in the data URI. URI format documentation.
    • startActivity with intent.
  • Share Intent
    • First, add the string for action_share
    • Add a new menu resource file with a new item for action_share.
    • Create a private String to store the forecast string in DetailFragment
    • Add a new Intent in DetailFragment. Use FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET to return to the original app and not the app that handle the share intent.
    • Set a flag that this fragment has an option menu under DetailFragment
    • Add onCreateOptionsMenu method by inflat the detailfragment menu, find the share item, getting the ShareActionProvider and attach an intent to the ShareActionProvider.
  • Broadcast Intents
    • Dynamic Receiver only when App running
    • Manifest Receiver will start app specific to receive broadcast.

Lesson 2: Connect Sunshine to the Cloud

Udacity – Developing Android Apps

Lesson 2 notes:

  • Open Weather Map
  • The URL query for 1 week forecast data at postal code 94043 using metric unit with JSON format.
    • api.openweathermap.org/data/2.5/forecast/daily?q=94043&units=metric&cnt=7&mode=json
    • default mode is json
  • HTTP request for weather
    • Make HTTP request
    • Read response from input stream
    • Clean up and log any errors
    • An example of the code to do this is here.
    • Tutorial for connecting to the network notes:
      • Choose an HTTP client
        • HttpURLConnection (Recommended)
        • HttpClient (Apache)
      • Check the Network Connection
        • getActiveNetworkInfo() or isConnected()
  • Logging
    • Log.e logs error messages
    • Avoid log spam
    • adb logcat at command line to view the debug and error messages. Additional option can be found here.
    • on Android Studio, you can launch Android Device Manager and select the device and click on logcat to view the same log messages.
    • Log level, Log._(String tag, String msg) with tag usually a constant defined for the name of the class or app
      • ERROR e – keep
      • WARN w- keep
      • INFO i- keep
      • DEBUG d- are compiled in but they are stripped out at run time.
      • VERBOSE v- should never compile into the app except for development
  • To enable auto import
    • Android Studio > Preferences > Editor > Auto Import. Check all the boxes and insert all imports on paste.
  • Threads
    • main thread aka UI thread that take care of all user input and output
    • background thread are use for long operation such as network call, decoding bitmap, or reading and writing from database.
    • Use AysncTask to fire off a new task from the UI thread. Here are 4 steps when the task is executed
      • onPreExecute() invoked on the UI thread for setup the task
      • doInBackground(Params…) invoked on the background thread for background computation and must be implemented.
      • onProgressUpdate(Progress…) invoked on the UI thread after a call to publishProgess(Progress…) to display any form of progress in the UI.
      • onPostExecute(Result) invoked by UI thread after background computation is finished.
  • Move to AsyncTask
    • Rename and Move ForecastFragment to a new file
      • To refactor the class name – right click on the class name > Refactor > Rename > type in new name
      • To move the class into its own file – select the class > Refactor > Move > select move up one level
    • Create AsyncTask called FetchWeatherTask
      • create public class FetchWeatherTask extends AsyncTask<Void, Void, Void> (Void mark the type not being used)
      • create method protected Void doInBackground(Void… params) and return null (null means return no parameter to UI threads after computation)
  • Why AsyncTask is not optimal
    • The transfer is on a thread whose lifetime is tied to a UI component so if the component is terminated, so does the transfer.
    • A better approach is to use a service with Inexact Alarm and SyncAdaptor
  • Menu options
    • in resource (res) folder > menu > main.xml file, there are single menu option for setting.
    • To add a menu option
      • add an item
      • define the id
      • add a title by referencing to a string you created
        • go to resource (res) > value > strings.xml and add a string
      • add app:showAsAction=”never” to show it in the overflow menu
    • in ForecastFragment.java ,model what the MainActivity.java
      • add onCreate method with setHasOptionsMenu(true)
      • add onCreateOptionsMenu() method
      • add onOptionsItemSelected() method using the id for action_refresh and add a new FetchweatherTask and execute it. However, at this point, the app crash due to SecurityException.
  • Permissions
    • each app is sandbox so no app can access information outside of its own VM.
    • permission to cross boundary is listed in the manifest.
    • a system app can be an intermediator for camera, phone call and accessing user-selected contact. However, getting user current location can only be done after declaring a user-permission in the manifest.
    • add internet Manifest.permission in the AndroidManifest.xml (e.g. android.permission.INTERNET.
  • Post Code Param
    • Modity FetchWeatherTask to take an argument of String
    • doInBackground method also receive a String as argument
    • Use Uri builder to build up the address
  • JSON
    • Using a JSON formatter to show that we need dt, main, max and min data for the apps.
    • Parsing the JSONObject to get the max temperature out
      • create String for list, temp, and max node.
      • create an JSONObject to store the Json string we got from the fetch.
      • create an JSONArray to get the list into an array of forecast by days.
      • create another JSONObject to grab only the forecast for the indexed day (0 base) from the JSONArray.
      • create another JSONObject to grab the temp node.
      • finally, grab the max node and return it as double.
    • Ensure doInBackground() returns String[]. This required to change AysncTask  and the return value of doInBackground.
  • Update the Adapter
    • override the AsyncTask onPostExecute method to add each day of forecast to the adapter.
    • adapter.notifyDatasetChanged() will notifies any attached observers that underlying data has changed.

Lesson 1: Create Project Sunshine

Udacity – Developing Android Apps

Lesson 1 notes:

  • Target SDK vs minimum SDK. The Target SDK. An example is that if there is a new feature recently introduced but not critical to the application, the target SDK should set to the version which the new feature was released in but have the minimum SDK to a lower version that your application is still functional without the new feature.
  • Layout Design
    • Frame Layout – useful for simple layouts with a single view or stack or views. Views are all aligned against the frame boundaries only.
    • Linear Layout – perfect for stacking views vertically or horizontally, one after another. Proportionally break up the screen.
    • Relative Layout – allow the positioning of view relative to other views or the boundaries of the view.
  • Add ListItem XML
    • create new layout resource file
    • in text view, define width, height, minHeight, gravity and id.
  • Add ListView to layout
    • at fragment_main, create ListView and define width, height, id
    • for “match_parent”, check the parent tag and the tag in activity_main to verify dimension (width & height).
  • Create Fake Data
    • create an array of string and then create an ArrayList of string to contain those string data.
  • Initialize ArrayAdapter Parameters
    • Context – contain global information of the app environment, allow access to system services and resources, and application specific resources. getActivity().
    • ID of list item layout – using this as a reference to the XML layout to get the layout for each list item. R.java class create human readable identifiers for resources. (R.layout refer to a specific layout file)
    • ID of text view – using this as a reference the text view that know how to display a string for a text view (R.id is refer to a specific XML element with the matching id attribute.)
    • list of data – the data to be display in the text view of the specific layout.
  • Binding ListView
    • system takes an inflated XML layout and turn it into full view hierarchy. root layout is the main_Activity.
    • to get a reference to an object, use findViewById to traverse through the hierarchy until it find the object
    • using subtree root reference as a starting location for searching child’s object.