Week 8 PDF
Week 8 PDF
Week 8
0
Binding List Items (CrimeListFragment.java)
private class CrimeHolder extends RecyclerView.ViewHolder {
private TextView mTitleTextView;
private TextView mDateTextView;
mTitleTextView = (TextView)
itemView.findViewById(R.id.crime_title);
mDateTextView = (TextView)
itemView.findViewById(R.id.crime_date);
}
}
mCrime = crime;
mTitleTextView.setText(mCrime.getTitle());
mDateTextView.setText(mCrime.getDate().toString());
}
}
Mobile Application
Development
Responding to Presses
private class CrimeHolder extends RecyclerView.ViewHolder
implements View.OnClickListener { ...
public CrimeHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(R.layout.list_item_crime, parent, false));
itemView.setOnClickListener(this);
...
}
...
@Override
public void onClick(View view) {
Toast.makeText(getActivity(),
mCrime.getTitle() + " clicked!",
Toast.LENGTH_SHORT)
.show();
}
}
Instead, you can handle them like you normally do: by
setting an OnClickListener. Since each View has an
Mobile Application associated ViewHolder, you can make your
Development ViewHolder the OnClickListener for its View.
Modify the CrimeHolder to handle presses for the
entire row.
Setting up the singleton (CrimeLab.java)
Mobile Application
Development
Starting an Activity from a Fragment
Starting CrimeActivity (CrimeListFragment.java)
private class CrimeHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
...
@Override
public void onClick(View view) {
Toast.makeText(getActivity(),
mCrime.getTitle() + " clicked!", Toast.LENGTH_SHORT)
.show();
Intent intent = new Intent(getActivity(), CrimeActivity.class);
startActivity(intent);
}
}
Mobile Application
Development
Putting an extra
Creating a newIntent method(CrimeActivity.java)
Mobile Application
Development
Retrieving an extra
• The crime ID is now safely stashed in the intent that belongs to CrimeActivity.
• However, it is the CrimeFragment class that needs to retrieve and use that data.
• There are two ways a fragment can access data in its activity’s intent:
• In the shortcut, CrimeFragment will simply use the getActivity() method to access the
CrimeActivity’s intent directly.
Mobile Application
Development
Retrieving the extra and fetching the Crime(CrimeFragment.java)
Mobile Application
Development
Updating Crime Fragment’s view with Crime data
Updating view objects
(CrimeFragment.java)
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
mTitleField = (EditText)v.findViewById(R.id.crime_title);
mTitleField.setText(mCrime.getTitle());
mTitleField.addTextChangedListener(new TextWatcher() {
...
});
...
mSolvedCheckBox = (CheckBox)v.findViewById(R.id.crime_solved);
mSolvedCheckBox.setChecked(mCrime.isSolved());
mSolvedCheckBox.setOnCheckedChangeListener(new
OnCheckedChangeListener() {
...
});
...
return v;
}
Mobile Application
Development
The downside to direct retrieval
• Having the fragment access the intent that belongs to the hosting activity
makes for simple code.
• The CrimeFragment could then retrieve this data without relying on the
presence of a particular extra in the activity’s intent.
Mobile Application
Development
Fragment Arguments
• This bundle contains key-value pairs that work just like the intent extras of an
Activity.
Mobile Application
Development
Attaching arguments to a fragment
• To attach the arguments bundle to a fragment, you call
Fragment.setArguments(Bundle).
• This method creates the fragment instance and bundles up and sets its
arguments.
• When the hosting activity needs an instance of that fragment, you have it
call the newInstance(...) method rather than calling the constructor
directly.
Mobile Application
Development
Attaching arguments to a fragment
• The activity can pass in any required parameters to newInstance(...) that
the fragment needs to create its arguments.
Mobile Application
Development
Writing a newInstance(UUID) method (CrimeFragment.java)
• Notice that the need for independence does not go both ways.
• CrimeActivity has to know plenty about CrimeFragment,
including that it has a newInstance(UUID) method. This is fine.
• Hosting activities should know the specifics of how to host their
Mobile Application
fragments, but fragments should not have to know specifics
Development about their activities.
• At least, not if you want to maintain the flexibility of independent
fragments.
Retrieving arguments
Getting crime ID from the arguments (CrimeFragment.java)
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UUID crimeId = (UUID) getActivity().getIntent()
.getSerializableExtra(CrimeActivity.EXTRA_CRIME_ID);
UUID crimeId = (UUID) getArguments().getSerializable(ARG_CRIME_ID);
mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
}
Mobile Application
Development
Reloading the List
• There is one more detail to take care of. Run CriminalIntent, press a list
item, and then modify that Crime’s details.
• These changes are saved to the model, but when you return to the list, the
RecyclerView is unchanged.
• You can work with the ActivityManager’s back stack to reload the list at
the right moment.
Mobile Application
Development
Reloading the List
• This pauses and stops the instance of CrimeListActivity that was initially
on top.
• When the user presses the Back button to return to the list, the
CrimeActivity is popped off the stack and destroyed. At that point, the
CrimeListActivity is started and resumed
Mobile Application
Development
Reloading the list in onResume()
(CrimeListFragment.java)
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
...
}
@Override
public void onResume() {
super.onResume();
updateUI();
}
private void updateUI() {
CrimeLab crimeLab = CrimeLab.get(getActivity());
List<Crime> crimes = crimeLab.getCrimes();
if (mAdapter == null) {
mAdapter = new CrimeAdapter(crimes);
mCrimeRecyclerView.setAdapter(mAdapter);
} else {
mAdapter.notifyDataSetChanged();
}
} Mobile Application
Development
Reloading the list in onResume()
• Why override onResume() to update the RecyclerView and not onStart()?
• You cannot assume that your activity will be stopped when another activity is
in front of it. If the other activity is transparent, your activity may just be
paused. If your activity is paused and your update code is in onStart(), then
the list will not be reloaded. In general, onResume() is the safest place to take
action to update a fragment’s view.
• Run CriminalIntent. Select a crime and change its details. When you return to
the list, you will immediately see your changes.
Mobile Application
Development
Updated object diagram for CriminalIntent
Mobile Application
Development
Using ViewPager
Swiping to page through crimes
Mobile Application
Development
Updated object diagram for CriminalIntent
Mobile Application
Development
Implementing ViewPager
Mobile Application
Development
Creating CrimePagerActivity
CrimePagerActivity will be a subclass of AppCompatActivity. It will create and manage
the ViewPager.
Mobile Application
Development
Creating CrimePagerActivity
Create a new layout file in res/layout/ and name it activity_crime_pager. Make its
root view a ViewPager and give it the attributes
You use ViewPager’s full package name when adding it to the layout file
because the ViewPager class is from the support library. Unlike Fragment,
ViewPager is only available in the support library; there is not a “standard”
ViewPager class in a later SDK.
Mobile Application
Development
ViewPager and PagerAdapter
• When your getItem(int) method is called for a position in your array of crimes,
it will return a CrimeFragment configured to display the crime at that position.
mCrimes = CrimeLab.get(this).getCrimes();
FragmentManager fragmentManager = getSupportFragmentManager();
mViewPager.setAdapter(new
FragmentStatePagerAdapter(fragmentManager) {
@Override
public Fragment getItem(int position) {
Crime crime = mCrimes.get(position);
return CrimeFragment.newInstance(crime.getId());
}
@Override
public int getCount() {
return mCrimes.size();
}
});Mobile Application
} Development
}
Integrating CrimePagerActivity
public class CrimePagerActivity extends AppCompatActivity {
private static final String EXTRA_CRIME_ID =
"com.bignerdranch.android.criminalintent.crime_id";
Mobile Application
Development
Adding CrimePager Activity to the manifest
(AndroidManifest.xml)
<manifest ...>
...
<application ...>
...
<activity
android:name=".CrimeActivity"
android:name=".CrimePagerActivity"> </activity>
Mobile Application
Development
Run CriminalIntent
• Run CriminalIntent. Press Crime #0 to view its details. Then swipe left and
right to browse the crimes. Notice that the paging is smooth and there is no
delay in loading.
• By default, ViewPager loads the item currently onscreen plus one neighboring
page in each direction so that the response to a swipe is immediate.
• You can tweak how many neighboring pages are loaded by calling
setOffscreenPageLimit(int).
• Your ViewPager is not yet perfect. Press the Back button to return to the list of
crimes and press a different item.
• You will see the first crime displayed again instead of the crime that you asked
for.
Mobile Application
Development
Run CriminalIntent
• You can have it show the crime that was selected by setting the ViewPager’s
current item to the index of the selected crime.
• When you find the Crime instance whose mId matches the crimeId in the
intent extra, set the current item to the index of that Crime.
Mobile Application
Development
Run CriminalIntent
public class CrimePagerActivity extends AppCompatActivity {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
FragmentManager fragmentManager =
getSupportFragmentManager();
mViewPager.setAdapter(new
FragmentStatePagerAdapter(fragmentManager) {
...
});
for (int i = 0; i < mCrimes.size(); i++) {
if (mCrimes.get(i).getId().equals(crimeId)) {
mViewPager.setCurrentItem(i);
break;
}
}
}
} Mobile Application
Development
FragmentStatePagerAdapter vs FragmentPagerAdapter
Mobile Application
Development
Dialogs
A dialog for picking the date of a crime
Mobile Application
Development
Dialogs
• When Lollipop was released, dialogs were given a visual makeover.
• AlertDialogs on Lollipop automatically use this new style.
• On earlier versions of Android, AlertDialog will fall back to the older style
Mobile Application
Development