44
Android Application Model II CSE 5236: Mobile Application Development Instructor: Adam C. Champion, Ph.D. Course Coordinator: Dr. Rajiv Ramnath Reading: Big Nerd Ranch Guide, Chaps. 3, 5 (Activities); Chap. 28 (Services); Chap. 14 (DB); Chap. 15 (Contacts) 1

Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Android Application Model II

CSE 5236: Mobile Application DevelopmentInstructor: Adam C. Champion, Ph.D.Course Coordinator: Dr. Rajiv RamnathReading: Big Nerd Ranch Guide, Chaps. 3, 5 (Activities); Chap. 28 (Services); Chap. 14 (DB); Chap. 15 (Contacts)

1

Page 2: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Outline

• Activity Lifecycle• Services• Persistence• Content Providers

2

Page 3: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Recap

• Android Framework• Activities• General UI:– Layouts, Handler methods– Widgets, Custom UI classes, Handling within activity

• Specialized UIs:– Menus and the Action Bar– Special Activities – Preferences

• UI for larger screens: Fragments3

Page 4: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

The Activity Lifecycle

• Android runtime manages Activities• Activities have a “lifecycle” consisting of

states: from creation until death• Standard (lifecycle) methods on the

activity are invoked at each state change (can test by rotating device)

4

Page 5: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Activity States• Created: Born to run• Active: Working 9 to 5• Paused: I’m about to break• Resumed: Back to work• Stopped: Obscured by clouds, vulnerable

5

Page 6: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Activity Transitions• Created ⟹ Active• Active ⟺ Paused• Paused ⟹ Stopped ⟹ Active• Stopped ⟹ Killed

6

Page 7: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Timing of ActivityLifecycle Methods

7

Page 8: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Lifecycle Methods• onCreate(Bundle savedInstanceState): create

views, (re) initialize state• onStart(): Restore transient state; one-time processing• onResume(): Session-specific processing, restore

transient state• onPause(): Save persistent data, release resources,

quickly! Last method guaranteed to be called.• onStop(): Called optionally by runtime • onDestroy(): If finish() is called, or object is being

temporarily destroyed. Distinguish via isFinishing().8

Page 9: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Transient State Management Methods• onSaveInstanceState(...): Called

before onPause(); use to save transient state.

• onRestoreInstanceState(...): Called after onStart() and onResume(); use to restore state.

9

Page 10: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Transient State Management: Java// MapsActivity.java

public class MapsActivity extends AppCompatActivity /* . . . */ {

private MapView mMapView;

private String whereAmIString = null;. . .

@Overrideprotected void onSaveInstanceState(Bundle outState) {

super.onSaveInstanceState(outState);mMapView.onSaveInstanceState(outState);if (whereAmIString != null) {outState.putString(WHERE_AM_I_STRING, whereAmIString);}

}

. . .

protected void onRestoreInstanceState(Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);whereAmIString = savedInstanceState.getString(WHERE_AM_I_STRING);if (whereAmIString != null) { mEditLocation.setText(whereAmIString); }

}} 10

Page 11: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Interaction Across Activities

• Activity 1: onPause()• Activity 2: onCreate(), onStart(), onResume()

• Activity 1: onStop() – if it is obscured

11

Page 12: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Starting Activities: Intents and Intent Filters• Message posted to the Android runtime to launch

an activity; matched against IntentFilter of activity in AndroidManifest.xml file

• Encourages activity reuse among applications• Uniform mechanism for launching internal and

external activities• Enables loose coupling between caller, responder

12

Page 13: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Intent and Intent Filter Components

• Target – fully qualified name (string), direct reference

• Action – standard or custom (string)• Data (URI)• Category of the target object

13

Page 14: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Intent Filters: Examples<!-- AndroidManifest.xml -->

<intent-filter> <!== for SplashScreen activity ==>

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

<category android:name="android.intent.category.LAUNCHER"/>

</intent-filter>

<intent-filter> <!== for Login activity ==>

<action

android:name="com.wiley.fordummies.androidsdk.tictactoe.Login">

<category android:name="android.intent.category.DEFAULT" />

</intent-filter>

14

Page 15: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Intent Invocations: Examples: Java• Matching component name: startActivity(new Intent(

"com.wiley.fordummies.androidsdk.tictactoe.Login"));

• Direct invocation: startActivity(new Intent(getActivity().getApplicationContext(), SettingsActivity.class));

• Passing data: public void sendScoresViaEmail() {Intent emailIntent = new Intent(Intent.ACTION_SEND);emailIntent.putExtra(Intent.EXTRA_SUBJECT,"Look at my AWESOME TicTacToe Score!");

emailIntent.setType("plain/text");emailIntent.putExtra(Intent.EXTRA_TEXT, firstPlayerName + " score is " + scorePlayerOne + " and " + secondPlayerName + " score is " + scorePlayerTwo);startActivity(emailIntent);

} 15

Page 16: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Intent Invocations: Examples: Kotlin• Matching component name: startActivity(Intent(

"com.wiley.fordummies.androidsdk.tictactoe.Login"))

• Direct invocation: startActivity(Intent(activity.applicationContext, SettingsActivity::class.java))

• Passing data: fun sendScoresViaEmail() {val emailIntent = Intent(Intent.ACTION_SEND)

emailIntent.putExtra(Intent.EXTRA_SUBJECT,

"Look at my AWESOME TicTacToe Score!")

emailIntent.type = "plain/text"

emailIntent.putExtra(Intent.EXTRA_TEXT, mFirstPlayerName +

" score is " + mScorePlayerOne + " and " + mSecondPlayerName +

" score is " + mScorePlayerTwo)+-

startActivity(emailIntent)

} 16

Page 17: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Tasks and Activity Stacks

• Task: a (conceptual) container for sets of “like-minded” activities

• Roughly corresponds to a Linux process• Activities are stacked in tasks• Activities can move across tasks• Task is requested by calling intent or

selected based on taskaffinity attribute in AndroidManifest.xml file

17

Page 18: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Outline

• Activity Lifecycle• Services• Persistence• Content Providers

18

Page 19: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Services

• Activities for background, long-term processing (e.g., email, music, synchronization)

• Local: Accessible by a single app.• Remote (aka bound): Accessible by all apps on the device

– See: http://developer.android.com/guide/topics/fundamentals/services.html#CreatingBoundService

• Comparison with threads:– Coarser-grained processing– Lifecycle separated from launching activity– More resources consumed – More respected J by OS

19

Page 20: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Service Example: Javapublic class MediaPlaybackService extends Service {

MediaPlayer player;

@Override

public IBinder onBind(Intent intent) {/*...*/}

public void onCreate() {

player = MediaPlayer.create(this, R.raw.sampleaudio); player.setLooping(true);

}

public int onStartCommand(Intent intent, int flags, int startId) { /* ... */

Bundle extras = intent.getExtras();

String audioFileURIString = extras.getString("URIString");

Uri audioFileURI = Uri.parse(audioFileURIString);

player.reset(); player.setDataSource(this.getApplicationContext(), audioFileURI);

player.prepare(); player.start(); /* ... */

}

public void onDestroy() { player.stop(); }

} 20

Page 21: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Service Example: Kotlinclass MediaPlaybackService : Service() {

override fun onBind(intent: Intent): IBinder? {/*. . .*/}

override fun onCreate() {

player = MediaPlayer.create(this, R.raw.sample_audio)

player.apply { isLooping = true } }

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {

super.onStartCommand(intent, flags, startId)

val extras = intent.extras

if (extras != null) {

val audioFileURIString = extras.getString("URIString")

val audioFileURI = Uri.parse(audioFileURIString)

player.reset()

player.setDataSource(this.applicationContext, audioFileURI)

player.prepare()

player.start()

} }

override fun onDestroy() { player.stop() }

}21

Page 22: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Service Invocation

Java. . .

Intent musicIntent =

new Intent(getApplicationContext(),MyPlaybackService.class);

musicIntent.putExtra("URIString",mAudioFileURI.toString());

getActivity().startService(musicIntent);

. . .

Kotlin. . .

val musicIntent = Intent(activity.applicationContext,MediaPlaybackService::

class.java)musicIntent.putExtra(

"URIString",mAudioFileUri.toString())

activity.startService(musicIntent)

. . .

22

Page 23: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Outline

• Activity Lifecycle• Services• Persistence• Content Providers

23

Page 24: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Saving Persistent Data – Files

• Same as in any Java or Kotlin app• Internal storage (Linux file system)– Local to app– Destroyed upon uninstall

• External storage (e.g., SD card)– Stored to SD card or flash memory (device-

dependent)– Shared among applications– E.g.:

24

Java KotlinFile imageFile =

new File(imageFilePath);val imageFile =

File(imageFilePath)

Page 25: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Saving Persistent Data – SQLite

• http://sqlite.org: “Most widely deployed SQL database engine in the world”– Lightweight, transactional

• Helper class for database creation• Methods for operating on SQL statements:– Creating a statement– Binding data– Executing

25

Page 26: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

SQLite Example: Account Model Class

Java// Account.javapublic class Account {

private String mName, mPassword;

public Account(String name, String password) {mName = name;

mPassword = password; }

public String getName() { . . . }public String getPassword() { ... }

/* equals(), hashCode(), toString() */}

Kotlin// Account.kt

data class Account(val name: String,val password: String) {

// We don't need anything here!}

26

Kotlin data classes automatically generate getters, setters, equals(), hashCode(), and toString()

Page 27: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

SQLite Example: DB Schema: Java

// AccountDbSchema.javapublic class AccountDbSchema {

public static final class AccountsTable {public static final String NAME = "accounts";

public static final class Cols {public static final String NAME = "name";public static final String PASSWORD = "password";

}}

}

// Also used with Kotlin

27

Page 28: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

SQLite Example: Account CursorWrapper

Java// AccountCursorWrapper.javapublic class AccountCursorWrapper

extends CursorWrapper {public AccountCursorWrapper(

Cursor cursor) { super(cursor); }public Account getAccount() {

String name = getString(getColumnIndex(

AccountsTable.Cols.NAME));String password = getString(

getColumnIndex(AccountsTable.Cols.PASSWORD));

Account account = new Account(name, password);

return account;}

}

Kotlin// AccountCursorWrapper.ktclass AccountCursorWrapper(cursor: Cursor) :

CursorWrapper(cursor) {

val account: Accountget() {

val name = getString(getColumnIndex(

AccountsTable.Cols.NAME))

val password = getString(getColumnIndex(

AccountsTable.Cols.PASSWORD))

return Account(name, password)}

}28

Page 29: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

SQLite Example: Account Singleton: Java

// AccountSingleton.java

public class AccountSingleton {private static AccountSingleton sAccount;private AccountDbHelper mDbHelper;private SQLiteDatabase mDatabase;private static final String INSERT_STMT ="INSERT INTO " + AccountsTable.NAME +"(name, password) VALUES (?, ?)" ; /* . . . */

private AccountSingleton(Context context) {mDbHelper = new AccountDbHelper(context.getApplicationContext());

mDatabase = mDbHelper.getWritableDatabase();

}private static ContentValues getContentValues(Account account) {ContentValues values = new ContentValues();values.put(AccountsTable.Cols.NAME,account.getName());

values.put(AccountsTable.Cols.PASSWORD,account.getPassword());

return values;

}

// Continued . . .

// Continued . . .

public void addAccount(Account account) {ContentValues contentValues =getContentValues(account);

. . . SQLiteStatement statement =mDatabase.compileStatement(INSERT_STMT);

statement.bindString(1, contentValues.getAsString(AccountsTable.Cols.NAME));

statement.bindString(2,contentValues.getAsString(AccountsTable.Cols.PASSWORD));

statement.executeInsert();

}public void deleteAllAccounts() { /* ... */

mDatabase.delete(AccountsTable.NAME, null, null);

}}

// Also used with Kotlin29

Page 30: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

SQLite Example: Helper Class: Java// AccountDbHelper.java

public class AccountDbHelper extends SQLiteOpenHelper {private Context mContext;private static final String DATABASE_NAME = "TicTacToe.db";private static final int DATABASE_VERSION = 1;public AccountDbHelper(Context context) {

super(context, DATABASE_NAME, null, DATABASE_VERSION); }

@Overridepublic void onCreate(SQLiteDatabase sqLiteDatabase) {

sqLiteDatabase.execSQL("CREATE TABLE " + AccountsTable.NAME + "(" +"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +

AccountsTable.Cols.NAME + " TEXT, " + AccountsTable.Cols.PASSWORD + " TEXT" + ")");}

@Overridepublic void onUpgrade(SQLiteDatabase sqLiteDatabase, /* ... */) {

Log.w("Example", "Example: upgrading DB; dropping/recreating tables.");sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + AccountsTable.NAME);onCreate(sqLiteDatabase); }

}30

Page 31: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

SQLite Example: Helper Class: Kotlin// AccountDbHelper.kt

class AccountDbHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {private lateinit var mContext: Context

override fun onCreate(sqLiteDatabase: SQLiteDatabase) {sqLiteDatabase.execSQL("CREATE TABLE " + AccountsTable.NAME + "(" + "_id INTEGER PRIMARY KEY AUTOINCREMENT, " + AccountsTable.Cols.NAME + " TEXT, " + AccountsTable.Cols.PASSWORD + " TEXT" + ")")}

override fun onUpgrade(database: SQLiteDatabase, /* ... */) {Log.w("Example", ”Upgrading DB; dropping/recreating tables.")database.execSQL("DROP TABLE IF EXISTS " + AccountsTable.NAME)onCreate(database) }

companion object {private val DATABASE_NAME = "TicTacToe.db"private val DATABASE_VERSION = 1 }

} 31

Page 32: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

SQLite Example: DB Operations: Java// AccountFragment.java

private void createAccount() {FragmentActivity activity = getActivity();String username = mEtUsername.getText().toString(), String password = mEtPassword.getText().toString();String confirm = mEtConfirm.getText().toString();if (activity != null) {

if ((password.equals(confirm)) && (!username.equals("")) && (!password.equals("")) && (!confirm.equals(""))) {AccountSingleton singleton = AccountSingleton.get(activity.getApplicationContext());Account account = new Account(username, password);singleton.addAccount(account);Toast.makeText(activity.getApplicationContext(), "New record inserted",

Toast.LENGTH_SHORT).show();} else if ((username.equals("")) || (password.equals("")) || (confirm.equals(""))) {

Toast.makeText(activity.getApplicationContext(), "Missing entry", Toast.LENGTH_SHORT).show();

} else if (!password.equals(confirm)) {/* Show error message */

} else { /* Error handling */ }}

} 32

Page 33: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

SQLite Example: DB Operations: Kotlin// AccountFragment.kt

private fun createAccount() {val username = mEtUsername.text.toString()val password = mEtPassword.text.toString()val confirm = mEtConfirm.text.toString()if (password == confirm && username != "" && password != "" && confirm != "") {

val singleton = AccountSingleton.get(activity?.applicationContext)val account = Account(username, password)singleton.addAccount(account)Toast.makeText(activity?.applicationContext, "New record inserted",

Toast.LENGTH_SHORT).show()} else if (username == "" || password == "" || confirm == "") {

Toast.makeText(activity?.applicationContext, "Missing entry", Toast.LENGTH_SHORT).show()

} else if (password != confirm) {/* Error handling */

} else { /* Error handling */ }}

33

Page 34: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Cloud Persistence

• Cloud data stores useful when app users need to read other users’ written data

• Example: Google’s Firebase– Non-relational data store (high availability)– Realtime Database: persists (key, value) data in a

shared JSON tree– Cloud Firestore: supports more flexible persistence

(document-based approach)– More info: http://firebase.google.com

34

Page 35: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Outline

• Activity Lifecycle• Services• Persistence• Content Providers

35

Page 36: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Sharing Content – Content Providers

• Standard content providers:– Contacts, dictionary, media

• Referred to by URI prefix: content://– Standard providers

• Permission must be requested in manifest:<uses-permission android:name=

"android.permission.READ_CONTACTS"/>

• Android 6+: permission for “dangerous” actions must be requested at runtime (https://developer.android.com/training/permissions/requesting.html )

36

ListView ofuser’s contacts

Page 37: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Content Provider Example: Java (1)// ContentsFragment.java

public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {

private ListView mContactsListView;

private static final String[] PROJECTION = { ContactsContract.Contacts._ID,ContactsContract.Contacts.LOOKUP_KEY, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY };

private final static String[] FROM_COLUMNS = {ContactsContract.Contacts.DISPLAY_NAME_PRIMARY };

@Overridepublic void onActivityCreated(. . .) { // First, call super.onActivityCreated()

Activity activity = getActivity();if (activity != null) {

mContactsListView = activity.findViewById(R.id.contact_list_view);requestContacts(); } }

private void requestContacts() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

if (!hasReadContactPermission()) {requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},

PERMISSION_REQUEST_READ_CONTACTS); }else { showContacts(); } }

else { showContacts(); } }37

Page 38: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Content Provider Example: Java (2)// ContactsFragment.java, continued . . .

private boolean hasReadContactPermission() {Activity activity = getActivity();return activity != null &&

activity.checkSelfPermission(Manifest.permission.READ_CONTACTS) ==PackageManager.PERMISSION_GRANTED; }

@Overridepublic void onRequestPermissionsResult(. . . ) {

if (requestCode == PERMISSION_REQUEST_READ_CONTACTS) {if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { showContacts(); }else { /* Show error message */} }

}

private void showContacts() {

// Gets a CursorAdaptermCursorAdapter = new SimpleCursorAdapter(getActivity(), R.layout.list_item_contact,

null, FROM_COLUMNS, TO_IDS, 0);// Sets the adapter for the ListViewmContactsListView.setAdapter(mCursorAdapter);// Initializes the loader, which loads the contacts asynchronouslygetLoaderManager().initLoader(0, null, this);

}

38

Page 39: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Content Provider Example: Java (3)// ContactsFragment.java, continued . . .

@Overridepublic Loader<Cursor> onCreateLoader(int id, Bundle args) {

return new CursorLoader(getActivity(), ContactsContract.Contacts.CONTENT_URI,PROJECTION, null, null, ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC” );

}

@Overridepublic void onLoadFinished(Loader<Cursor> loader, Cursor data) {

// Put the result Cursor in the adapter for the ListViewmCursorAdapter.swapCursor(data);

}

@Overridepublic void onLoaderReset(Loader<Cursor> loader) { mCursorAdapter.swapCursor(null); }

} // End of Fragment

39

Page 40: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Content Provider Example: Kotlin (1)// ContactsFragment.kt

class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> {private lateinit var mContactsListView: ListViewcompanion object { . . .

private val PROJECTION = arrayOf(ContactsContract.Contacts._ID,

ContactsContract.Contacts.LOOKUP_KEY, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)private val PERMISSION_REQUEST_READ_CONTACTS = 1private val FROM_COLUMNS = arrayOf(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)private val TO_IDS = intArrayOf(R.id.contact_info) }

private lateinit var mCursorAdapter: SimpleCursorAdapter

override fun onActivityCreated(savedInstanceState: Bundle?) {// First, call super...mContactsListView = activity!!.findViewById(R.id.contact_list_view)requestContacts()}

private fun requestContacts() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

if (!hasReadContactPermission()) { requestPermissions(arrayOf(Manifest.permission.READ_CONTACTS), PERMISSION_REQUEST_READ_CONTACTS) }

else { showContacts() }} else { showContacts() }

}40

Page 41: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Content Provider Example: Kotlin (2)// ContactsFragment.kt, continued . . .

private fun hasReadContactPermission(): Boolean { return activity?.checkSelfPermission(Manifest.permission.READ_CONTACTS) ==

PackageManager.PERMISSION_GRANTED }

override fun onRequestPermissionsResult( . . . ) {if (requestCode == PERMISSION_REQUEST_READ_CONTACTS) {

if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {showContacts()}}else { /* Show error message */ }

}

private fun showContacts() {// Gets a CursorAdaptermCursorAdapter = SimpleCursorAdapter(activity, R.layout.list_item_contact,

null, FROM_COLUMNS, TO_IDS, 0)// Sets the adapter for the ListViewmContactsListView.adapter = mCursorAdapter// Initializes the loaderloaderManager.initLoader(0, null, this)

}41

Page 42: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Content Provider Example: Kotlin (3)// ContactsFragment.kt, continued . . .

override fun onCreateLoader(id: Int, args: Bundle): Loader<Cursor> {return CursorLoader(activity, ContactsContract.Contacts.CONTENT_URI,

PROJECTION, null, null, ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC")

}

override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) {// Put the result Cursor in the adapter for the ListViewmCursorAdapter.swapCursor(data)

}

override fun onLoaderReset(loader: Loader<Cursor>) {mCursorAdapter.swapCursor(null)

}

} // End of class definition

42

Page 43: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Even More?!

• Yes!• More widgets, styles and themes• Maps• Email, media, telephony• Sensors

43

Page 44: Android Application Model IIweb.cse.ohio-state.edu/~champion.17/5236/04...SQL database engine in the world” –Lightweight, transactional •Helper class for database creation •Methods

Summary• Activities: “Single screen” of content that user sees– Can be paused, resumed by users– Managing Activity lifecycle is crucial!

• Services: Long-running tasks• Persistence:– Files (internal, external storage)– (Local) SQLite database– Look at https://developer.android.com/guide/topics/

data/data-storage.html for info about Room ORM (easier to use than SQLiteOpenHelper)

• Content Providers: mechanism for sharing data 44