Date post: | 22-May-2015 |
Category: |
Technology |
Upload: | david-vavra |
View: | 665 times |
Download: | 2 times |
Jak zabít několik much jednou ranou přechodem na Fragmenty+David Vávra pro GUG ČVUT
Dlužníček● Společné výdaje, 50k+ stažení● mouchy:
○ na tabletech roztažené○ není úplně podle Android
Design guidelines■ dashboard screen■ Nová platba a Kdo má
platit jsou akce○ Swipe mezi skupinami○ rotace obrazovky => android:
configChanges="orientation"
○ jinak AsyncTasky leaknou aktivitu
○ nepoužívají se observery na data
○ View not attached to window manager Exception
○ mohlo by být rychlejší
● nové API Android 3.0 Honeycomb (+ Compatibility Library)● znovupoužitelné UI komponenty● http://developer.android.com/guide/components/fragments.html
Co s tím? Fragmenty!
Příklad z dokumentace layout-sw600dp-land/fragment_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation ="horizontal" android:layout_width ="match_parent" android:layout_height ="match_parent" >
<fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment" android:id="@+id/titles" android:layout_weight="1" android:layout_width ="0px" android:layout_height ="match_parent" />
<FrameLayout android:id="@+id/details" android:layout_weight ="1" android:layout_width ="0px" android:layout_height ="match_parent" android:background ="?android:attr/detailsElementBackground" />
</LinearLayout>
layout/fragment_layout.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width ="match_parent" android:layout_height ="match_parent" > <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment" android:id="@+id/titles" android:layout_width ="match_parent" android:layout_height ="match_parent" /></FrameLayout>
TitlesActity:
@Overrideprotected void onCreate(Bundle savedInstanceState ) { super.onCreate(savedInstanceState ); setContentView (R.layout.fragment_layout );}
public static class TitlesFragment extends ListFragment { boolean mDualPane; @Override public void onActivityCreated (Bundle savedInstanceState ) { setListAdapter (new ArrayAdapter<String>(getActivity(), android .R.layout.simple_list_item_activated_1 , Shakespeare.TITLES)); View detailsFrame = getActivity().findViewById(R.id.details); mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE; }
@Override public void onListItemClick (ListView l, View v, int position, long id) { if (mDualPane) { DetailsFragment details = DetailsFragment .newInstance(position); getFragmentManager ().beginTransaction ().replace(R.id.details, details).commit(); } else { Intent intent = new Intent(); intent .setClass(getActivity(), DetailsActivity .class); intent .putExtra("index", index); startActivity (intent); } }}
TitlesFragment
DetailsFragmentpublic static class DetailsFragment extends Fragment {
public static DetailsFragment newInstance(int index) { DetailsFragment f = new DetailsFragment ();
Bundle args = new Bundle(); args.putInt("index", index); f.setArguments(args);
return f; }
public int getShownIndex () { return getArguments().getInt("index", 0); }
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { ScrollView scroller = new ScrollView(getActivity()); TextView text = new TextView(getActivity()); scroller .addView(text); text.setText(Shakespeare.DIALOGUE[getShownIndex()]); return scroller; }}
DetailsActivitypublic static class DetailsActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState ) { super.onCreate(savedInstanceState );
if (getResources().getConfiguration ().orientation == Configuration.ORIENTATION_LANDSCAPE ) { finish (); return; } DetailsFragment details = new DetailsFragment (); details .setArguments(getIntent().getExtras()); getFragmentManager ().beginTransaction ().add(android.R.id.content, details).commit(); }}
Zásek #1: PaymentsActivity
Zásek #1: PaymentDetailActivity
Zásek #1: řešení● Jedna aktivita
○ hacky ActionBaru○ rotace, rotace, rotace a zachování stavu○ tlačítko back
■ addToBackStack - buggy = Fragmenty přes sebe■ ale pak nejde použít setRetainInstance(true) => problémy s
AsyncTasky a savedIntanceState● Dvě aktivity
○ ActionBar definovaný v aktivitě handling ve fragmentu○ je jasné co bude po rotaci = stejná aktivita○ back funguje out of the box○ setRetainInstance(true) funguje krásně○ bez hacků○ animaci mezi aktivitami jde vypnout
Zásek #2: AsyncTasky a observerypublic class SettleUpFragment extends SherlockFragment {
protected SettleUpActivity c;private Uri uriToObserve = null;private AsyncTask<Void, Void, Void>
fillDataTask;private NewAsyncTaskCallback
newAsyncTaskCallback;@Overridepublic void onAttach(Activity activity) {
super.onAttach(activity);c = (SettleUpActivity) activity;
}@Overridepublic void onDetach() {
super.onDetach();if (fillDataTask != null) {
fillDataTask.cancel(true);}
}@Overridepublic void onDestroyView() {
if (uriToObserve != null) { c.getContentResolver().unregisterContentObserver(observer);
}if (fillDataTask != null) {
fillDataTask.cancel(true);}super.onDestroyView();
}
protected void registerObserver(Uri uri) {this.uriToObserve = uri;// TODO: multiple observers
c.getContentResolver().registerContentObserver(uri, true, observer);
}
protected void loadData(NewAsyncTaskCallback callback) {
this.newAsyncTaskCallback = callback;this.fillDataTask = callback.
onCreateAsyncTask();fillDataTask.execute();
}
ContentObserver observer = new ContentObserver(null) {
@Overridepublic void onChange(boolean selfChange) {
if (fillDataTask != null && !fillDataTask.isCancelled()) {
SettleUpFragment.this.fillDataTask = newAsyncTaskCallback.onCreateAsyncTask();
fillDataTask.execute();}
}};
public interface NewAsyncTaskCallback {AsyncTask<Void, Void, Void>
onCreateAsyncTask();}
}
● aplikace nepočítala s více skupinami● invalidace ViewPageru:
○ uiViewPagerIndicator.invalidate()
○ při změně tabu:uiViewPager.getAdapter().notifyDataSetChanged();
@Overridepublic int getItemPosition(Object object) { return POSITION_NONE;}
● handling ActionBaru z aktuálního ViewPager fragmentu:
SettleUpFragment fragment = (SettleUpFragment) uiViewPager.getAdapter().instantiateItem(uiViewPager, uiViewPager.getCurrentItem());
if (fragment != null) {return fragment.
onOptionsItemSelected(item);}
Zásek #3: ViewPager & taby
● Není v Compatibility library● Tutoriál: http://developer.android.com/guide/topics/ui/settings.html#BackCompatHeaders
○ Android >3.0 preference-headers○ Android <3.0 PreferenceScreen s Intenty
● Co když je potřeba přidat listenery atd? ○ samostatná třída co je inicializovaná z Activity nebo Fragmentu
Zásek #4: PreferenceFragment
Shrnutí● Zabité mouchy:
○ na tabletech vypadá dobře○ podle Android Design Guidelines○ rotace obrazovky, pamatování stavu + AsyncTasky bez problémů○ aplikace svižnější○ donutilo mě to k používání observerů a ORM○ víc zapouzdřených komponent = v Aktivitě minimum kódu
● Ale:○ velký refaktoring celé aplikace○ záseky kde i StackOverflow drhne (snad jich po dnešku bude míň)
● Takže:○ pro nové aplikace určitě, pro existující zvážit○ šance jak se prosadit v davu aplikací - HoloEverywhere.com atd.
■ Aplikace Tasks - za 3 měsíce 100k stažení placené verze
● David Vávra○ http://gplus.to/destil○ @destil○ Dlužníček: http://www.settleup.info
Dotazy?