android_learning:headfirst_android_development_notes:chapter_8
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
android_learning:headfirst_android_development_notes:chapter_8 [2016/01/09 01:08] – created mithat | android_learning:headfirst_android_development_notes:chapter_8 [2016/02/21 04:24] (current) – [On Android fragment managers] mithat | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | <WRAP center round info 60%> | + | ====== Chapter 8 ====== |
- | Under development. | + | |
- | </WRAP> | + | ===== pp. 328-329 ===== |
+ | |||
+ | Don't get discouraged if you miss a lot of the details in converting the code. The authors pretty much throw you into the deep end with this exercise. Be sure to study the solution on pp. 330-331 and make sure you understand why each change is necessary. | ||
+ | |||
+ | The summary of converting Activities to Fragments is: | ||
+ | * Change the class name to '' | ||
+ | * Make all lifecycle methods public. | ||
+ | * Define an '' | ||
+ | * Remove any cruft from the lifecycle methods. | ||
+ | * Be very careful about when/ | ||
+ | |||
+ | The last item above is often the most challenging. | ||
+ | |||
+ | ===== pp. 332-334: Code block ===== | ||
+ | |||
+ | <file java StopwatchFragment.java> | ||
+ | package com.hfad.workout; | ||
+ | |||
+ | import android.os.Bundle; | ||
+ | import android.os.Handler; | ||
+ | import android.app.Fragment; | ||
+ | import android.view.LayoutInflater; | ||
+ | import android.view.View; | ||
+ | import android.view.ViewGroup; | ||
+ | import android.widget.TextView; | ||
+ | |||
+ | public class StopwatchFragment extends Fragment { | ||
+ | //Number of seconds displayed on the stopwatch. | ||
+ | private int seconds = 0; | ||
+ | //Is the stopwatch running? | ||
+ | private boolean running; | ||
+ | private boolean wasRunning; | ||
+ | |||
+ | @Override | ||
+ | public void onCreate(Bundle savedInstanceState) { | ||
+ | super.onCreate(savedInstanceState); | ||
+ | if (savedInstanceState != null) { | ||
+ | seconds = savedInstanceState.getInt(" | ||
+ | running = savedInstanceState.getBoolean(" | ||
+ | wasRunning = savedInstanceState.getBoolean(" | ||
+ | if (wasRunning) { | ||
+ | running = true; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public View onCreateView(LayoutInflater inflater, ViewGroup container, | ||
+ | | ||
+ | View layout = inflater.inflate(R.layout.fragment_stopwatch, | ||
+ | runTimer(layout); | ||
+ | return layout; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void onPause() { | ||
+ | super.onPause(); | ||
+ | wasRunning = running; | ||
+ | running = false; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void onResume() { | ||
+ | super.onResume(); | ||
+ | if (wasRunning) { | ||
+ | running = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void onSaveInstanceState(Bundle savedInstanceState) { | ||
+ | savedInstanceState.putInt(" | ||
+ | savedInstanceState.putBoolean(" | ||
+ | savedInstanceState.putBoolean(" | ||
+ | } | ||
+ | |||
+ | public void onClickStart(View view) { | ||
+ | running = true; | ||
+ | } | ||
+ | |||
+ | public void onClickStop(View view) { | ||
+ | running = false; | ||
+ | } | ||
+ | |||
+ | public void onClickReset(View view) { | ||
+ | running = false; | ||
+ | seconds = 0; | ||
+ | } | ||
+ | |||
+ | private void runTimer(View view) { | ||
+ | final TextView timeView = (TextView) view.findViewById(R.id.time_view); | ||
+ | final Handler handler = new Handler(); | ||
+ | handler.post(new Runnable() { | ||
+ | @Override | ||
+ | public void run() { | ||
+ | int hours = seconds / 3600; | ||
+ | int minutes = (seconds % 3600) / 60; | ||
+ | int secs = seconds | ||
+ | String time = String.format(" | ||
+ | hours, minutes, secs); | ||
+ | timeView.setText(time); | ||
+ | if (running) { | ||
+ | seconds++; | ||
+ | } | ||
+ | handler.postDelayed(this, | ||
+ | } | ||
+ | }); | ||
+ | } | ||
+ | } | ||
+ | </file> | ||
+ | |||
+ | ===== pp. 335-336: Code block ===== | ||
+ | <file xml fragment_stopwatch.xml> | ||
+ | <?xml version=" | ||
+ | < | ||
+ | xmlns: | ||
+ | android: | ||
+ | android: | ||
+ | |||
+ | < | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | |||
+ | < | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | |||
+ | < | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | |||
+ | < | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | android: | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ===== On Android fragment managers ===== | ||
+ | |||
+ | //rant: on// | ||
+ | |||
+ | Given my current understanding of Android, I think the way it deals with nested fragments is pretty awful. The concepts are ok-ish, but the implementation is confusing. | ||
+ | |||
+ | Some key points are: | ||
+ | * There are two different fragment manager retrieval functions---one for Activities and another for Fragments. | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | It's awkward to need two different function names for these two very similar cases, but fine. What I think is really awful is the naming of the functions: '' | ||
+ | |||
+ | I suspect the reason for requiring two different functions is that the AOSP developers didn't fully think through things when they first developed Fragments, and when they figured out a better architecture, | ||
+ | |||
+ | //rant: off// | ||
+ | |||
+ | ===== p. 342 Code block ===== | ||
+ | <code java> | ||
+ | FragmentTransaction ft = getChildFragmentManager().beginTransaction(); | ||
+ | StopwatchFragment stopwatchFragment = new StopwatchFragment(); | ||
+ | ft.replace(R.id.stopwatch_container, | ||
+ | ft.addToBackStack(null); | ||
+ | ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); | ||
+ | ft.commit(); | ||
+ | </ | ||
+ | |||
+ | ===== p. 350: Code block ===== | ||
+ | <code java> | ||
+ | switch (v.getId()) { | ||
+ | case R.id.start_button: | ||
+ | onClickStart(v); | ||
+ | break; | ||
+ | case R.id.stop_button: | ||
+ | onClickStop(v); | ||
+ | break; | ||
+ | case R.id.reset_button: | ||
+ | onClickReset(v); | ||
+ | break; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== p. 351: Code block ===== | ||
+ | <code java> | ||
+ | Button startButton = (Button)layout.findViewById(R.id.start_button); | ||
+ | startButton.setOnClickListener(this); | ||
+ | Button stopButton = (Button)layout.findViewById(R.id.stop_button); | ||
+ | stopButton.setOnClickListener(this); | ||
+ | Button resetButton = (Button)layout.findViewById(R.id.reset_button); | ||
+ | resetButton.setOnClickListener(this); | ||
+ | </ | ||
+ | |||
+ | ===== p. 356-358 ===== | ||
+ | The takeaway from this section is that the host Activity' |
android_learning/headfirst_android_development_notes/chapter_8.1452301680.txt.gz · Last modified: 2016/01/09 01:08 by mithat