8. 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
12. Android Main/UI Thread
1. Code runs on the main thread (UI thread).
2.Statements are executed in sequence.
13. 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.
14. 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.
41. Loaders
● Loading data asynchronously.
● Coordinating with Activity lifecycle.
● Surviving configuration changes.
● Observing the data source for changes.
42. Loaders - Where?
Available to every Activity.
First introduced in Android 3.0 (Honeycomb, API 11).
Part of the v4 support library (Compatibility Library).
49. 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.
50. Creating a Loader
1. Create class that extends AsyncTaskLoader<String>.
1. Implement loadInBackground().
2. Override deliverResult().
1. Override onStartLoading().
65. LoaderCallbacks<String>
Loader data is ready
onLoadFinished(Loader<String> loader, String data)
Finished Loader. Returned data
Check Loader ID:
loader.getId()
100. 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>());
102. Custom ArrayAdapter
1. Define the data model.
2. Create a custom XML layout.
3. Create UsersAdapter class.
4. Override getView().
5. Tweak for performance
103. User.java
public 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; }
}
104. Custom ArrayAdapter
1. Define the data model.
2. Create a custom XML layout.
3. Create UsersAdapter class.
4. Override getView().
5. Tweak for performance
106. Custom ArrayAdapter
1. Define the data model.
2. Create a custom XML layout.
3. Create UsersAdapter class.
4. Override getView().
5. Tweak for performance
107. UsersAdapter.java
public class UsersAdapter extends ArrayAdapter<User> {
public UsersAdapter(Context context, User[] users) {
// We'll Override getView()
// layout res can be 0.
super(context, 0, users);
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
//todo implement this method
}
108. Custom ArrayAdapter
1. Define the data model.
2. Create a custom XML layout.
3. Create UsersAdapter class.
4. Override getView().
5. Tweak for performance
109. getView()
Called for every AdapterView position.
getView(int position, View convertView, ViewGroup parent)
110. getView()
Called for every AdapterView position.
Convert data into a View.
getView(int position, View convertView, ViewGroup parent)
111. getView()
Called for every AdapterView position.
Convert data into a View.
Reference to current position.
getView(int position, View convertView, ViewGroup parent)
112. 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)
120. Custom ArrayAdapter
1. Define the data model.
2. Create a custom XML layout.
3. Create UsersAdapter class.
4. Override getView().
5. Tweak for performance
132. getView() with ViewHolder
@Override
public 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;
}
135. CursorAdapter
1. Subclass of the abstract BaseAdapter class.
2. Using a Cursor as a data source.
3.getView() is mostly implemented.
136. CursorAdapter source code
public 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;
}
137. CursorAdapter source code
public 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;
}
139. CursorAdapter
public class ContactCursorAdapter extends CursorAdapter {
public ContactCursorAdapter(Context context, Cursor c,
boolean autoRequery) {
super(context, c, autoRequery);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Inflate new view
return LayoutInflater.from(context)
.inflate(R.layout.contacts_adapter_row, parent, false);
}
// ...
}
140. CursorAdapter
@Override
public 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);
}
142. CursorAdapter + ViewHolder
@Override
public 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;
}
143. CursorAdapter + ViewHolder
@Override
public 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);
144. What we didn’t cover today
Multiple layouts
RecyclerView