mobile application development · 2018. 9. 21. · storage in local databases •android has full...

Post on 24-Sep-2020

9 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Mobile Application Development

MTAT.03.262

Jakob Mass

jakob.mass@ut.ee

Recap from last lecture

• Views & Layouts• Nesting

• LinearLayout, ConstraintLayout

• Fragments

• Intents & Components• Basic introduction to application components

• Intents & Intent Filters

• Launching Activities

• Context

Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 221/09/2018

This lecture

• Other Application Components• Broadcast Receivers

• Content Providers

• Services

• Data Storage• File access

• Working with databases

• Handling Background tasks

• Home Assignment 1 (and HW3)

Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 321/09/2018

Broadcast Receivers

• Allows your app to receive events outside of user flow• System level messages

• E.g. Boot finished, picture was captured, charger connected

• App-initiated:• Data finished downloading & ready to use

• An entry-point to your app

• With System events, Android runtime notifies all receivers registered to that event• E.g. register for ACTION_BOOT_COMPLETED

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 4

https://developer.android.com/guide/components/broadcasts

Implementing a Broadcast receiver• Implement as subclass of BroadcastReceiver

• Receive Intent broadcast objects withonReceive(Context context, Intent intent)

• The Intent object may contain additional info• As we discussed last lecture

• E.g. the Intent for Airplane mode changing has a Boolean extra

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 5

https://developer.android.com/guide/components/broadcasts

Implementing a Broadcast receiver: Java

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 6

public class MyReceiver extends BroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent){

// react to the broadcast event

}

}

Receiving broadcasts (1)

To register for a given type of broadcast, either:

• Declare the BroadcastReceiver in the Manifest:

The system launches your app if not running when broadcast is sent

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 7

https://developer.android.com/guide/components/broadcasts

<receiverandroid:name=".MyReceiver"android:enabled="true"android:exported="true"><intent-filter>

<action android:name="android.intent.action.BATTERY_LOW"></action>

</intent-filter></receiver>

.. Or register using Context

• In this case, the lifecycle of the context influences how long the receiver can get events!

BroadcastReceiver br = new MyReceiver();

IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);

filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);this.registerReceiver(br, filter);// later:this.unregisterReceiver(br);

Receiving broadcasts (2)

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 8

https://developer.android.com/guide/components/broadcasts

Receiving implicit broadcasts

• Since API ver. 26, implicit broadcasts should not be declared in the manifest

• Instead, use the programmatic approach

• Currently, there’s a list of exceptions to this:• https://developer.android.com/guide/components/broa

dcast-exceptions

• The recommended approach is to use JobSchedulers

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 9

Sending Broadcasts

• LocalBroadcastManager.sendBroadcast( … )• Sent to receivers within your app• More performant

• sendBroadcast(Intent)• Sent to all receivers

• sendOrderedBroadcast(Intent, String) • Sent to all receivers, but one at a time• Order is specified with android:priority attribute of the

matching intent-filter• Can chain the broadcast

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 10

https://developer.android.com/guide/components/broadcasts#sending-broadcasts

Intent intent = new Intent();

intent.setAction("com.example.broadcast.MY_MESSAGE");

intent.putExtra("data","My custom message");

sendBroadcast(intent);

Example: logging the number of a call

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 11

public class CallReceiver extends BroadcastReceiver {String TAG = "CallReceiver";

@Overridepublic void onReceive(Context context, Intent intent) {

if (intent.getExtras() != null){String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);Log.i(TAG, state);

//System receives 2 “RINGING” broadcasts: 1 with number and 1 withoutif (intent.hasExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)){

String phoneNo = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);

Log.i(TAG, phoneNo);}

}

}}

Example (2) – registering the receiver

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 12

<receiver android:name=".CallReceiver"android:enabled="true"android:exported="true"><intent-filter>

<action android:name="android.intent.action.PHONE_STATE"></action>

</intent-filter></receiver>

System Permissions

• Divided into 2 categories: normal and dangerous

• Normal:• Do not directly risk user’s privacy• E.g. setting the time zone• If declared in manifest, system grants the permissions

automatically

• Dangerous:• May give app access to user’s confidential data• In addition to listing the permissions in the manifest,

app has to ask user for each individual permission when running

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 13

https://developer.android.com/guide/topics/permissions/overview#normal-dangerous

Permissions example for Receiving Phone Calls

1. Declare in manifest ↑

2. Request permission from user in Activity:

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 14

https://developer.android.com/reference/android/telephony/TelephonyManager#ACTION_PHONE_STATE_CHANGED

String[] requestedPermissions = new String[]{Manifest.permission.READ_PHONE_STATE,Manifest.permission.READ_CALL_LOG

};ActivityCompat.requestPermissions(this, requestedPermissions, 1);

<uses-permission android:name="android.permission.READ_PHONE_STATE"/><uses-permission android:name="android.permission.READ_CALL_LOG"/>

@Overridepublic void onRequestPermissionsResult( … ) {

// User has made a choice, check & react to results}

Exercise 1

• Repeat call logging example

• Don’t forget about permissions

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 15

Data Storage with Android

• Storage in ‘normal’ files• External & internal storage

• Using Preference files

• Using local databases• Structured data with e.g. SQLite

• Network Storage (not part of this lecture)

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 16

https://developer.android.com/guide/topics/data/data-storage

File storage (Internal)

• The default file save location is the Internal storage• Private to your app (even user cannot access)

• System provides a private directory for each app• Specified by package name

• Internal storage removed upon uninstall!

• getFilesDir()

• openFileInput()

• openFileOutput()

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 17

https://developer.android.com/training/data-storage/files#WriteInternalStorage

File file = new File(context.getFilesDir(), "foo.txt");

Internal Storage example

• Using openFileOutput, note the 2nd argument (file mode)• MODE_PRIVATE• MODE_WORLD_READABLE, MODE_WORLD_WRITEABLE –

deprecated since API 17!

getCacheDir()• Returns File for apps cache directory• Should keep usage low• System deletes files here when disk space is running out

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 18

https://developer.android.com/training/data-storage/files#WriteInternalStorage

String FILENAME = "myfile.txt";

FileOutputStream fos =

openFileOutput(FILENAME, Context.MODE_PRIVATE);

fos.write("Hello, file!".getBytes());

fos.close();

Exercise 2

• Working with files• Try to write a string to a file

• Then, read back the contents of the file

• Try to see that they are the same

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 19

External Storage

• World-readable and modifiable by user

• Potentially removable – e.g. SD card

• Apps still need permissions to access:• android.permission.READ_EXTERNAL_STORAGE• android.permission.WRITE_EXTERNAL_STORAGE

• This is the right place to store data that survives application uninstall – e.g. photos, documentsThere is also an option to use ext. storage for app-

specific storage that is removed upon uninstalled and other apps cannot access (e.g. you don’t want to waste internal storage space)

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 20

https://developer.android.com/training/data-storage/files#WriteExternalStorage

External Storage - continued

1. Make sure you have the right permission

2. Verify storage is available!Environment.getExternalStorageState() – returning• Environment.MEDIA_MOUNTED• Environment.MEDIA_MOUNTED_READ_ONLY• ..

3. Open directory• Public - getExternalStoragePublicDirectory()• Private - getExternalFilesDir()• Argument determines file type: e.g.

Environment.DIRECTORY_PICTURES, DIRECTORY_RINGTONES, can also use null

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 21

Ext. Storage: Scoped Directory access

• An API for accessing common external directories

• In cases where you are targeting specific directories• Avoid requesting READ_EXTERNAL_STORAGE

• Provides a simple permissions UI that clearly details what directory the application is requesting access to

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 22

https://developer.android.com/training/articles/scoped-directory-access

Summary of Internal/External Storage• Internal Storage

• Always available

• Files saved here accessible by only your app

• Files deleted when your app is uninstalled

• External storage• World-readable, outside of your control

• Files deleted during uninstall only if you save them to Private external storage directories (getExternalFilesDir())

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 23

Storage in Preference files

• For storing a “small” collection of key-value pairs• Light-weight & easy to use• Not shareable across applications• SharedPreferences object

• Points to a file containing the data• Provides simple read/write methods

• Create/access a preferences file with:• getSharedPreferences(String name, int mode)

• File identified with custom name• Call with any Context

• getPreferences()• Call from Activity Context• Single, default file for that activity

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 24

https://developer.android.com/training/data-storage/shared-preferences

SharedPreferences Examples

• Recommended to prefix the preferences file with your app ID, e.g. “com.example.myapp.MY_PREFERENCE_FILE”

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 25

SharedPreferences prefs = getSharedPreferences(

getString(R.string.pref_file_key),

Context.MODE_PRIVATE);

// Changes to preference file are

// done using an Editor object

SharedPreferences.Editor editor = prefs.edit();

editor.putInt("highScore", newHighScore);

editor.commit(); // or apply() for asynchronous writing

// Read values:

prefs.getBoolean("silentMode", false);

Storage in local databases

• Android has full support for SQLite databases

• Databases are accessible only to apps which create them

• While SQLite can be used directly, we will be using the Room persistence library

• Room is an abstraction layer over SQLite:• Reduces boilerplate code• Provides verification of queries• Manages DB schema changes

• If you want to work with the lower level SQLite APIs:• https://developer.android.com/training/data-storage/sqlite

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 26

Room Overview

1. Database• main access point to

persisted data

2. Entity• A table within the

database

3. Data Access Object (DAO) • the methods used for

accessing the database

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 27

https://developer.android.com/training/data-storage/room/

implementation ‘android.arch.persistence.room:runtime:1.1.1’

Defining Data

• Include the relevant dependencies, e.g. in build.gradle:

• For each field that's defined in the entity, a column is created in the DB• Use @Ignore annotation to avoid this

• Room needs access to your fields in order to persist them so either:• Fields need to be public• You must define getter and setters

• Each entitity must define at least 1 primary key field• Annotate with @PrimaryKey• Assign automatic ID-s with @PrimaryKey(autoGenerate = true)

• Let’s define a Entity representing users

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 28

https://developer.android.com/training/data-storage/room/defining-data

@Entity

public class User {

@PrimaryKey

private int uid;

@ColumnInfo(name = "first_name")

private String firstName;

@ColumnInfo(name = "last_name")

private String lastName;

// Getters & setters are also needed

}

Getting started with Room

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 29

https://developer.android.com/training/data-storage/room/defining-data

Define access to data with DAOs

• Define the methods which correspond to queries

• Room has various convenience annotations for defining the DAO methods:• @Insert

• @Update

• @Delete

• @Query

• Let’s use these for the User entity

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 30

https://developer.android.com/training/data-storage/room/accessing-data

Getting started with Room (2)

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 31

https://developer.android.com/training/data-storage/room/accessing-data

@Dao

public interface UserDao {

@Query("SELECT * FROM user")

List<User> getAll();

@Query("SELECT * FROM user WHERE uid IN (:userIds)")

List<User> loadAllByIds(int[] userIds);

@Query("SELECT * FROM user WHERE first_name LIKE :first AND "

+ "last_name LIKE :last LIMIT 1")

User findByName(String first, String last);

@Insert

void insertAll(User... users);

@Delete

void delete(User user);

}

Define the database

To create a Room-Database class:

1. Create an abstract class extending RoomDatabase

2. Annotate class with @Database• Define associated entities

3. Define abstract method with 0 arguments that returns class annotated with @Dao

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 32

https://developer.android.com/training/data-storage/room/

@Database(entities = {User.class}, version = 1)

public abstract class AppDatabase extends RoomDatabase {

public abstract UserDao userDao();

}

Now we can use our database!

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 33

https://developer.android.com/training/data-storage/room/

// Get the DB

AppDatabase db = Room.databaseBuilder(

getApplicationContext(),

AppDatabase.class, "db-name")

.allowMainThreadQueries() // use non-UI-thread instead

.build();

// Use a method of the DAO

User user = db.userDao().findByName("John", "Doe");

db.userDao().delete(user);

Managing Schema changes

• As your app gets enhanced, the entities and their schema will change• E.g. what if we want to add the users birthday?

• If you simply add/change class fields, you will get:

• The proper solution is to• Update the version in @Database annotation• Define Migrations to manage how old data should be

handled when schema changes

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 34

https://developer.android.com/training/data-storage/room/migrating-db-versions

java.lang.RuntimeException: Unable to start activity …: java.lang.IllegalStateException:Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.

Content Providers

• Content providers manage access to a structured set of data

• Enable sharing of data across applications• Address book, Calendar, Photo Gallery, …

• By default, applications can’t access the data and files of other applications

• In effect, a Content Provider is an abstraction interface to data storage mechanisms• Uniform APIs for CRUD

• Create, Read, Update Delete

• Files, SQLite databases, in-memory hash maps• Secure

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 35

https://developer.android.com/guide/topics/providers/content-providers

Content Provider

• Presents data to external applications as one or more tables• Row – instance of some data type• Column – individual piece of data for an

instance

• Manages access to the stored data for various APIs and components:• Sharing data with other apps• Sending data to a widget• Loading data into UI• …

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 36

https://developer.android.com/guide/topics/providers/content-provider-basics

Accessing Content Providers

• To access data in a Content Provider, you use a ContentResolver―ContentResolver cr =

getContentResolver();

• ContentResolver provides methods to perform basic CRUD operations

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 37

https://developer.android.com/guide/topics/providers/content-provider-basics#ClientProvider

Example: user dictionary

• Stores the spellings of non-standard words that the user wants to keep

• _ID column acts as primary key, maintained by the provider

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 38

word app id frequency locale _ID

mapreduce user1 100 en_US 1

precompiler user14 200 fr_FR 2

applet user2 225 fr_CA 3

const user1 255 pt_BR 4

int user5 100 en_UK 5

Using ContentResolver example

• Call ContentResolver.query():

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 39

// Queries the user dictionary and returns results

getContentResolver().query(

UserDictionary.Words.CONTENT_URI, // Content URI of the words table

mProjection, // Columns to return for each row

mSelectionClause, // Selection criteria

mSelectionArgs, // Selection criteria

mSortOrder); // Sort order for returned rows

Content URIs

• A content URI is a URI that identifies data in a provider.

• Content URIs include• The fixed scheme value for content URI-s (content://)

• Symbolic name of the entire provider (its authority)

• a name that points to a table or file (a path).

• Optional: id part points to an individual row in a table (query.

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 40

https://developer.android.com/guide/topics/providers/content-provider-basics#ContentURIs

Scheme Authority Path Query

Example Continued

• Note: The User Dictionary Provider defines the android.permission.READ_USER_DICTIONARY in it’s manifest, so clients of it must request this permission

• Next, constructing the query

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 41

getContentResolver().query(

UserDictionary.Words.CONTENT_URI,

mProjection,

mSelectionClause

mSelectionArgs,

mSortOrder);

• Projection defines which columns to return

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 42

https://developer.android.com/guide/topics/providers/content-provider-basics#Query

getContentResolver().query(

mURI,

mProjection,

mSelectionClause

mSelectionArgs,

mSortOrder);

// String array values are contract class constants

String[] mProjection = {

UserDictionary.Words._ID,

UserDictionary.Words.WORD,

UserDictionary.Words.LOCALE

};

• Selection Clause – logical statement for filtering rows

• Selection Args – arguments for selection clause, if clause uses replaceable parameter “?”

• No filtering:

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 43

https://developer.android.com/guide/topics/providers/content-provider-basics#Query

getContentResolver().query(

mURI,

mProjection,

mSelectionClause

mSelectionArgs,

mSortOrder);

String mSelectionClause = null;

String[] mSelectionArgs = {""};

//SQL: SELECT .. FROM words WHERE word = “mobile”

mSelectionClause = UserDictionary.Words.WORD + " = ?";

mSelectionArgs = new String[]{"mobile"};

Content Provider Query Results

• As a result of the query, a Cursor object is returned

• Cursor provides random read access to returned rows & columns

• Cursor.getCount() returns no. of matches

• You can iterate over the Cursor’s rows

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 44

https://developer.android.com/guide/topics/providers/content-provider-basics#DisplayResults

Example - Contacts Content Provider

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 45

Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

String[] SELECTED_COLUMNS = {

ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,

ContactsContract.CommonDataKinds.Phone.NUMBER,

};

private Cursor makeContactsQuery() {

Cursor cursor = getContentResolver().query(uri, SELECTED_COLUMNS, null,null,null);

return cursor;

}

Cursor cursor = makeContactsQuery();

Log.i(TAG, "Rows: " + cursor.getCount());

int indexName = cursor.getColumnIndex(SELECTED_COLUMNS[0]);

int indexNumber = cursor.getColumnIndex(SELECTED_COLUMNS[1]);

while (cursor.moveToNext()) {

String name = cursor.getString(indexName);

String number = cursor.getString(indexNumber);

Log.i(TAG, name + "; " + number);

}

Adapters

• Adapter – bridge between AdapterView and data• Binds the view to external data source

• Initializes and populates the View

• AdapterView – view that displays items loaded into an adapter

• Call Adapter.notifyDataSetChanged()to refresh the UI

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 46

https://developer.android.com/guide/topics/providers/content-provider-basics#DisplayResultshttps://developer.android.com/guide/topics/ui/binding

Array

Example with ArrayAdapter

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 47

https://developer.android.com/guide/topics/ui/declaring-layout#AdapterViews

ArrayList<String> nameList = new ArrayList<>();

ArrayAdapter<String> adapter = new ArrayAdapter<>( this,

android.R.layout.simple_list_item_1, //TextView for value

nameList // source data object

);

// Note: simple_list_item_1 is a Android OS default file

// Bind array to the list view

listView.setAdapter(adapter);

// Update the dataset

nameList.add("Johnny");

adapter.notifyDataSetChanged();

Cursor Adapter

• SimpleCursorAdapter – An AdapterViewimplementation for use with Cursors.• Specify layout to use for rows

• Specify which columns to use

• Cursor must include the _ID column!

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 48

https://developer.android.com/reference/android/widget/SimpleCursorAdapter

Example – ContactsProvider, ListView and CursorAdapter

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 49

https://developer.android.com/guide/topics/providers/content-provider-basics#DisplayResults

String[] SELECTED_COLUMNS = {

ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,

ContactsContract.CommonDataKinds.Phone.NUMBER,

};

int[] toViews = {R.id.textview_name, R.id.textview_number};

SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(

this, // context

R.layout.list_row, // layout that defines the views for this list item.

cursor, // The database cursor

SELECTED_COLUMNS, // "from" - column names of the data to bind to the UI

toViews, // TextViews that should display column in the "from" param

0 // Flags used to determine the behavior of the adapter

);

listView.setAdapter(cursorAdapter);

Modifying data

• ContentResolver.insert() – returns URI of inserted row

• ContentResolver.update()• Specify query selection criteria

• Use ContentValues to set new values

• ContentResolver.delete()• Specify query selection criteria

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 50

https://developer.android.com/guide/topics/providers/content-provider-basics#Modifications

ContentValues values = new ContentValues();

values.put(Data.RAW_CONTACT_ID, rawContactId);

values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);

values.put(Phone.NUMBER, "1-800-GOOG-411");

values.put(Phone.TYPE, Phone.TYPE_CUSTOM);

values.put(Phone.LABEL, "free directory assistance");

Uri dataUri = getContentResolver().insert(Data.CONTENT_URI, values);

Finding existing and creating new Content Providers• To find out about the existing various providers

available on Android, check out:• https://developer.android.com/reference/android/provi

der/package-summary

• You want to share data with other applications• E.g. widgets

• You want to implement custom search suggestions

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 51

Creating Content Providers

• Extend ContentProvider class

• Override the necessary methods• Insert, delete, update

• Query handling

• Declare provider in manifest

• For more info refer to the developer portal

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 52

https://developer.android.com/guide/topics/providers/content-provider-creating

<manifest>

<provider

android:name=".MyContentProvider"

android:authorities="ee.ut.cs.exampleprovider"

android:enabled="true"

android:exported="true"></provider>

</manifest>

Exercise

• Display contact names and phone numbers

• Don’t forget permissions

• Stick to ContactsContract.CommonDataKinds.Phone!

• The Contacts Provider can be complex, spans more than one table

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 53

Background Processing

• Main thread – handles UI• Drawing views

• User interaction

• Lifecycle events

• Too much work on Main/UI thread – slowdowns & hiccups

• All long-running tasks should be run on a separate background thread

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 54

https://developer.android.com/guide/background/

Homework 3

• Using services to run a background music player• Also include a SharedPreferences-based counter to see

how many times music has been played

• https://courses.cs.ut.ee/2018/MAD/fall/Main/Homework3

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 55

Services

• Faceless components that run in the background• E.g. music player, network download, etc.

• Have higher priority than background activities, thus suitable for long-running tasks• Recall runtime memory management

• Services can take 2 forms:• Started

• Called with startService()• Run indefinitely

• Bound • App components bind to the service with bindService()• Runs as long as there are components bound to it• Provides a binding – a client-server interface

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 56

https://developer.android.com/guide/components/services

Services - continued

• Explicitly starting a new Service:

• Implementing your own Service• Extend Service class and declare in Manifest• Override callback methods

• NOTE: A Service still runs in the main thread of host process. If you need to do blocking calls / CPU-heavy tasks, create a Java Thread within the Service!

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 57

https://developer.android.com/guide/components/services

Intent intent = new Intent(this, MyService.class);

startService(intent);

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 58

https://developer.android.com/guide/components/services

public class MyService extends Service {

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

// invoked through startService()

}

@Override

public IBinder onBind(Intent intent) {

// invoked through bindService()

// TODO: Return the communication channel to the service.

}

// Other lifecycle methods like onCreate, onDestroy

}

Process Management Recap

• By default, components of a single app run in the same process

• When the system wants to run a new component• If app doesn’t yet have any running components, a new

process with a single execution thread is started

• Otherwise, component is started within that process

• It’s possible to control which process certain components run in• Manifest android:process XML attribute

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 59

https://developer.android.com/guide/components/processes-and-threads

Threads

• As there is 1 main execution thread, both application components and UI interactions are done synchronously

• Long computations, I/O background tasks on the main thread will block the UI

• If the UI thread hangs for more than a few seconds (5s), the “Application Not Responding” dialog is presented• Poor user experience

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 60

Threads continued

• The Android UI functions are NOT thread-safe

• All UI manipulation must be done from UI thread

• Thus• On one hand you should do work on worker threads

• On the other hand, you can’t update UI from those threads

• What to do? Use messages and/or helper methods:

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 61

https://developer.android.com/guide/components/processes-and-threads#WorkerThreads

• Activity.runOnUiThread(Runnable)• View.post(Runnable)• View.postDelayed(Runnable, long)

Working with threads

• Several ways for implementing background work:• Standard Java threads, extending Runnable

• Use the helper methods from prev. slide• Do messaging with Handlers

• Android AsyncTask• Useful for one-off tasks, e.g. download image• 4 callback methods:

• doInBackground• onPreExecute• onPostExecute• onProgressUpdate

• Only doInBackground run on worker threads, others on UI thread!

• For more complex applications, consider using WorkManager API

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 62

Example – Sending results from Worker Thread to UI thread

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 63

http://developer.android.com/guide/components/processes-and-threads.html

new Thread(new Runnable() {

public void run() {

// a time consuming task

final Bitmap bitmap = processBitMap("image.png");

// post results to UI thread

mImageView.post(new Runnable() {

public void run() {

mImageView.setImageBitmap(bitmap);

}

});

}

}).start();

Our Android skills so far…

• Lifecycle management of Android applications

• GUI development

• Working with Application Components• Activities• Broadcast Receivers• Content Providers• Services

• Managing Intents, Background tasks, Permissions

• Managing data: File storage, databases

We are ready to start creating serious applications!

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 64

Home Assignment 1: Contact Picker

• Have an activity with design in fig-A with contacts of the phone

• Select a contact• Opens details Activity

• Send an email to the selected contact

• Back to original screen and display as in fig-B• Indicate which contact e-

mail was composed to

• Have an action bar (app bar) and introduce search functionality

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 65

A B

Next week

• Working with Sensors & Internet of Things

21/09/2018 Mobile & Cloud Lab. Institute of Computer Science, University Of Tartu 66

top related