oscarb pad

Guides, resources, notes, docs and knowledge for everything Oscar.

Tags

Android Development Notes

Intents

Example from Intents and Intent Filters

// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

Preserve state when navigating upwards

android:launchMode

When up-navigation is present, use singleTop for the main activity to preserve state when navigating upwards. This will also stop new activites from being started from a notification.

See

Uri

Build URLs using Uri.Builder

compileSdkVersion, minSdkVersion, and targetSdkVersion

Organizing code

Previewing layouts in Android Studio

Use the tools attribute

Frpm Android Studio 3.0, samples are available:

@sample/lorem

Lifecycle

An Activity appears in the foreground
onCreate -> onStart -> onResume

An Activity is sent to the background (app switched)
onPause -> onStop -> onDestroy

From Active to Visible (but not active) (modals)
onPause -> onResume

From Active or Visible to Background
onPause -> onStop -> onRestart -> onStart

Lifecycle

Loaders

Persistance

Five ways to persist data in Android:

Preferences

Reading From SharedPreferences

getDefaultSharedPreferences
Gets a SharedPreferences instance that points to the default file that is used by the preference framework in the given context!
getSharedPreferences
Gets a specific SharedPreferences instance by name in case you have more than one preference in the same context!

Preference Change Listener

Update preference fragment

Guidelines

Should it be a setting?

Make it a setting?

SQLLite Database

Create a database

Content provider

Using a ContentProvider

  1. Get permission to use the ContentProvider.

    <uses-permission android:name="com.example.appname.TERMS_READ" />
    
  2. Get the ContentResolver

    ContentResolver resolver = getContentResolver();
    Cursor cursor = resolver.query(Contract.CONTENT_URI, null, null, null, null);
    
  3. Pick one of four basic actions on the data: query, insert, update, delete
  4. Identify the data you are reading or manipulating to create a URI
  5. In the case of reading from the ContentProvider, display the information in the UI

Creating a content provider

  1. Extend the ContentProvider class and implement the required methods
  2. Register it in the Manifest
  3. Define URI’s
  4. Add URI’s to the contract class
  5. Build a URIMatcher to match URI patterns

URI Example:

content://com.example.appname/specificData

CONTENT_URI

Cursor methods arguments

Match integer: #
Match string: *

Example of getType:

public String getType(@NonNull Uri uri) {
    int match = sUriMatcher.match(uri);

    switch (match) {
        case TASKS:
            // directory
            return "vnd.android.cursor.dir" + "/" + TaskContract.AUTHORITY + "/" + TaskContract.PATH_TASKS;
        case TASK_WITH_ID:
            // single item type
            return "vnd.android.cursor.item" + "/" + TaskContract.AUTHORITY + "/" + TaskContract.PATH_TASKS;
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
    }
}

The best way to asynchronously load data from any ContentProvider is with a CursorLoader

Comparing S09.05-Exercise-MoreDetails…S09.05-Solution-MoreDetails · udacity/ud851-Sunshine

BulkInsert
Comparing S09.02-Exercise-ContentProviderBulkInsert…S09.02-Solution-ContentProviderBulkInsert · udacity/ud851-Sunshine

Code Quality

Services

Background task

“More background” than Loader (more front-end)
Loaders outlasts configuration changes
Services outlasts activites

Start a service

Lifecycle:

IntentService

Automatically runs on the background thread in order, perfect for one off tasks that need to be handled in the background in order.

Runs on a worker thread (compared to the main thread for a Service).

Stops itself after requests have been handled unlike a Service which needs to be stopped with stopSelf() or stopService()

“Fire and forget”

Comparing T10.01-Exercise-IntentServices…T10.01-Solution-IntentServices · udacity/ud851-Exercises

Android 8.0

Many apps that rely on IntentService do not work properly when targeting Android 8.0 or higher. For this reason, Android Support Library 26.0.0 introduces a new JobIntentService class, which provides the same functionality as IntentService but uses jobs instead of services when running on Android 8.0 or higher.

https://developer.android.com/reference/android/support/v4/app/JobIntentService.html

JobService

The base class that handles asynchronous requests that were previously scheduled in a JobScheduler.

Because it runs on the main thread any task needs to be set up on another thread/handler/AsyncTask to avoid blocking future callbacks from the JobManager.

Adding a JobService - YouTube
Exercise: Schedule with FirebaseJobDispatcher - YouTube

It’s important that we verify that we’ve imported jobdispatcher.JobService rather than the Android framework’s JobService, because if you do, you’ll definitely have some headaches. Double and triple check that please.

ForegroundService

Service required to have a non-dismissible ongoing notification. Less likely to be destroyed when memory gets low.

JobScheduler

FirebaseJobDispatcher

Example

Driver driver = new GooglePlayDriver(context);
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(driver);

Job myJob = dispatcher.newJobBuilder()
    // the JobService that will be called
    .setService(MyJobService.class)
    // uniquely identifies the job
    .setTag("complex-job")
    // one-off job
    .setRecurring(false)
    // don't persist past a device reboot
    .setLifetime(Lifetime.UNTIL_NEXT_BOOT)
    // start between 0 and 15 minutes (900 seconds)     
    .setTrigger(Trigger.executionWindow(0, 900))
    // overwrite an existing job with the same tag
    .setReplaceCurrent(true)
    // retry with exponential backoff 
    .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
    // constraints that need to be satisfied for the job to run
    .setConstraints(
        // only run on an unmetered network
        Constraint.ON_UNMETERED_NETWORK,
        // only run when the device is charging
        Constraint.DEVICE_CHARGING
    )
    .build();

Scheduling Jobs - YouTube
The Firebase JobDispatcher

Comparing T10.04-Exercise-PeriodicSyncWithJobDispatcher…T10.04-Solution-PeriodicSyncWithJobDispatcher · udacity/ud851-Exercises

String resources

Pluralization

XML

<plurals name="charge_notification_count">
   <item quantity="zero">Hydrate while charging reminder sent %d times</item>
   <item quantity="one">Hydrate while charging reminder sent %d time</item>
   <item quantity="other">Hydrate while charging reminder sent %d times</item>
</plurals>

Java

String formattedChargingReminders = getResources().getQuantityString(R.plurals.charge_notification_count, chargingReminders, chargingReminders);

Documentation

String format

XML

<string name="format_art_url" translatable="false">https://raw.githubusercontent.com/udacity/Sunshine-Version-2/sunshine_master/app/src/main/res/drawable-xxhdpi/art_<xliff:g id="description">%s</xliff:g>.png</string>

Java

context.getString(R.string.format_art_url, "clear");

PendingIntent

Intent in your app designed to be started by another app/service.

This allows a notification (which is handled by the NotificationManager (a system service)) to start your App.

Notifications

Use a PendingIntent to open your App from a notification.

Notifications - Patterns - Material design guidelines

[Notifications Android Developers](https://developer.android.com/guide/topics/ui/notifiers/notifications.html)
[Using Big View Styles Android Developers](https://developer.android.com/training/notify-user/expanded.html)
[Notification.BigPictureStyle Android Developers](https://developer.android.com/reference/android/app/Notification.BigPictureStyle.html)

Comparing T10.02-Exercise-CreateNotification…T10.02-Solution-CreateNotification · udacity/ud851-Exercises

Add actions to notifications

Engage with rich notifications

Check for Google Play Services both in onCreate() and onResume()

For Android versions >= HONEYCOMB, notifcation image sizes can be found with

int largeIconWidth = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? 
	? resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_width)
	: resources.getDimensionPixelSize(R.dimen.notification_large_icon_default);

Where R.dimen.notification_large_icon_default is set to 48dp

Set the color for notifications from Firebase in the manifest with:

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
     notification message. See README(https://goo.gl/6BKBk7) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

If the device doesn’t have a compatible version of Google Play services, your app can call GoogleApiAvailability.makeGooglePlayServicesAvailable() to allow users to download Google Play services from the Play Store.

Must use channels once target O is targeted.

Memory prioritization

Broadcast Receiver

System Broadcast Intents - triggers for various device changes.

Creating a broadcast receiever:

To handle broadcasts when app isn’t started: JobDispatcher or in some cases a static broadcast receiver
To handle broadcasts when app is started: dynamic broadcast receiver

Register in onResume() and unregister in onPause if it only is needed for foreground stuff.

Comparing T10.05-Exercise-ChargingBroadcastReceiver…T10.05-Solution-ChargingBroadcastReceiver · udacity/ud851-Exercises

Android Debug Bridge

Start app

adb shell am start -n com.package.name/com.package.name.ActivityName

Simulate unplugging from USB

adb shell dumpsys battery set usb 0

Above for Android 6.0+

adb shell dumpsys battery unplug

Simulate plugging into power

adb shell dumpsys battery reset
[Android Debug Bridge Android Studio](https://developer.android.com/studio/command-line/adb.html?utm_source=udacity&utm_medium=mooc&utm_term=android&utm_content=adb&utm_campaign=training)

View and View Groups

Avoid nesting view and viewgroups too deep.

General rule of thumb:

Views & View Groups - YouTube

Correct the ImageView’s adjustViewBounds behaviour on API Level 17 and below with AdjustableImageView :: The Cheese Factory

ViewGroups

FrameLayout

LinearLayout

RelativeLayout

GridLayout

ConstraintLayout

Center vertically by putting a top-constraint to the bottom of the other view, and a bottom-constraint to the top of the other view

TextAppearance

Captions

@style/TextAppearance.AppCompat.Captiom

Headline

@style/TextAppearance.AppCompat.Display1

Hierarchy viewer

Tools > Device monitor > Perspective > Hierarcy viewer

Accessibility

[Accessibility Developer Checklist Android Developers](https://developer.android.com/guide/topics/ui/accessibility/checklist.html#recommendations)

Localization

Localization Checklist | Android Developers
ISO 639-2 Language Code List - Codes for the representation of names of languages (Library of Congress)
Localization checklist | Android Developers

RecyclerView

Different views in a RecyclerView
Comparing S11.02-Exercise-TodayListItem…S11.02-Solution-TodayListItem · udacity/ud851-Sunshine

Provide height and width or face the consequences

DesignSupportLibrary

Parcel

http://blog.bradcampbell.nz/a-comparison-of-parcelable-boilerplate-libraries/

Style vs Theme

A theme is a style applied to an activity

For lists, use dimensions such as: @dimen/list_item_icon_margin_right

Layout

Use the smallest width qualifier

?attr/listPreferredItemHeight

Touch selectors

  1. Create drawable list_item_selector.xml
  2. Root element should be selector
    0- Add items for different states
    • state_pressed
    • state_activated
    • state_selected
    • default
      Note: each item can have a color as the drawable
  3. Set background of item to be selected to the newly created touch selector

Publishing an app

Material Design

Typography

Display 4 corresponds to

android:textAppearance="@style/TextAppearance.AppCompat.Display4"

and so on…

Libraries

Look for support, documentation and functionality

Testing

Android Testing Codelab

Material design

Toolbar

Default toolbar size height: `?attr/actionBarSize”

Style with

   android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"   

Card

cardPreventCornerOverlap="false"

Refs

Aliases as resources

refs.xml

<resources>
  <item type="layout" name="refName">@layout/some_layout</item>
</resources>

RecyclerView

Item choices

https://github.com/udacity/Advanced_Android_Development/compare/6.17_Improving_our_RecyclerView…6.18_Bonus_RecyclerView_Code
Using RecyclerView Part 3 - YouTube

Implementing a modal selection helper for RecyclerView

Parallell scrolling

  1. Attach scrollListener
    • Change translation in y of background by half in relative to the y scroll
    • Clear onScrollListeners in onDestroy

Scrolling in Parallel - YouTube
Scrolling in Parallel - YouTube

Support higher screen ratios

In order to support screen ratios such as 18.5:9 (like that on the Samsung Galaxy S8), add the following to the manifest, in the application element:

_Where ratio_float is the maximum aspect ratio your app can support, expressed as (longer dimension / shorter dimension) in decimal form. _

https://android-developers.googleblog.com/2017/03/update-your-app-to-take-advantage-of.html

Transitions

Exclude navigation bar and status bar with @android:id/statusBarBackground and @android:id/navigationBarBackground respectively.

<item name="android:windowContentTransitions">true</item>
<item name="android:windowEnterTransition">@transition/enter_transition</item>
<item name="android:windowReturnTransition">@transition/return_transition</item>
ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(this);
ActivityCompat.startActivity(this, intent, activityOptions.toBundle());
[Animation Resources Android Developers](https://developer.android.com/guide/topics/resources/animation-resource.html)
[The Transitions Framework Android Developers](https://developer.android.com/training/transitions/overview.html)
[Animating Views Using Scenes and Transitions Android Developers](https://developer.android.com/training/transitions/index.html)
[Applying a Transition Android Developers](https://developer.android.com/training/transitions/transitions.html)

Shared elements

Shared Element Transitions (solution) - YouTube

Android Developers Blog: Continuous Shared Element Transitions: RecyclerView to ViewPager

Places API

Comparing 8.00_Places_API_Start…8.07_Adding_Attributions · udacity/Advanced_Android_Development

[Place Picker     Google Places API for Android     Google Developers](https://developers.google.com/places/android-api/placepicker#add)

Widgets

Creating the Widget’s view - YouTube
7.01_Sunshines_First_Widget · udacity/Advanced_Android_Development

SyncAdapter

minResizeWidth can be set to smaller than default size minWidth

Collection widget: YouTube

AppWidgetProviderInfo (XML)

Required attributes

Size = 70dp * n - 30dp
= 40 dp for n = 1
= 110 dp    = n = 2

AppWidgetProvider (Java)

public class TodayWidgetProvider extends AppWidgetProvider {
  @Override 
  public void onUpdate(Context context, AppWidgetManager manager, int[} appWidgetIds) {
    for (int appWidgetId : appWidgetIds) {
      RemoteViews = views = new RemoteViews(context.getPackageName(), R.layot.widget_today_small);
      
      // Clickable widget
      Intent intent = new Intent(context, MainActivity.class);
      PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
      views.setOnClickPendingIntent(R.id.widget, pendingIntent);
      
      manager.updateAppWidget(appWidgetId, views);
      
    }  
  }
}

Performance

“Users will complain about performance 3x than any other issue”

[Performance Tips Android Developers](https://developer.android.com/training/articles/perf-tips.html)

Overdraw

Test overdraw

Memory Monitor

[Manage Your App’s Memory Android Developers](https://developer.android.com/topic/performance/memory.html)

Publishing

Fonts

MVI - Model View Intent

Debugging

Fragments

UX

Check for unessecary added permissions from libraries

How Libraries can silently add permissions to your Android App

Android Architecture

Android Developers Blog: Android and Architecture

[Guide to App Architecture Android Developers](https://developer.android.com/topic/libraries/architecture/guide.html)

WebView

Enable Google Safe Browsing API

Same as in Chrome

<manifest>
	<meta-data
    	android:name="android.webkit.WebView.EnableSafeBrowsing"
        android:value="true" />
    <!-- ... --->
</manifest>

Adaptive icons

Date, time and calendars

Android O

Location

VectorDrawable

Launcer Icon Sizes

size identifier size
ldpi 36x36
mdpi 48x48
hdpi 72x72
xhdpi 96x96
xxhdpi 144x144
xxxhdpi 192x192
Google Play 512x512

Google Play Referrer API

See http://android-developers.googleblog.com/2017/11/google-play-referrer-api-track-and.html

Auto-backup for apps

Android Developers Blog: Discover tools for Android data migration and improve your app retention