mobile application development · 2018. 9. 21. · storage in local databases •android has full...
TRANSCRIPT
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