IngmarBoddington
9/27/2017 - 9:18 AM

Android

Notes from Android / Java Study for Learning Tree exam

IDE
======
Recommended -> Android Studio
Common (Legacy) -> Eclipse with Android Development Tools (ADT)
Requires Android SDK + Java JDK
Applications are ran in an emulator -> Android Virtual Device (AVD) by the AVD Manager
  Allows multiple configurations to be created
  Different API versions and screen sizes
  Detailed configuration, such as memory size and GPS emulation, available
Android applications can be developed on almost any platform

Android
=====
Based on Linux Kernal, open source
Android Runtime
  Set of core libraries supporting most of the Java language
  The Android Runtime Virtual Machine (ART VM)
    Java virtual machine highly optimized for minimal memory
    Runs class files converted to Dalvik Executable (.dex) format
    Compiled to native code Ahead Of Time (AOT)
    Prior to Android 5, the VM was called Dalvik
Libraries
  C/C++ libraries providing low-level support to applications
    System library—core operating system support
    Media libraries, WebKit, SQLite, etc.
  Exposed to developers through the application framework    
Version history -> https://en.wikipedia.org/wiki/Android_version_history
Launches a seperate Linux process for each application, seperate Java VM

Google recommend that all projects include
  Support-v4
  Appcompat-v7
  
To test version (for newer feature checks) - v4 and above:
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB){
    return true;
  }
  return false;

Application Stores
=====
Google Play -> No approval process, 30% cut
Others -> “Unknown sources” must be enabled on the device to use them

Screen Sizes
=====
Android uses a resource system to support multiple resolutions
Four screen sizes defined -> small, normal, large, and xlarge
Six screen densities defined -> ldpi 120dpi, mdpi 160dpi, hdpi 240dpi, xhdpi 320dpi, xxhdpi 480dpi, xxxhdpi 640dpi

Build
=====
Gradle (written in a Groovy-based Domain-Specific Language (DSL)) used as build tool generally
Supports incremental builds by intelligently determining which parts of the
build tree are up-to-date
build.gradle files define build including dependencies

Packaging / Manifest
=====
All components are packaged in an .apk file
Manifest details contents of package - AndroidManifest.xml
  Components cannot be used unless in the manifest
  
Example Manifest:
  <manifest>
    <uses-permission />
    <permission /> …
    <uses-sdk />
    <uses-configuration />
    <uses-feature />
    <supports-screens />…
    <application>
      <activity>...</activity>
      <activity-alias>...</activity-alias>
      <service>...</service>
      <receiver>...</receiver>
      <provider>... </provider>
      <uses-library />
    </application>
  </manifest>

  uses-permission   A permission needed for the application to run: access to the camera, Internet, external storage, etc.
  permission        Allows restriction of access from other applications
  uses-sdk          Information about SDK versions; attributes specify minimum version needed to run, target SDK version, the maximum SDK version on which the application can run*
  usesconfiguration Specific hardware configuration required; e.g., a physical keyboard*
  uses-feature      Hardware features required: Bluetooth, camera, GPS, etc.*
  supports-screens  Screen sizes supported—default since API level 4 is that all screen sizes are supported; use this, for instance, to state that small screens are not supported*

Google play uses the last four of the items above to determine whether to show an application to a user in the store

Manifest must specify permissions it uses
  Which features of Android system it needs at runtime
  android.Manifest.permission defines the base set of permission
  Failure to specify a permission results in an AccessControlException
  Unchecked: Can result in “silent failures”
  Google Play warns user about the uses-permissions of the application they are installing

Example:
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.CAMERA" />
  <uses-permission android:name="android.permission.INTERNET" />

activity, activity-alias, service, and receiver May have an intent-filter nested within them to allow receipt of Intents from other applications

Android 6.0 added fine-grained runtime permission control
  User may grant/revoke permissions while an app is running!
  If targetSdkVersions is 23 or higher
    App must check permission prior to accessing the protected resource
    If a permission is dangerous, then Android must check it
    If permission is not granted, then Android will prompt
  uses-permissionsmust still be declared in the manifest

Example:
  private void doSomethingIfWeHavePermission(String permissionToCheck){
    if (ActivityCompat.checkSelfPermission(this, permissionToCheck) == PackageManager.PERMISSION_GRANTED) {
      // Do the work that requires a permission here
    } else {
      String[] perms = {permissionToCheck};
      ActivityCompat.requestPermissions(this, perms, REQUEST_PERMISSIONS);
    }
  }

Android would then call back:
  @Override
  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == REQUEST_PERMISSIONS) {
      if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        // Do the work originally requested
      } else {
        Toast.makeText(this, "Permission not granted“, Toast.LENGTH_LONG).show();
      }
    }
  }
  
For release, the package must be
  Zipaligned – Optimizes the structure of the package for memory efficiency
  Signed – Digitally signed to provide an anti-tamper mechanism
  
Google has introduced a license verification scheme
– http://developer.android.com/guide/publishing/licensing.html

Performance
=====
Do not run long processes in th primary (user interface) thread
  May cause Application Not Responding (ANR) errors
  Use services, AsyncTasks or intents

Activities
=====
The user interacts with an Android application through activities
Each activity is a single screen
Displays or captures data through a view (which may be split into fragments)
Activities are managed by the Android application framework
Main activity launched in response to user request
Responsible for
  Capturing user input
  Supporting the activity life cycle
  Interacting with underlying data and business logic

Extends android.app.Activity, although generally we extend AppCompatActivity for compatibility

  onCreate override for launch of activity from intent - called by framework when application is ready
    Call the overridden method
    Set the view for the activity
    
    Example:
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
    }
    
Can get the activity which launched the activity:
  Intent getIntent()
  
Or retrieve the URI for a content provider / any other set data
  Uri getData()
  double getDoubleExtra(String name)
  int getIntExtra(String name)
  int[] getIntArrayExtra(String name)
  
Serializable and Parcelable extras must be cast to correct type
  Type type = (Type) getIntent().getParcelableExtra("Name");

Subactivities
=====
Can be launched using:
  startActivityForResult (Intent launchIntent, int requestCode)
  
And the callback implementation:
  protected void onActivityResult(int requestCode, int resultCode, Intent resultIntent)
  
The requestCode can be used to correlate the subactivity result
Activity class provides constants to check the resultCode

The subactivity must use setResult with option resultIntent and the finish
  setResult(Activity.RESULT_OK, resultIntent);
  finish()

Views
=====
Defined in XML
Defined in res folder of project
ID maps to location R.<folder>.<folder> where R = res
Visual portion of an activity, what the user sees

Set using setContentView:
  setContentView(int resourceId) - Using declared resource item
  setContentView(View view) - Using view object
  
Views can be organised in collections using ViewGroups (which are Views)

View contains widgets, such as:
  TextView - Used to display text; optionally allows text to be edited
  EditText - A subclass of TextView used to create edit fields on forms
  AutoCompleteTextView - A text edit control with an associated list of autocomplete entries; autocomplete entries are shown in a drop-down list
  CheckBox - A button with two states—checked or unchecked
  RadioButton - A two-state button that can be grouped using RadioGroup so that only one button in the group can be checked
  Button - A button that has an associated event handler View.OnClickListener()
  ImageButton - Similar to the Button but supports an image rendered on its surface
  
Widgets can either be defined directly in code or using XML resource files (which is recommended)

Widget reference -> https://developer.android.com/reference/android/widget/package-summary.html

If declared in XML than can fetch from R:
  example = (Type) findViewById(R.id.<identifier>);
  
Android provides several different layouts (which are ViewGroups)
  Frame Layout: Child Views displayed as a stack, fixed to upper left of frame
    Example:
      <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ImageView android:src="@drawable/emo_im_yelling"
          android:id="@+id/frm_img_yell" android:visibility="invisible" />
        <Button android:text="Button" android:id="@+id/button1" … />
      </FrameLayout>
  Linear Layout: Row or Column of children
    Space is allocated in proportion to child layout_weight value
      If multiple with highest value: space equally shared
    Children may be assigned a gravity value
      top, bottom, left, right, center_vertical, center_horizontal...
    Example:
      <LinearLayout … android:orientation="vertical">
        <TextView …
          android:layout_weight="1"
          android:layout_gravity="center_vertical" />
        <TextView … />
      </LinearLayout>
  Table Layout
    Each row is a <TableRow>, each View within a cell
    Example:
      <TableLayout … android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TableRow android:id="@+id/tableRow1"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content">
          <TextView android:text="R1_C1"></TextView>
          <TextView android:text="Row1_Column2" ></TextView>
          <TextView android:text="R1_C3" ></TextView>
        </TableRow>
      </TableLayout>
  Relative Layout
    Child Views may be positioned relative to each other, or parent layout
      layout_alignRight, layout_alignBelow, layout_alignParentRight, layout_alignParentBelow...
    Example:
      <RelativeLayout...>
        <EditText android:layout_alignParentRight="true" android:text="EditText1"
          android:id="@+id/eT1" />
        <EditText android:layout_below="@id/eT1" android:text="EditText2"
          android:id="@+id/eT2" android:layout_toLeftOf="@id/eT1" />
        <EditText android:layout_below="@id/eT2" android:text="EditText3"
          android:id="@+id/eT3" android:layout_toRightOf="@id/eT2" />
        <EditText android:layout_alignParentLeft="true" android:text="EditText4"
          android:id="@+id/eT4" />
      </RelativeLayout>
  ++ Sliding Drawer, and Absolute
  
All Views may have height, width, and padding specifiers
  layout_width, layout_height, paddingTop, paddingLeft, paddingRight, paddingBottom
  match_parent - View should fill its parent (allowing space for any padding)
  wrap_content - View should be as small as possible to wrap its content (allowing for padding)
  Values may be specified as
    px (pixels)
    dp (density-independent pixels)
    sp (scaled pixels based on preferred font size)
    in (inches)
    mm (millimeters)  

Fragments
=====
Multi-pane user interfaces
A single activity may host multiple fragments
Has a view and some additional lifecycle methods
Multiple fragments can be active and can be optionally put on the backstack
Children of a ViewGroup
Five additional lifecycle methods:
  onAttach            The Fragment has been associated with an Activity
  onCreateView        The Fragment must create its View
  onActivityCreated   The parent Activity has completed its creation
  onDestroyView       The View associated with the Fragment is being destroyed
  onDetach            The Fragment is about to be disassociated from the Activity
A fragment must inflate it's own view (in the onCreateView method using inflater.inflate)
Can get / interact with parent activity
  Activity parentActivity = getActivity()
  
Example declaration in Activity:
  <LinearLayout android:orientation="horizontal" …>
    <fragment class="com.ltree.expenses.ExampleListFragment" android:id="@+id/frag_example_list" android:layout_width=… />
  ...

To load a Fragment dynamically:
  ExampleFragment frag = new ExampleFragment();
  FragmentTransaction ft = getFragmentManager().beginTransaction();
  ft.replace(R.id.frag_example_details, frag);
  ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
  ft.commit();
  
Can add to backstack (for back functionality):
  ft.addToBackStack("name");
  
Data can be passed into a Fragment from an Activity using a Bundle:
  Bundle args = new Bundle();
  args.putLong("name", value);
  frag.setArguments(args);

Which can then be fetched in the onCreate method of the activity:
  example = getArguments().getLong("name");
  
Good practice to set Framelayout's for dynamic Fragments:
  <LinearLayout …
    <FrameLayout android:id="@+id/frag_example_list" …/>
    <FrameLayout android:id="@+id/frag_example_details" …/>
  </LinearLayout>

Can then set one Framelayout to have a "gone" visibility in Potrait and dynamically add missing fragment to the backstack instead

Resources / res / R
=====
The layout XML files are stored within the resource directory structure
  Drawables - res/drawable - Graphics and bitmaps
    Image files (.png, .jpg, .gif)
    Nine-patch file—a .png with stretchable areas
    Should have a version in each of:
      res/drawable-xhdpi: extra-high–density images
      res/drawable-hdpi: high-density images
      res/drawable-ldpi: low-density images
      res/drawable-mdpi: medium-density images
– Android autofits it to the available space
  Layouts - res/layout - Layout files
  Menus - res/menu - XML declarations of menus
  Strings - res/values - XML declaration of strings
  Styles - res/values - XML declaration of styles and themes
  
R is an auto generated class based on the res directory contents, created during build of .apk

Example (Strings, same naming for other resource types) - normally res/values/strings.xml):
  <resources>
    <string name="hello">Hello Course 577</string>
    <string name="app_name">Samples</string>
  </resources>
  
Can then be referenced in Views:
  <TextView android:layout_width="fill_parent" android:layout_height="wrap_content"
    android:text="@string/hello"/>
    
In code: R.string.hello

Views are slightly different in ID structure (than the other resource types):
  <EditText android:id="@+id/eT2" android:layout_below="@id/eT1" .../>

In code: findViewById(R.id.eT2)

Styles can be used instead of directives like android:textColor="#ffff4d6b" / android:typeface="monospace"
  <style name="ButtonStyle" parent="@android:style/Widget.Button">
    <item name="android:textColor">#ffff4d6b</item>
    <item name="android:typeface">monospace</item>
  </style>
  
Apply a style in the manifest:
<application android:theme="@style/ApplicationTheme" >

Can also use localisation in resource directory structure
  res/<type>-<languageCode>-<regionCode>
    Language code is defined by a two-letter ISO 639 code
    Region code is two-letter ISO 3166-1-alpha-2 preceded by an r
    Specificity matters
  Other qualifiers see https://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources
Used generally for differ resolutions, orientation

Can use shortcuts to use to much repition, e.g:
  <resources>
    <item name="main" type="layout">@layout/narrow_layout</item>
  </resources>

Intents
=====
Intents are sent to the Framework to request an activity
  Explicit Intent: Specify a named class, can only be used within application
  Implicit Intent: Request an action (resolved by the framework)
By the user, through interaction, by applications
Must be sent through the framework using startService() or startActivity()

Example:
  Intent startSomethingIntent = new Intent(this, Something.class);
  startService(startSomethingIntent);

Data can be attached to an intent: 
  setData(URI data) – Used to pass details about a content provider 
  putExtra(String name, xxx value)
    Used to pass other data as name/value pairs
    xxx may be a primitive, CharSequence, or arrays of these types
    Object data may also be sent using the Parcelable or Serializable types  
      Serializable is part of the JDK
        Serializable objects may be written to and read from a stream
        Class be must be marked as implementing Serializable
        No methods to implement
      Parcelable classes may be converted to a Parcel
        Intended to pass data between Android processes
        Using the Android IPC mechanisms
        Relatively complex to implement    

Implicit Intent Example:
  // Specify an Action in the constructor
  Intent intent = new Intent("android.intent.action.VIEW");
  // Add optional categories
  intent.addCategory("lt.samples.showAll");
  // Add the URI of the content provider
  intent.setData(Uri.parse("content://com.ltree.weather/stations"));
  startActivity(intent);

Intent Filters (For implicit intents)
=====
Activities, services, and broadcast receivers register IntentFilters
Specify Action, Category, and Data handled
Usually declared in the manifest
Registered automatically on installation
Implicit Intent resolution is handled by the PackageManager
Matches Action, Category, and Data
Of the Intent against the values in the IntentFilter

When the PackageManager resolves an Intent it compares the values in the Intent with available IntentFilters to select a target

          Intent                                                        IntentFilter
Action    A single action                                               One or more. Intent action must match one. A filter with no actions matches any intent action.
Category  Zero or more                                                  Zero or more. Every category in the Intent object must match a category in the filter. If the filter contains additional values, it will still match.
Data      Zero or one. Specifies the URI of the data to be acted on     Zero or more MIME types. Matches if one of the filter values matches the Intent content type. May refine the filter by specifying values for scheme, authority, and path (zero or more of each).

Example implementation:
  <activity …>
    <intent-filter>
      <action android:name="android.intent.action.EDIT" />
      <category android:name="android.intent.category.DEFAULT" />
      <data android:mimeType="vnd.android.cursor.item/vnd.learningtree.station" />
    </intent-filter>
  </activity>
  
  #Specify a main activity (get launcher icon)
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>

Broadcast Reciever
=====
Recieves system intents
Example:
  <receiver android:name="BootCompletedReceiver">
    <intent-filter>
      <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
  </receiver>
  
To catch event and start a service:
  public class BootCompletedReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent bootIntent) {
      // Start a service here
      Intent intent = new Intent(context, SimpleIntentService.class);
      context.startService(intent);
    }
  }

Contexts
=====
Activities, services, and other components interact with the application framework via the Context object
Parent of both Activities and Services
  
Services
=====
Used for background / long running operations
Continue to run after associated activities are destroyed
Started in main thread so must start a thread for long running actions

Service -> IntentService -> MyService
  IntentService can automatically launch a background thread
  onCreate() override
    Code for main thread
  onHandleIntent() override
    Code for background thread
    
When startService() is called for an IntentService, the system
  1. Places the Intent on a queue (FIFO)
  2. Starts the service if not already running
  3. Invokes the service's onHandleIntent()for each Intent – In a background thread
  4. Stops the service when all Intents have been processed    

Example:
  public class SyncService extends IntentService {
    public SyncService() {
      // Super-class constructor requires a name
      // (only used for debugging)
      super("SyncService");
    }
    
    @Override
    protected void onHandleIntent(Intent intent) {
      // Background processing goes in here
      // It can't access the UI as it is in a thread
      
      
      
Content Providers
=====
Provide access to a data set to one or more applications
Exposed through a standard table like model
Each ContentProvider is identified by a unique URI
  Standard providers (bookmarks, contacts, etc.) have standard URIs built into the system
    ContactsContract.Thing.PROPERTY
  Custom providers—such as the Expenses app—must define a URI
    content://com.company.app/thing/property
URIs generall follow a REST like standard to identify resources
ContentProviders present data in tabular form
  The first column must be called _ID, is unique numeric, Used to identify record—the end of the provider URI
  Other columns can be of any type
ContentResolver locates and communicate with content providers

  protected void onResume() {
    super.onResume();
    String[] projection = new String[] { Browser.BookmarkColumns._ID, Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL };
    String[] displayFields = new String[] { Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL };
    int[] displayViews = new int[] { R.id.text1, R.id.text2 };
    Cursor cur = getContentResolver().query(
    Browser.BOOKMARKS_URI,
    projection, null, null, null);
    setListAdapter(new SimpleCursorAdapter(this,
    R.layout.two_item_list,
    cur, displayFields, displayViews));
  }

Example Insert:
  ContentValues values = new ContentValues();
  values.put("<name>", value);
  getContentResolver().insert(CONTENT_URI, values);
  
Example Delete (could also use where in query):
  Uri uri = ContentUris.withAppendedId(CONTENT_URI, id);
  getContentResolver().delete(uri, null, null);
  
Example Update:
  ContentValues values = new ContentValues();
  values.put("<key>","<value>");
  String where = "<name> = ?";
  String[] selectionArgs = {"<arg>"};
  getContentResolver().update(uri, values, where, selectionArgs);

A loader can be used to load content in the background:

  public class BookmarksLoaderActivity extends ListActivity implements LoaderManager.LoaderCallbacks<Cursor> {
  
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      mProjection = new String[] { Browser.BookmarkColumns._ID,…};
      String[] displayFields = new String[] {…};
      mAdapter = new SimpleCursorAdapter(this, R.layout.two_item_list,
      null, displayFields, displayViews,0);
      setListAdapter(mAdapter);
      getLoaderManager().initLoader(0, null, this);
    }  
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
      return new CursorLoader(this, android.provider.Browser.BOOKMARKS_URI, mProjection, null, null, null );
    }
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
      mAdapter.swapCursor(data);
    }
    public void onLoaderReset(Loader<Cursor> loader) {
      mAdapter.swapCursor(null);
    }
  }
  
To create own content provider:

  public class MyContentProvider extends ContentProvider {
    // Initialize the provider
    public boolean onCreate(){…}
    
    // Get the MIME type for the content
    // Return one of
    // vnd.android.cursor.item/vnd.<company>.<type> for single items
    // vnd.android.cursor.dir/vnd.<company>.<type> for multiple items
    // standard MIME type if this actually applies
    public String getType(Uri uri) {…}
    
    // Query the provider – results as a Cursor
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {…}
    
    // Insert new data – supplied in ContentValues
    public Uri insert(Uri uri, ContentValues values) {…}
  
    // Update values specified by where clause in where, whereArgs
    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {…}
  
    // Delete – supplied a where clause in where, whereArgs
    public int delete(Uri uri, String where, String[] whereArgs) {…}
  }

In order to get an ID from the uri (# for int, * for string match):

  #Add a pattern
  private static final ID = 2;
  sUriMatcher.addURI("<com.authority.identifier>", "<path>/#", ID);
  
  #Match a pattern
  sUriMatcher.match("content://<com.authority.identifier>/<path>/6"); //Returns 2
  
  #Can then switch on this value for implementation of methods
  #If matches ID patter then can extract using:
  long Id = ContentUris.parseId(uri);
  
  #Inserts must return the new uri and dont need _ID
  
Register a content provider in the manifest:
  <manifest … package="lt.samples" … >
    <application>
      ...
      <provider android:authorities="com.<company>.<app>" android:name=".db.SamplesCP" android:exported="false">
      </provider>
    </application>
  </manifest>

Storage
=====
Database (on or off the device)
Internal (on the device)
External (removable)

Broadcast Receivers
=====
Generally thin components designed to respond to a systemwide broadcast

Lifecycle
=====
When an activity is started it is put on the back stack, and the previous activity is stopped
Previous activity restarted on user pressing the back button generally, current activity is destroyed
Three states:
  Resumed
  Paused - May be killed by OS, obscured
  Stopped - In background, may be killed by OS
Generally any data should be saved when a activity is removed from the foreground

Lifecycle methods (in order)
  onCreate()
  onStart()
  onResume()
  RUNNING STATE - In foreground
  onPause() - can also go to onResume()
  PAUSED - In background (partially obscured), can be cleaned up by OS (rare)
  onStop() - can also go to onStart() via onRestart()
  STOPPED STATE - In background (fully obscured), can be killed by OS
  onDestroy()
  DEAD - Killed

Android sees applications as nonresponsive if
  They fail to respond to user input within 5 seconds
  A BroadcastReceiver hasn’t finished executing within 10 seconds
  Don't do long running work in the main thread (the UI thread)
  
The interface thread is not thread safe, updating from a background thread will fail
  
Creating a thread (main thread get priority, CPU time split between threads):
  
  ExecutorService executorService = Executors.newSingleThreadExecutor();
  executorService.exec(new Runnable() {
    @Override
    public void run() {
      // Do something in the background
    }
  });
  
Or to run in main thread:
  view.postDelayed(new Runnable() {
    public void run() {
    // Stuff to do after 500mS delay
    }
  },500);

AsyncTask
=====
  For background processing that needs to interact with the user interface
  AsyncTask is started by calling execute() on an instance of the class
  Operation of AsyncTask
    1. doInBackground(Params...): The main method for the background thread
    2. onProgressUpdate(Progress...): Runs on UI thread – In response to call to publishProgress()from the background thread
    3. onPostExecute(Result): Runs on UI thread – Result is the return value from doInBackground()
  An instance of AsyncTask can only be started (execute() called) once, construct a new one to run again  
  
Example AsyncTask:
  class UpdateServerTask extends AsyncTask<String, Integer, Double> {
    // Background processing (runs in the background thread)
    protected Double doInBackground(String... params) {
      return updateServer(urls[0]);
    }
    // Runs on the UI thread (parameter is result of doInBackground)
    protected void onPostExecute(Double result) {
      mTextViewResult.setText("Done: Result=" + result
    }
    // Runs on UI thread in response to call to publishProgress()
    protected void onProgressUpdate(Integer... progress) {
      mProgressBar.setProgress(progress[0]);
    }
    
    private Double updateServer(String url){
      while(stuffToDo){
        result = doWork(url);
        publishProgress(percentComplete);
      }
      return result;
    }
  }

Services
=====
Perform long-running background tasks
Even when an application’s activities are paused or destroyed
But poor service design can still lead to ANR errors
Can be bound to an activity to create a view
Run in the main thread

Subclass android.app.Service and create code to
  Start and stop the service
  Manage background threading
Subclass android.app.IntentService
  Android manages service start/stop and creates a thread for each request

  
Logging
=====
Android has a logging tech similar to log4j
Held in memory
LogCat displayes logs during development
Log.v (verbose), Log.d (debug), Log.i (information), Log.w (warning), Log.e (error)
Define a tag in the class to use with log lines
  private static final String TAG="IntentService"
  
Toasts
=====
Invoke a short lived pop-up message:
  static Toast makeText(Context context, int resId, int duration)
  static Toast makeText(Context context, CharSequence text, int duration)
  
Status Bar
=====
Invoked by activities and services, clicking on expanded notification can launch activity

Example:

  int icon = R.drawable.emo_im_yelling;
  CharSequence notiTickerText = "NOTIFICATION! – Ticker Text";
  long notiTime = System.currentTimeMillis();
  CharSequence notiTitle = "A NOTIFICATION!";
  CharSequence notiContent ="I'm trying to tell you something!";
  
  Intent notificationIntent = new Intent(context, NotificationActivity.class);
  PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
  
  Notification.Builder notiBuilder = new Notification.Builder(context);
  notiBuilder.setSmallIcon(icon).setTicker(notiTickerText).setWhen(notiTime)
  .setAutoCancel(true).setContentText(notiContent).setTitleText(notiTitle).setContentIntent(pendingIntent);
  Notification notification = notiBuilder.build();
  
  String ns = Context.NOTIFICATION_SERVICE;
  NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
  mNotificationManager.notify(SAMPLE_NOTIFICATION, notification);

Event Handling
=====
Common events:
  Click - User clicks (touches widget or presses an “enter” key)
  Long click - Same inputs as click, but held for one second
  Focus change - User navigates onto or away from View item
  Key - User presses a key while view has focus
  Touch - Any touch event
  
Views have associated listener methods for the different events:
  Click - View.OnClickListener
  Long click - View.OnLongClickListener
  Focus change - View.OnFocusChangeListener
  Key - View.OnKeyListener
  Touch - View.OnTouchListener
  
Example:

  View but = findViewById(R.id.name);
  but.setOnClickListener(new View.OnClickListener() {
  
    @Override
    public void onClick(View v) {
    }
  });
  
Dialogs
=====
Pop-up window to which the user must respond
Implemented by DialogFragment

Example:

  public void onClick(View v) {
    DatePickerFragment newFragment = new DatePickerFragment();
    mExpenseDate = Calendar.getInstance();
    Bundle args = new Bundle();
    args.putSerializable(DatePickerFragment.INPUT_DATE_MS, mExpenseDate);
    newFragment.setArguments(args);
    newFragment.show(getActivity().getSupportFragmentManager(), "datePicker");
  }
  
  public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
    public static final String INPUT_DATE_MS = "Input Date in Millis";

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
      final Calendar c = (Calendar)
      getArguments().getSerializable(INPUT_DATE_MS);
      return new DatePickerDialog(getActivity(), this, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
    }
    
    public void onDateSet(DatePicker view, int y, int m, int d) {
      final Calendar c = Calendar.getInstance();
      c.set(Calendar.YEAR, y);
      c.set(Calendar.MONTH, m);
      c.set(Calendar.DAY_OF_MONTH, d);
      updateDate(c);
    } 
  }
  
Menus
=====
Options Menu: When the menu button is pressed
Context Menus: Long click (like a right click)
Defined in res/menu
e.g. res/menu/menu.xml is identified by R.menu.menu

Example:

  <menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_add" android:title="@string/menu_str_add" />
    <item android:id="@+id/menu_sync" android:title="@string/menu_str_sync" android:icon="@drawable/ic_menu_sync" />
  </menu>
  
In activity, override:
  public boolean onCreateOptionsMenu(Menu menu)
  public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
  
onCreateContextMenu() is only called if registerForContextMenu(View view) has previously been called

Example Inflation:

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.name, menu);
    return true;
  }
  
Example Options menu handling:

  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
      case R.id.menu_refresh:
        //...
        return true;
      case R.id.menu_add:
        //...
        return true;
      default:
        return super.onOptionsItemSelected(item);
    }
  }
  
Action Bar
=====
Displays option menu items at top of screen
Options menu items may be displayed as actions
  <menu …>
  <item … android:icon="@drawable/ic_menu_add" android:showAsAction="ifRoom|withText" />
Action bar is configured in the manifest
Automatically enabled if targetSdkVersion is >= 11
May be disabled by setting the theme to a non-holographic theme

Adaptors and AdaptorViews
=====
Android provides many AdapterView subclasses
Each provides a different way of visually organizing items
Examples:
  ListView - Displays items in a vertically scrolling list, uses ListAdapter
  GridView - A two-dimensional scrolling grid view, uses ListAdapter
  Spinner - Expanding list view; displays single selected item until activated, uses Adapter
  Gallery - Horizontally scrolling list, typically of images, uses Adapter
The items are Views returned from the Adapter

Example (Using a list and ArrayAdapter):
  #Main Activity
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.stations_list);
  
  #Layout Res File
  <LinearLayout …
    <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/listView" android:layout_weight="1" />
  </LinearLayout>
  
  #Layout For Items Res File (Coult use R.layout defaults instead):
  <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text1" android:layout_width="match_parent" android:layout_height="match_parent" />
  
  #List Activity
  ArrayList<String> theArrayList = getListData();
  ArrayAdapter<String> theListAdapter = new ArrayAdapter<String>(this, R.layout.list_item, theArrayList);
  
  #Main Activity
  ListView mList;
  mList = (ListView) findViewById(R.id.listView);
  mList.setAdapter(stationListAdapter); 

Example (Using TextViews and SimpleCursorAdapter):
  
  #R.layout.two_item_list
  <LinearLayout …>
    <TextView android:id="@+id/text1" …/>
    <TextView android:id="@+id/text2" …/>
  </LinearLayout>
  
  #ShowDatabaseInListActivity.java
  protected void onResume() {
    String[] projection = new String[] { "<columnName>", "<columnName>", "<columnName>" };
    Cursor cursor = qb.query(mDb, projection, null, null, null, null, null);
    String[] fromFields = new String[] { "<columnName>", "<columnName>" };
    int[] toViews = new int[] { R.id.text1, R.id.text2 };
    SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(this,
    R.layout.two_item_list,
    cursor,
    fromFields, toViews);
    setListAdapter(cursorAdapter);
  }
  
JUnit
=====
Android uses extentions of JUnit to allow for context / lifecycle based unit testing
ActivityTestCase, ProviderTestCase, ServiceTestCase, etc
Otherwise the same as in Java, test classes extend AndroidTestCase

How to create on list item click listener:
  public void onItemClick(AdapterView<?> parent, View, int position, long id)
    parent - The AdapterView where the click happened
    view - The view that was clicked within the ListView
    position - The position of the view in the list
    id - The row ID of the item that was clicked
  Use l.getItemAtPosition(position); to get item clicked 
  
Example:
  public class TheActivity extends Activity implements AdapterView.OnItemClickListener
    protected void onCreate(Bundle savedInstanceState) {
      mList = (ListView) findViewById(R.id.listView);
      mList.setOnItemClickListener(this);
    }
    
    public void onItemClick(AdapterView<?> theList,
      View view, int position, long id) {
      String station = (String)theList.getItemAtPosition(position);
    }
    ...
    
Changes to the Adapter data cascade generally, can be forced with notifyDataSetChanged()

Form Widgets (Views)
=====
Fetch with ID
  <Type> name = (<Type>) findViewById(R.id.<id>);
Set content:
  name.setText(<CharSequence>);
Fetch content:
  CharSequence name = name.getText();

Content Providers
=====
All types of storage can be accessed using a content provider

Storage - Shared Preferences
=====
For simple application preferences
Restricted to primitives and strings
Deleted when application is removed
Saved into memory private to the application /data/data/<packageName>

Access:
  SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
  <Type> name = prefs.get<Type>("<identifer>", false); #Where type is one of boolean, int, float, long, String
  
Edit:
  SharedPreferences.Editor editor = prefs.edit();
  editor.put<Type>("<identifer>", <value>); #Where type is one of boolean, int, float, long, String
  commit();

Storage - Internal
=====
Android supports the standard Java API for file I/O with some additions specific to Android’s storage mechanisms

Read:
  FileInputStream openFileInput (String name)
  
Write:
  FileOutputStream openFileOutput (String name, int mode)

Storage - External
=====
Accessed much like internal, but must check for state:
  String state = Environment.getExternalStorageState(); #Want Environment.MEDIA_MOUNTED or Environment.MEDIA_MOUNTED_READ_ONLY
Can have private or shared storage on external
Private locations:
  File getExternalFilesDir(String type) #From Context
Shared locations:
  File getExternalStoragePublicDirectory(String type) #From Environment
Use File.mkdirs() to create directories

Storage - SQLite
=====
Is self-contained, Is serverless, Requires zero configuration, Is transactional, Implements most of SQL92, Is written in C/C++
Private to the application, unless shared with content providers
android.database.sqlite.SQLiteDatabase

Example class with onCreate implementation (called when DB does not exist):

  class DatabaseHelper extends SQLiteOpenHelper {
   private static final String DB_CREATE = "<SQL>";
  
   public void onCreate(SQLiteDatabase db) {
      db.execSQL(DB_CREATE); //Does not return a result
   }
   
Methods for insert, update, delete, query - use ContentValues to add key / value pairs
nullableColumnName in some methods requires name of a column which can contain NULL value - this protects against a SQLite limitiation (https://stackoverflow.com/questions/2662927/android-sqlite-nullcolumnhack-parameter-in-insert-replace-methods)

Example Insert:

  SQLiteDatabase db = dbHelper.getWritableDatabase();
  ContentValues values = new ContentValues();
  values.put("<columnName>", "<value>");
  long rowId = db.insert("<Tablename>", "<nullableColumnName>", values);

Example Update:

  String where = "<columnName> = ?";
  String[] selectionArgs = {"<values>"};
  int count = db.update("<tableName>", values, where, selectionArgs);
  
Example Select:

  SQLiteDatabase db = dbHelper.getReadableDatabase();
  SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
  qb.setTables("<table>");
  String where = "<columnName> = ?";
  String[] selectionArgs = {Long.toString(id)};
  Cursor c = qb.query(
    db, 
    new String[] {"<columnToReturnInOrder>", "<columnToReturnInOrder>"},
    where,
    selectionArgs,
    "<groupBy>",
    "<having>",
    "<sort>"
  );
  while (c.moveToNext()) {
    Log.i(TAG, "<columnNameOne>=" + c.get<Type>(0));
    Log.i(TAG, "<columnNameOne>=" + c.get<Type>(1));
  }

Networking
=====
Android provides good support for networked applications
  java.net.*: basic Java networking support
  android.net.*: additional network functionality for the Android platform
    NetworkInfo: support for querying the network status
      Wi-Fi or mobile network connection
      Is the device roaming?
      Etc.
    Additional support for SSL in the mobile environment
    URL sanitizers
    Etc.
    
Can use sockets, basic http or web service clients
For maximum efficiency
  Use the java.net.HttpURLConnection class for HTTP communication
  To keep the application responsive
    Connections must be performed in a background thread
    Use AsyncTask or implement your own threading
    Network connection made on the main thread will cause exceptions in API 11+
    
Simple HTTP example:
  private String fetchHTML(URL serviceUrl) throws Exception {
    String result = "Nothing received! ";
    HttpURLConnection urlConnection = (HttpURLConnection)serviceUrl.openConnection();
    try {
      int responseCode = urlConnection.getResponseCode();
      if (responseCode == HttpURLConnection.HTTP_OK) {
        result = readStringFromStream(urlConnection.getInputStream());
      } else {
        result = readStringFromStream(urlConnection.getErrorStream());
      }
    } catch (Exception e) {
      Log.e(TAG, "Connection failed " + e.getMessage());
    } finally { 
      urlConnection.disconnect();
    }
    return result;
  }
  
Use getOutputStream to write a post request (as Bytes)
  
To build from stream:
  private String readStringFromStream(InputStream in) {
    StringBuilder sb = new StringBuilder();
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(in));) {
      String nextLine = "";
      while ((nextLine = reader.readLine()) != null) {
        sb.append(nextLine);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    return sb.toString();
  }
  
To create JSON to send to a web service, use JSONArray for arrays:
  JSONObject jObj = new JSONObject();
  jObj.put("name", value);
  jObj.put("name", value);
  jObj.put("name", value);
  String json = jObj.toString();
   
To get data from JSON response example:
  JSONTokener tokenizer = new JSONTokener(jsonString);
  JSONObject wrapper = (JSONObject)tokenizer.nextValue();
  JSONArray things = wrapper.getJSONArray("thing");
  for (int i = 0; i < things.length(); i++) {
    Log.i(TAG, "Description = " + things.getJSONObject(i).getString("name"));
  }
  
Drag and Drop
=====
Android drag-and-drop has four stages in its life cycle
  Start: The drag has been started
  Continuing: Events created as potential targets are dragged over
  Dropped: Notification that the item has been dropped
  Ended: The drag has stopped—either dropped or released
  
Example Listener:
  protected class TrashDragEventListener implements OnDragListener {
    public boolean onDrag(View v, DragEvent event) {
      switch (event.getAction()) {
        case DragEvent.ACTION_DRAG_STARTED: // Drag has started
        case DragEvent.ACTION_DRAG_ENTERED: // Drag is over this view
        case DragEvent.ACTION_DRAG_EXITED: // Drag has left this view
        case DragEvent.ACTION_DRAG_ENDED: // Drag finished
        case DragEvent.ACTION_DROP: // Dropped in this view
        return false; // true to accept the event
      }
    }
    
Can access passed data:
  ClipData data = event.getClipData();
  ClipData.Item uriClipItem = data.getItemAt(0);
  
Set Listener with:
  view.setOnDragListener(new View.OnDragListener()…
  
To start the drag:
  public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id) {
    ...
    Uri exampleUri = ContentUris.withAppendedId(intent.getData(), id);
    ClipData data = ClipData.newUri(getActivity().getContentResolver(), "Drag data", exampleUri);
    v.startDrag(data, new View.DragShadowBuilder(v), null, 0);
    return true;
  }
  
Geolocation
=====
Android provides several mechanisms for determining location
  Global Positioning System
  Cell-based—position based on the cell to which you are connected
  Wi-Fi—position based on Google’s database of Wi-Fi names
  
Example to get last known location (Using GPS):
  LocationManager locMan = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
  Location lastKnownLocation = locMan.getLastKnownLocation(LocationManager.GPS_PROVIDER);
  if (null != lastKnownLocation) {
    Log.i(TAG,"Location. Lat: " + lastKnownLocation.getLatitude() + "lon" + lastKnownLocation.getLongitude());
  }
  
To get update events, register a LocationListener:
  locMan.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, new LocationListener() {
    public void onLocationChanged(Location location) {
      storePosition(location);
    }
    ...
  });
  
Google Maps can be integrated easily using Android Studio (which automatically insert permissions into the manifest and map fragment)
Keys are required for dev and live for google maps
There are methods to add markers and navigate to given locations

Example:
  private void setUpMap() {
    Location location = (Location) getIntent().getParcelableExtra("FIX");
    LatLng pos = new LatLng(location.getLatitude(),
    location.getLongitude());
    CameraPosition cameraPosition = new CameraPosition.Builder().target(pos).zoom(9).build();
    CameraUpdate camUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition);
    mMap.moveCamera(camUpdate);
    mMap.animateCamera(camUpdate);
    MarkerOptions marker = new MarkerOptions().position(pos).title("Location").draggable(false);
    mMap.addMarker(marker);
  }