session #6 loaders and adapters

146
Campus-Guest Techiteasy

Upload: vitali-pekelis

Post on 13-Jan-2017

92 views

Category:

Software


2 download

TRANSCRIPT

Page 1: Session #6  loaders and adapters

Campus-GuestTechiteasy

Page 2: Session #6  loaders and adapters

Loaders and Adapters#6

Android Academy TLV11/12/2016Yossi Segev

Page 3: Session #6  loaders and adapters

Yossi Segev

Crave

Android Academy

Page 4: Session #6  loaders and adapters

Jonathan Yarkoni

Android Developer & Advocate Ironsource

Android Academy Staff

Yonatan LevinGoogle Developer

Expert & Android @ Gett

Britt BarakAndroid Lead

Figure8

Yossi SegevAndroid Developer

Crave

Page 5: Session #6  loaders and adapters

~ 2000 members Largest Android Active Community

Page 6: Session #6  loaders and adapters

What Do We Do?

●Android Fundamentals

●Android UI / UX

●Community Hackathon

●Android Performance

●Mentors Program●Active community

Page 7: Session #6  loaders and adapters

Community Mentors

Betzalel Silver

Page 8: Session #6  loaders and adapters

Today’s agenda

● Part 1: Loaders○ What are they? ○ Why do we need them? ○ How do we use them?

● Part 2: Adapters○ View recycling○ ViewHolder○ ArrayAdapter○ CursorAdapter

Page 9: Session #6  loaders and adapters

Code. Lots of it.

Page 10: Session #6  loaders and adapters

Part 1:

Loaders

Page 11: Session #6  loaders and adapters

Android Main/UI Thread

1.Code runs on the main thread (UI thread).

Page 12: Session #6  loaders and adapters

Android Main/UI Thread

1. Code runs on the main thread (UI thread).

2.Statements are executed in sequence.

Page 13: Session #6  loaders and adapters

Android Main/UI Thread

1. Code runs on the main thread (UI thread).

2. Statements are executed in sequence.

3.Long operation will block the UI thread.

Page 14: Session #6  loaders and adapters

Android Main/UI Thread

1. Code runs on the main thread (UI thread).

2. Statements are executed in sequence.

3. Long operation will block the UI thread.

4.Perform long operation off the UI thread.

Page 15: Session #6  loaders and adapters

Use AsyncTask ?

Page 16: Session #6  loaders and adapters

AsyncTask

✓ Performs background operations off the UI thread.

Page 17: Session #6  loaders and adapters

doInBackground()@Overrideprotected String doInBackground(String... params) { // This code is running on a background thread. if (!TextUtils.isEmpty(params[0])) { return "Hello AsyncTask " + params[0]; } return null;}

Page 18: Session #6  loaders and adapters

AsyncTask

✓ Performs background operations off the UI thread.

✓ Returns results on the UI thread.

Page 19: Session #6  loaders and adapters

onPostExecute()@Overrideprotected void onPostExecute(String result) { super.onPostExecute(result); // We're back on the UI thread so we can update the UI from here. if (!TextUtils.isEmpty(result)) { mTextView.setText(result); }}

Page 20: Session #6  loaders and adapters

AsyncTask

✓ Performs background operations off the UI thread.

✓ Returns results on the UI thread.

✓ Save time.

Page 21: Session #6  loaders and adapters

AsyncTask = AwesomeBut there’s a problem…

Page 22: Session #6  loaders and adapters

The AsyncTaskExperiment

Page 23: Session #6  loaders and adapters

Experiment

onCreate() execute()

doInBackground()Count to 3

.

.

.

onPostExecute()

Activity AsyncTask

Page 24: Session #6  loaders and adapters

Experiment - Loggerpublic class Logger {

public static void logWithThread(String tag, String message) { Log.d(tag, "T:" + Thread.currentThread().getId() + " | " + message); }}

D/LogTag: T:1 | The log message.

Page 25: Session #6  loaders and adapters

Experiment - AsyncTask@Overrideprotected Void doInBackground(Void... params) { for (int i = 1 ; i < 4 ; i ++) { Logger.logWithThread(TAG, "doInBackground: " + i); try { Thread.sleep(1000); // Simulates long operation } catch (InterruptedException e) { e.printStackTrace(); } } return null;}

Page 26: Session #6  loaders and adapters

Experiment - AsyncTaskpublic SimpleAsyncTask() { Logger.logWithThread(TAG, "SimpleAsyncTask created.");}

// ...

@Overrideprotected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); Logger.logWithThread(TAG, "onPostExecute()");}

Page 27: Session #6  loaders and adapters

Experiment - Activity@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Logger.logWithThread(TAG, "onCreate()"); setContentView(R.layout.activity_async_task);

// Creating a new AsyncTask SimpleAsyncTask simpleAsyncTask = new SimpleAsyncTask(); simpleAsyncTask.execute();}

Page 28: Session #6  loaders and adapters

Experiment - Activity@Overrideprotected void onDestroy() { super.onDestroy(); Logger.logWithThread(TAG, "onDestroy()");}

Page 29: Session #6  loaders and adapters

Test #1

Page 30: Session #6  loaders and adapters

Test log #1

D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:132 | doInBackground: 1D/AsyncTask: T:132 | doInBackground: 2D/AsyncTask: T:132 | doInBackground: 3D/AsyncTask: T:1 | onPostExecute()

Page 31: Session #6  loaders and adapters

Test log #1

D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:132 | doInBackground: 1D/AsyncTask: T:132 | doInBackground: 2D/AsyncTask: T:132 | doInBackground: 3D/AsyncTask: T:1 | onPostExecute()

Activity lifecycle

Page 32: Session #6  loaders and adapters

Test log #1

D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:132 | doInBackground: 1D/AsyncTask: T:132 | doInBackground: 2D/AsyncTask: T:132 | doInBackground: 3D/AsyncTask: T:1 | onPostExecute()

Activity lifecycle

AsyncTask

Page 33: Session #6  loaders and adapters

Test #1 results

Page 34: Session #6  loaders and adapters

Test #2

Page 35: Session #6  loaders and adapters

Test log #2D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:136 | doInBackground: 1D/AsyncTask: T:136 | doInBackground: 2D/Activity: T:1 | onDestroy()D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:136 | doInBackground: 3D/AsyncTask: T:137 | doInBackground: 1D/AsyncTask: T:1 | onPostExecute()D/AsyncTask: T:137 | doInBackground: 2D/AsyncTask: T:137 | doInBackground: 3D/AsyncTask: T:1 | onPostExecute()

Page 36: Session #6  loaders and adapters

Test log #2D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:136 | doInBackground: 1D/AsyncTask: T:136 | doInBackground: 2D/Activity: T:1 | onDestroy()D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:136 | doInBackground: 3D/AsyncTask: T:137 | doInBackground: 1D/AsyncTask: T:1 | onPostExecute()D/AsyncTask: T:137 | doInBackground: 2D/AsyncTask: T:137 | doInBackground: 3D/AsyncTask: T:1 | onPostExecute()

Activity lifecycle

AsyncTask

Page 37: Session #6  loaders and adapters

Test log #2D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:136 | doInBackground: 1D/AsyncTask: T:136 | doInBackground: 2D/Activity: T:1 | onDestroy()D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:136 | doInBackground: 3D/AsyncTask: T:137 | doInBackground: 1D/AsyncTask: T:1 | onPostExecute()D/AsyncTask: T:137 | doInBackground: 2D/AsyncTask: T:137 | doInBackground: 3D/AsyncTask: T:1 | onPostExecute()

Activity lifecycle

AsyncTask

Page 38: Session #6  loaders and adapters

Test log #2D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:136 | doInBackground: 1D/AsyncTask: T:136 | doInBackground: 2D/Activity: T:1 | onDestroy()D/Activity: T:1 | onCreate()D/AsyncTask: T:1 | SimpleAsyncTask created.D/AsyncTask: T:136 | doInBackground: 3D/AsyncTask: T:137 | doInBackground: 1D/AsyncTask: T:1 | onPostExecute()D/AsyncTask: T:137 | doInBackground: 2D/AsyncTask: T:137 | doInBackground: 3D/AsyncTask: T:1 | onPostExecute()

Activity lifecycle

AsyncTask

AsyncTask #2

Page 39: Session #6  loaders and adapters

✘ No coordination with Activity lifecycle.

✘ Multiple AsyncTasks.

✘ onPostExecute() has no effect.

Test #2 results

Page 40: Session #6  loaders and adapters

Introducing:Loaders

Page 41: Session #6  loaders and adapters

Loaders

● Loading data asynchronously.

● Coordinating with Activity lifecycle.

● Surviving configuration changes.

● Observing the data source for changes.

Page 42: Session #6  loaders and adapters

Loaders - Where?

Available to every Activity.

First introduced in Android 3.0 (Honeycomb, API 11).

Part of the v4 support library (Compatibility Library).

Page 43: Session #6  loaders and adapters

so,How Loaders work?

Page 44: Session #6  loaders and adapters

Loader

LoaderDoing background work

● Loading data asynchronously.

● Can monitor the data source.

Page 45: Session #6  loaders and adapters

LoaderCallbacks

LoaderCallBacksNotify on Loader events

Events:● New Loader is needed.● Data is ready.● Loader is about to reset.

Page 46: Session #6  loaders and adapters

LoaderManager

● Monitor Activity lifecycle.

● Manage Loaders:➢ Start / Stop / Reset / Retrain

(Activity lifecycle / direct request)

● Invoke LoaderCallBacks.

LoaderManagerMonitor Activity

Manage Loaders

Notify LoaderCallBacks

Page 47: Session #6  loaders and adapters

How Loaders work

LoaderDoing background work

LoaderCallBacksNotify on Loader events

LoaderManagerMonitor Activity

Manage Loaders

Notify LoaderCallBacks

InvokeNotify

Manag

eCreate

Page 48: Session #6  loaders and adapters

Let’s create a Loader.

Page 49: Session #6  loaders and adapters

Creating a Loader

Loader<D>The base class of all Loaders.

AsyncTaskLoader<D>Subclass of Loader<D>, uses AsyncTask to do its

work in the background.

CursorLoader<D>Subclass of AsyncTaskLoader<Cursor>, built to query ContentProviders and monitor their data.

Page 50: Session #6  loaders and adapters

Creating a Loader

1. Create class that extends AsyncTaskLoader<String>.

2. Implement loadInBackground().

3. Override deliverResult().

4. Override onStartLoading().

Page 51: Session #6  loaders and adapters

SimpleLoader.javapublic class SimpleLoader extends AsyncTaskLoader<String> { public SimpleLoader(Context context) { super(context); }}

Page 52: Session #6  loaders and adapters

Creating a Loader

1. Create class that extends AsyncTaskLoader<String>.

2. Implement loadInBackground().

3. Override deliverResult().

4. Override onStartLoading().

Page 53: Session #6  loaders and adapters

SimpleLoader.java@Overridepublic String loadInBackground() {

// Simulate long operation try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); }

// Return data return "I'm a data string.";}

Page 54: Session #6  loaders and adapters

Creating a Loader

1. Create class that extends AsyncTaskLoader<String>.

2. Implement loadInBackground().

3. Override deliverResult().

4. Override onStartLoading().

Page 55: Session #6  loaders and adapters

SimpleLoader.javaprivate String mCache;

// ...

@Overridepublic void deliverResult(String data) { mCache = data; super.deliverResult(data);}

Page 56: Session #6  loaders and adapters

Creating a Loader

1. Create class that extends AsyncTaskLoader<String>.

2. Implement loadInBackground().

3. Override deliverResult().

4. Override onStartLoading().

Page 57: Session #6  loaders and adapters

SimpleLoader.javaprivate String mCache;

// ...

@Overrideprotected void onStartLoading() { super.onStartLoading(); if (TextUtils.isEmpty(mCache)) { forceLoad(); } else { deliverResult(mCache); }}

Page 58: Session #6  loaders and adapters

We have a Loader...Now preparing our Activity

Page 59: Session #6  loaders and adapters

Preparing our Activity

1. Implement a LoaderCallbacks<String> interface.

2. Create Loader unique ID.

3. Initialize our Loader.

Page 60: Session #6  loaders and adapters

MyActivity.javapublic class MyActivity extends Activity implements LoaderManager.LoaderCallbacks<String> {

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_myactivity); mTextView = (TextView) findViewById(R.id.text_view); mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);

showLoadingIndicator(); //todo init loader}}

Page 61: Session #6  loaders and adapters

LoaderCallbacks

LoaderCallBacksNotify on Loader events

Events:● New Loader is needed.● Loader data is ready.● Loader is about to reset.

Page 62: Session #6  loaders and adapters

LoaderCallbacks<String>

New Loader is neededonCreateLoader(int id, Bundle args)

Loader unique ID

Optional Bundle

Page 63: Session #6  loaders and adapters

MyActivity.java// ...

@Overridepublic Loader<String> onCreateLoader(int id, Bundle args) { return new SimpleLoader(this);}

Page 64: Session #6  loaders and adapters

LoaderCallbacks

LoaderCallBacksNotify on Loader events

Events:● New Loader is needed.● Loader data is ready.● Loader is about to reset.

Page 65: Session #6  loaders and adapters

LoaderCallbacks<String>

Loader data is readyonLoadFinished(Loader<String> loader, String data)

Finished Loader.

Returned data

Check Loader ID:

loader.getId()

Page 66: Session #6  loaders and adapters

MyActivity.java// ...

@Overridepublic void onLoadFinished(Loader<String> loader, String data) { if (!TextUtils.isEmpty(data)) { showData(data); }}

Page 67: Session #6  loaders and adapters

LoaderCallbacks

LoaderCallBacksNotify on Loader events

Events:● New Loader is needed.● Loader data is ready.● Loader is about to reset.

Page 68: Session #6  loaders and adapters

LoaderCallbacks<String>

Loader is about to resetonLoaderReset(Loader<String> loader)

Check Loader ID:

loader.getId()

Page 69: Session #6  loaders and adapters

MyActivity.java// ...

@Overridepublic void onLoaderReset(Loader<String> loader) { // Our chance to clear data, reset UI etc...}

Page 70: Session #6  loaders and adapters

Preparing our Activity

1. Implement a LoaderCallbacks<String> interface.

2. Create Loader unique ID.

3. Initialize our Loader.

Page 71: Session #6  loaders and adapters

Create Loader unique ID

Used to identify the Loader by LoaderManager and the Activity.

private static final int SIMPLE_LOADER_ID =

100;

Page 72: Session #6  loaders and adapters

Preparing our Activity

1. Implement a LoaderCallbacks<String> interface.

2. Create Loader unique ID.

3. Initialize our Loader.

Page 73: Session #6  loaders and adapters

Init Loader

getLoaderManager().initLoader(LOADER_ID, args, LoaderCallbacks);

Page 74: Session #6  loaders and adapters

Init Loader

getLoaderManager().initLoader(LOADER_ID, args, LoaderCallbacks);

Getting a reference to the Activity LoaderManager

Page 75: Session #6  loaders and adapters

Init Loader

getLoaderManager().initLoader(LOADER_ID, args, LoaderCallbacks);

Instruct LoaderManager to initialize the Loader

Page 76: Session #6  loaders and adapters

Init Loader

getLoaderManager().initLoader(LOADER_ID, args, LoaderCallbacks);

Unique Loader ID to init

Page 77: Session #6  loaders and adapters

Init Loader

getLoaderManager().initLoader(LOADER_ID, args, LoaderCallbacks);

Optional BundleCan be used for Loader creation

Page 78: Session #6  loaders and adapters

Init Loader

getLoaderManager().initLoader(LOADER_ID, args, LoaderCallbacks);

Interface to report on Loader state changes

Page 79: Session #6  loaders and adapters

MyActivity.javapublic class MyActivity extends Activity implements LoaderManager.LoaderCallbacks<String> {

private static final int SIMPLE_LOADER_ID = 100;

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_myactivity); mTextView = (TextView) findViewById(R.id.text_view); mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);

showLoadingIndicator(); getLoaderManager().initLoader(SIMPLE_LOADER_ID, null, this);}}

Page 80: Session #6  loaders and adapters

initLoader()

LoaderManager

initLoader(LOADER_ID, args, LoaderCallbacks);

Do I know

this ID?

No.

onCreateLoader(int id, Bundle args) Use the existing Loader

Yes.

Page 81: Session #6  loaders and adapters

Init new Loader

LoaderManager

Page 82: Session #6  loaders and adapters

Init new Loader

LoaderManager

onCreateLoader(int id, Bundle args)

Page 83: Session #6  loaders and adapters

Init new Loader

LoaderManageronStartLoading()

loadInBackground()

deliverResult(D data)

Page 84: Session #6  loaders and adapters

Init new Loader

LoaderManager

onLoadFinished(Loader<D> loader, D data)

Page 85: Session #6  loaders and adapters

initLoader()

LoaderManager

initLoader(LOADER_ID, args, LoaderCallbacks);

Do I know

this ID?

No.

onCreateLoader(int id, Bundle args) Use the existing Loader

Yes.

Page 86: Session #6  loaders and adapters

Use existing Loader

deliverResult(D data)

Loader state ?

onLoadFinished(Loader<D> loader, D data)

Page 87: Session #6  loaders and adapters

Remember

● initLoader() - when ready to receive data.

● Need fresh data? Call restartLoader().

Page 88: Session #6  loaders and adapters

Loader vs AsyncTask

Page 89: Session #6  loaders and adapters

Loader vs AsyncTask

Page 90: Session #6  loaders and adapters

Let’s talk about the CursorLoader

Page 91: Session #6  loaders and adapters

CursorLoader

Subclass of AsyncTaskLoader<Cursor>.

Queries ContentProviders.

Monitor data changes using ContentObserver.

Returns a Cursor.

Page 92: Session #6  loaders and adapters

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

CursorLoader loader = new CursorLoader(this);loader.setUri(ContactsContract.Contacts.CONTENT_URI);return loader;

}

Page 93: Session #6  loaders and adapters

CursorLoader #2

// …

Bundle args = new Bundle();args.putString(ARGS_SEARCH_QUERY, “Yossi”);getLoaderManager().initLoader(CONTACTS_LOADER_ID, args, this);

Page 94: Session #6  loaders and adapters

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

String searchQuery = args.getString(ARGS_SEARCH_QUERY); String selection = ContactsContract.Contacts.DISPLAY_NAME + " = ?"; String[] selectionArgs = { searchQuery };

return new CursorLoader( this, // Context ContactsContract.Contacts.CONTENT_URI, // Table null, // Projections selection, // Selection selectionArgs, // Selection args null); // Sort order}

Page 95: Session #6  loaders and adapters

Questions ?

Page 96: Session #6  loaders and adapters

Part 2:

Adapters

Page 97: Session #6  loaders and adapters

Adapter

A “bridge” between an AdapterView and it’s underlying data.

Has access to the data items.

Building a View for each item.

Page 98: Session #6  loaders and adapters

Adapter

Data set

ListView (AdapterView)

Adapter

Position Position

Data View

Page 99: Session #6  loaders and adapters

Adapter

Adapter interface

BaseAdapterBase class of common implementation

for an Adapter

ArrayAdapter<T>Uses array as a data source

CursorAdapterUses Cursor as a data source

Page 100: Session #6  loaders and adapters

Sunshine app ArrayAdapter// The ArrayAdapter will take data from a source and// use it to populate the ListView it's attached to.mForecastAdapter = new ArrayAdapter<String>( getActivity(), // The current context (this activity) R.layout.list_item_forecast, // The name of the layout ID. R.id.list_item_forecast_textview, // The ID of the textview to populate. new ArrayList<String>());

Page 101: Session #6  loaders and adapters

Building a custom ArrayAdapter

Page 102: Session #6  loaders and adapters

Custom ArrayAdapter

1. Define the data model.2. Create a custom XML layout.3. Create UsersAdapter class.4. Override getView().5. Tweak for performance

Page 103: Session #6  loaders and adapters

User.javapublic class User {

private String mFullName; private String mPhoneNumber;

public User(String fullName, String phoneNumber) { mFullName = fullName; mPhoneNumber = phoneNumber; }

public String getFullName() { return mFullName; }

public String getPhoneNumber() { return mPhoneNumber; }}

Page 104: Session #6  loaders and adapters

Custom ArrayAdapter

1. Define the data model.2. Create a custom XML layout.3. Create UsersAdapter class.4. Override getView().5. Tweak for performance

Page 105: Session #6  loaders and adapters

XML layout<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

<TextView android:id="@+id/users_adapter_row_fullname" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20sp" tools:text="Full Name"/>

<TextView android:id="@+id/users_adapter_row_phone" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="16sp" tools:text="123-4567"/></LinearLayout>

Page 106: Session #6  loaders and adapters

Custom ArrayAdapter

1. Define the data model.2. Create a custom XML layout.3. Create UsersAdapter class.4. Override getView().5. Tweak for performance

Page 107: Session #6  loaders and adapters

UsersAdapter.javapublic class UsersAdapter extends ArrayAdapter<User> {

public UsersAdapter(Context context, User[] users) { // We'll Override getView() // layout res can be 0. super(context, 0, users);}

@Overridepublic View getView(int position, View convertView,

ViewGroup parent) {//todo implement this method

}

}

Page 108: Session #6  loaders and adapters

Custom ArrayAdapter

1. Define the data model.2. Create a custom XML layout.3. Create UsersAdapter class.4. Override getView().5. Tweak for performance

Page 109: Session #6  loaders and adapters

getView()

Called for every AdapterView position.

getView(int position, View convertView, ViewGroup parent)

Page 110: Session #6  loaders and adapters

getView()

Called for every AdapterView position.

Convert data into a View.

getView(int position, View convertView, ViewGroup parent)

Page 111: Session #6  loaders and adapters

getView()

Called for every AdapterView position.

Convert data into a View.

Reference to current position.getView(int position, View convertView, ViewGroup parent)

Page 112: Session #6  loaders and adapters

getView()

Called for every AdapterView position.

Convert data into a View.

Reference to current position.

Has access to recycled views.getView(int position, View convertView, ViewGroup parent)

Page 113: Session #6  loaders and adapters

getView()@Overridepublic View getView(int position, View convertView, ViewGroup parent) {

}

Page 114: Session #6  loaders and adapters

getView()@Overridepublic View getView(int position, View convertView, ViewGroup parent) {

User user = getItem(position);

}

Get data object by position

Page 115: Session #6  loaders and adapters

getView()@Overridepublic View getView(int position, View convertView, ViewGroup parent) {

User user = getItem(position);

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false); }

}

Inflate XML (only if needed)

Page 116: Session #6  loaders and adapters

View recycling

getView(int position, View convertView, ViewGroup parent)

Page 117: Session #6  loaders and adapters

getView()@Overridepublic View getView(int position, View convertView, ViewGroup parent) {

User user = getItem(position);

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false); }

TextView fullName = (TextView) convertView.findViewById(R.id.users_adapter_row_fullname); TextView phoneNumber = (TextView) convertView.findViewById(R.id.users_adapter_row_phone);

}

Reference layout Views

Page 118: Session #6  loaders and adapters

getView()@Overridepublic View getView(int position, View convertView, ViewGroup parent) {

User user = getItem(position);

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false); }

TextView fullName = (TextView) convertView.findViewById(R.id.users_adapter_row_fullname); TextView phoneNumber = (TextView) convertView.findViewById(R.id.users_adapter_row_phone);

fullName.setText(user.getFullName()); phoneNumber.setText(user.getPhoneNumber());

}

Bind data to Views

Page 119: Session #6  loaders and adapters

getView()@Overridepublic View getView(int position, View convertView, ViewGroup parent) {

User user = getItem(position);

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false); }

TextView fullName = (TextView) convertView.findViewById(R.id.users_adapter_row_fullname); TextView phoneNumber = (TextView) convertView.findViewById(R.id.users_adapter_row_phone);

fullName.setText(user.getFullName()); phoneNumber.setText(user.getPhoneNumber());

return convertView;}

Return View

Page 120: Session #6  loaders and adapters

Custom ArrayAdapter

1. Define the data model.2. Create a custom XML layout.3. Create UsersAdapter class.4. Override getView().5. Tweak for performance

Page 121: Session #6  loaders and adapters

getView()@Overridepublic View getView(int position, View convertView, ViewGroup parent) {

User user = getItem(position);

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false); }

TextView fullName = (TextView) convertView.findViewById(R.id.users_adapter_row_fullname); TextView phoneNumber = (TextView) convertView.findViewById(R.id.users_adapter_row_phone);

fullName.setText(user.getFullName()); phoneNumber.setText(user.getPhoneNumber());

return convertView;}

Page 122: Session #6  loaders and adapters

getView()@Overridepublic View getView(int position, View convertView, ViewGroup parent) {

User user = getItem(position);

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false); }

TextView fullName = (TextView) convertView.findViewById(R.id.users_adapter_row_fullname); TextView phoneNumber = (TextView) convertView.findViewById(R.id.users_adapter_row_phone);

fullName.setText(user.getFullName()); phoneNumber.setText(user.getPhoneNumber());

return convertView;}

Page 123: Session #6  loaders and adapters

getView()@Overridepublic View getView(int position, View convertView, ViewGroup parent) {

User user = getItem(position);

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false); }

TextView fullName = (TextView) convertView.findViewById(R.id.users_adapter_row_fullname); TextView phoneNumber = (TextView) convertView.findViewById(R.id.users_adapter_row_phone);

fullName.setText(user.getFullName()); phoneNumber.setText(user.getPhoneNumber());

return convertView;}

Page 124: Session #6  loaders and adapters

ViewHolder

Hold references to the Views

Skip findViewById()

Page 125: Session #6  loaders and adapters

ViewHolderpublic class UsersAdapter extends ArrayAdapter<User> { // ... private static class ViewHolder { TextView fullName; TextView phoneNumber; }

}

Page 126: Session #6  loaders and adapters

ViewHolder

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false);}

Page 127: Session #6  loaders and adapters

ViewHolderViewHolder vh;

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false);}

Page 128: Session #6  loaders and adapters

ViewHolderViewHolder vh;

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false);

vh = new ViewHolder(); vh.fullName = (TextView) convertView.findViewById(R.id.users_adapter_row_fullname); vh.phoneNumber = (TextView) convertView.findViewById(R.id.users_adapter_row_phone);

}

Page 129: Session #6  loaders and adapters

ViewHolderViewHolder vh;

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false);

vh = new ViewHolder(); vh.fullName = (TextView) convertView.findViewById(R.id.users_adapter_row_fullname); vh.phoneNumber = (TextView) convertView.findViewById(R.id.users_adapter_row_phone); convertView.setTag(vh);

}

Page 130: Session #6  loaders and adapters

ViewHolderViewHolder vh;

if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false);

vh = new ViewHolder(); vh.fullName = (TextView) convertView.findViewById(R.id.users_adapter_row_fullname); vh.phoneNumber = (TextView) convertView.findViewById(R.id.users_adapter_row_phone); convertView.setTag(vh);

} else { vh = (ViewHolder) convertView.getTag(); }

Page 131: Session #6  loaders and adapters

ViewHolder// ...

vh.fullName.setText(user.getFullName());vh.phoneNumber.setText(user.getPhoneNumber());

Page 132: Session #6  loaders and adapters

getView() with ViewHolder@Overridepublic View getView(int position, View convertView, ViewGroup parent) { User user = getItem(position); ViewHolder vh; if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(R.layout.users_adapter_row, parent, false);

vh = new ViewHolder(); // Create a new ViewHolder vh.fullName = (TextView) convertView.findViewById(R.id.users_adapter_row_fullname); vh.phoneNumber = (TextView) convertView.findViewById(R.id.users_adapter_row_phone); convertView.setTag(vh); // Store it as a tag } else { vh = (ViewHolder) convertView.getTag(); // use the ViewHolder } vh.fullName.setText(user.getFullName()); vh.phoneNumber.setText(user.getPhoneNumber()); return convertView;}

Page 133: Session #6  loaders and adapters

Questions ?

Page 134: Session #6  loaders and adapters

CursorAdapter

Page 135: Session #6  loaders and adapters

CursorAdapter

1. Subclass of the abstract BaseAdapter class.

2. Using a Cursor as a data source.

3.getView() is mostly implemented.

Page 136: Session #6  loaders and adapters

CursorAdapter source codepublic View getView(int position, View convertView, ViewGroup parent) { if (!mDataValid) { throw new IllegalStateException("this should only be called when the cursor is valid"); } if (!mCursor.moveToPosition(position)) { throw new IllegalStateException("couldn't move cursor to position " + position); } View v; if (convertView == null) { v = newView(mContext, mCursor, parent); } else { v = convertView; } bindView(v, mContext, mCursor); return v;}

Page 137: Session #6  loaders and adapters

CursorAdapter source codepublic View getView(int position, View convertView, ViewGroup parent) { if (!mDataValid) { throw new IllegalStateException("this should only be called when the cursor is valid"); } if (!mCursor.moveToPosition(position)) { throw new IllegalStateException("couldn't move cursor to position " + position); } View v; if (convertView == null) { v = newView(mContext, mCursor, parent); } else { v = convertView; } bindView(v, mContext, mCursor); return v;}

Page 138: Session #6  loaders and adapters

CursorAdapter

1.newView():Used to inflate a new view and return it.

2.bindView():Get Cursor Extract data Bind data to

View.

Page 139: Session #6  loaders and adapters

CursorAdapterpublic class ContactCursorAdapter extends CursorAdapter {

public ContactCursorAdapter(Context context, Cursor c, boolean autoRequery) {

super(context, c, autoRequery);}

@Overridepublic View newView(Context context, Cursor cursor, ViewGroup parent) { // Inflate new view return LayoutInflater.from(context)

.inflate(R.layout.contacts_adapter_row, parent, false);}

// ...}

Page 140: Session #6  loaders and adapters

CursorAdapter@Overridepublic void bindView(View view, Context context, Cursor cursor) {

int idx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); TextView displayName =

(TextView) view.findViewById(R.id.contacts_adapter_row_displayName);

// Get cursor + extract data String name = cursor.getString(idx);

// Bind data to the view displayName.setText(name);}

Page 141: Session #6  loaders and adapters

CursorAdapter + ViewHolder

Page 142: Session #6  loaders and adapters

CursorAdapter + ViewHolder@Overridepublic View newView(Context context, Cursor cursor, ViewGroup parent) {

// Inflate new view View view = LayoutInflater.from(context)

.inflate(R.layout.contacts_adapter_row, parent, false);

// Create a new view holder ViewHolder vh = new ViewHolder(); vh.displayName = (TextView)

view.findViewById(R.id.contacts_adapter_row_displayName);

// Save as tag view.setTag(vh); return view;}

Page 143: Session #6  loaders and adapters

CursorAdapter + ViewHolder@Overridepublic void bindView(View view, Context context, Cursor cursor) {

int idx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);

// Get the view holder from the view tag ViewHolder vh = (ViewHolder) view.getTag();

// Get cursor + extract data String name = cursor.getString(idx);

// Bind data to the view vh.displayName.setText(name);

}

Page 144: Session #6  loaders and adapters

What we didn’t cover today

Multiple layoutsRecyclerView

Page 145: Session #6  loaders and adapters

Questions ?

Page 146: Session #6  loaders and adapters

Thank you