session #6 loaders and adapters

Post on 13-Jan-2017

92 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Campus-GuestTechiteasy

Loaders and Adapters#6

Android Academy TLV11/12/2016Yossi Segev

Yossi Segev

Crave

Android Academy

Jonathan Yarkoni

Android Developer & Advocate Ironsource

Android Academy Staff

Yonatan LevinGoogle Developer

Expert & Android @ Gett

Britt BarakAndroid Lead

Figure8

Yossi SegevAndroid Developer

Crave

~ 2000 members Largest Android Active Community

What Do We Do?

●Android Fundamentals

●Android UI / UX

●Community Hackathon

●Android Performance

●Mentors Program●Active community

Community Mentors

Betzalel Silver

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

Code. Lots of it.

Part 1:

Loaders

Android Main/UI Thread

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

Android Main/UI Thread

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

2.Statements are executed in sequence.

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.

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.

Use AsyncTask ?

AsyncTask

✓ Performs background operations off the UI thread.

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;}

AsyncTask

✓ Performs background operations off the UI thread.

✓ Returns results on the UI thread.

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); }}

AsyncTask

✓ Performs background operations off the UI thread.

✓ Returns results on the UI thread.

✓ Save time.

AsyncTask = AwesomeBut there’s a problem…

The AsyncTaskExperiment

Experiment

onCreate() execute()

doInBackground()Count to 3

.

.

.

onPostExecute()

Activity AsyncTask

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.

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;}

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

// ...

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

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();}

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

Test #1

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()

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

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

Test #1 results

Test #2

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()

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

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

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

✘ No coordination with Activity lifecycle.

✘ Multiple AsyncTasks.

✘ onPostExecute() has no effect.

Test #2 results

Introducing:Loaders

Loaders

● Loading data asynchronously.

● Coordinating with Activity lifecycle.

● Surviving configuration changes.

● Observing the data source for changes.

Loaders - Where?

Available to every Activity.

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

Part of the v4 support library (Compatibility Library).

so,How Loaders work?

Loader

LoaderDoing background work

● Loading data asynchronously.

● Can monitor the data source.

LoaderCallbacks

LoaderCallBacksNotify on Loader events

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

LoaderManager

● Monitor Activity lifecycle.

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

(Activity lifecycle / direct request)

● Invoke LoaderCallBacks.

LoaderManagerMonitor Activity

Manage Loaders

Notify LoaderCallBacks

How Loaders work

LoaderDoing background work

LoaderCallBacksNotify on Loader events

LoaderManagerMonitor Activity

Manage Loaders

Notify LoaderCallBacks

InvokeNotify

Manag

eCreate

Let’s create a Loader.

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.

Creating a Loader

1. Create class that extends AsyncTaskLoader<String>.

2. Implement loadInBackground().

3. Override deliverResult().

4. Override onStartLoading().

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

Creating a Loader

1. Create class that extends AsyncTaskLoader<String>.

2. Implement loadInBackground().

3. Override deliverResult().

4. Override onStartLoading().

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.";}

Creating a Loader

1. Create class that extends AsyncTaskLoader<String>.

2. Implement loadInBackground().

3. Override deliverResult().

4. Override onStartLoading().

SimpleLoader.javaprivate String mCache;

// ...

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

Creating a Loader

1. Create class that extends AsyncTaskLoader<String>.

2. Implement loadInBackground().

3. Override deliverResult().

4. Override onStartLoading().

SimpleLoader.javaprivate String mCache;

// ...

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

We have a Loader...Now preparing our Activity

Preparing our Activity

1. Implement a LoaderCallbacks<String> interface.

2. Create Loader unique ID.

3. Initialize our Loader.

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}}

LoaderCallbacks

LoaderCallBacksNotify on Loader events

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

LoaderCallbacks<String>

New Loader is neededonCreateLoader(int id, Bundle args)

Loader unique ID

Optional Bundle

MyActivity.java// ...

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

LoaderCallbacks

LoaderCallBacksNotify on Loader events

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

LoaderCallbacks<String>

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

Finished Loader.

Returned data

Check Loader ID:

loader.getId()

MyActivity.java// ...

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

LoaderCallbacks

LoaderCallBacksNotify on Loader events

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

LoaderCallbacks<String>

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

Check Loader ID:

loader.getId()

MyActivity.java// ...

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

Preparing our Activity

1. Implement a LoaderCallbacks<String> interface.

2. Create Loader unique ID.

3. Initialize our Loader.

Create Loader unique ID

Used to identify the Loader by LoaderManager and the Activity.

private static final int SIMPLE_LOADER_ID =

100;

Preparing our Activity

1. Implement a LoaderCallbacks<String> interface.

2. Create Loader unique ID.

3. Initialize our Loader.

Init Loader

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

Init Loader

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

Getting a reference to the Activity LoaderManager

Init Loader

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

Instruct LoaderManager to initialize the Loader

Init Loader

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

Unique Loader ID to init

Init Loader

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

Optional BundleCan be used for Loader creation

Init Loader

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

Interface to report on Loader state changes

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);}}

initLoader()

LoaderManager

initLoader(LOADER_ID, args, LoaderCallbacks);

Do I know

this ID?

No.

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

Yes.

Init new Loader

LoaderManager

Init new Loader

LoaderManager

onCreateLoader(int id, Bundle args)

Init new Loader

LoaderManageronStartLoading()

loadInBackground()

deliverResult(D data)

Init new Loader

LoaderManager

onLoadFinished(Loader<D> loader, D data)

initLoader()

LoaderManager

initLoader(LOADER_ID, args, LoaderCallbacks);

Do I know

this ID?

No.

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

Yes.

Use existing Loader

deliverResult(D data)

Loader state ?

onLoadFinished(Loader<D> loader, D data)

Remember

● initLoader() - when ready to receive data.

● Need fresh data? Call restartLoader().

Loader vs AsyncTask

Loader vs AsyncTask

Let’s talk about the CursorLoader

CursorLoader

Subclass of AsyncTaskLoader<Cursor>.

Queries ContentProviders.

Monitor data changes using ContentObserver.

Returns a Cursor.

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

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

}

CursorLoader #2

// …

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

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}

Questions ?

Part 2:

Adapters

Adapter

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

Has access to the data items.

Building a View for each item.

Adapter

Data set

ListView (AdapterView)

Adapter

Position Position

Data View

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

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>());

Building a custom ArrayAdapter

Custom ArrayAdapter

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

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; }}

Custom ArrayAdapter

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

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>

Custom ArrayAdapter

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

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

}

}

Custom ArrayAdapter

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

getView()

Called for every AdapterView position.

getView(int position, View convertView, ViewGroup parent)

getView()

Called for every AdapterView position.

Convert data into a View.

getView(int position, View convertView, ViewGroup parent)

getView()

Called for every AdapterView position.

Convert data into a View.

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

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)

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

}

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

User user = getItem(position);

}

Get data object by position

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)

View recycling

getView(int position, View convertView, ViewGroup parent)

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

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

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

Custom ArrayAdapter

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

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;}

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;}

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;}

ViewHolder

Hold references to the Views

Skip findViewById()

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

}

ViewHolder

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

ViewHolderViewHolder vh;

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

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);

}

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);

}

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(); }

ViewHolder// ...

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

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;}

Questions ?

CursorAdapter

CursorAdapter

1. Subclass of the abstract BaseAdapter class.

2. Using a Cursor as a data source.

3.getView() is mostly implemented.

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;}

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;}

CursorAdapter

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

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

View.

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);}

// ...}

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);}

CursorAdapter + ViewHolder

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;}

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);

}

What we didn’t cover today

Multiple layoutsRecyclerView

Questions ?

Thank you

top related