Android - Tips & Tricks Richard Davison Developer Mobility richard.davison@cgi.com 16 April 2014 CGI Group Inc. CONFIDENTIAL
Agenda Intro IDE och emulator optimeringar Resurshantering XML rätt och fel Designprinciper List-optimeringar - Picasso Fragments Trådhantering, EventBus och rotation Frågor 2
Intro Android ios Microsoft BlackBerry Others 12% 1% 4%2% 82% Gartner, nov 2013 3
IDE och Emulator Eclipse 4.4 Luna Java 7 eclipse.ini Android studio Emulator Vaska den befintliga Använd Genymotion http://www.genymotion.com/ RAM DISK1111 Java 7 4
Resurshantering - res Res-mappen Default DP - Density Indipendent Pixels Android använder inte Pixlar Lägg dina värden i - res/values/dimens.xml <resources> <dimen name="space_l">16dp</dimen> <dimen name="space_m">8dp</dimen> <dimen name="space_s">4dp</dimen> </resources> Alternative Hanterar resurser automagiskt 5
Resurshantering - fortsättning Refs - referenser peka på andra resurser beroende på konfiguration Exempel - res/values-sw600dp/refs.xml & res/values-large/refs.xml <resources> <item name="activity_main" type="layout">@layout/activity_main_twopane</item> </resources> SW = smallest width, large = stor enhet Kör activity_main_twopane istället för activity_main när vi har en surfplatta 6
XML Djupa layouter ger sämre prestanda Platta ut RelativeLayout is your friend GridLayout - ungefär som HTML <table> TIPS Prefix för android:id som definierar view-typ img_profile btn_register txt_name lay_button_wrapper <GridLayout xmlns:android="http://schemas.android.com/apk/ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/lay_grid" android:layout_width= match_parent" android:layout_height="wrap_content" android:columncount="3" tools:context=".gridlayoutactivity" > <Button android:id="@+id/btn_example_0" android:layout_column="0" android:layout_gravity="left top" android:layout_row="0" android:text="button" /> <Button android:id="@+id/btn_example_1" android:layout_column="1" android:layout_gravity="left top" android:layout_row="0" android:text="button" /> <Button android:id="@+id/btn_example_2" android:layout_column="2" android:layout_gravity="fill_vertical" android:layout_row="0" android:layout_rowspan="2" android:text="button" /> <Button android:id="@+id/btn_example_3" android:layout_column="0" android:layout_columnspan="2" android:layout_gravity="fill_horizontal" android:layout_row="1" android:text="button" /> </GridLayout> 7
Designprinciper = Android är INTE ios Olika OS = olika former av navigering, layout, designspråk Ikoner, 3d perspektiv, inte tvingad till en avrundad kvadrat Undvik splashscreens - behövs inte Använd ActionBar - är sammanhängande, uppfinn inte hjulet på nytt Använd appcompat library för ActionBar API 8+ LÄS design guidelines - https://developer.android.com/design/index.html 8
List-optimeringar - behind the scene 9
List-optimeringar Dyrt att köra inflate() och findviewbyid() återanvänd convertview i din adapter ViewHolder pattern Demo Remote-images i en listvy, cache? Picasso Picasso.with(context).load( http://www.example.com/img.jpg").into(imageview); 10
List-optimeringar - Recycle, ViewHolder public View getview(int position, View convertview, ViewGroup parent) { View view = inflater.inflate(r.layout.list_item_complex, null); TextView textview = (TextView) view.findviewbyid(android.r.id.text1); TextView textview2 = (TextView) view.findviewbyid(android.r.id.text2); ImageView imageview = (ImageView) view.findviewbyid(android.r.id.icon); textview.settext(getitem(position).tostring()); textview2.settext(getitem(position).tostring()); imageview.setimageresource(getrandombaconimage()); return view; public View getview(int position, View convertview, ViewGroup parent) { ViewHolder holder; if (convertview == null) { convertview = inflater.inflate(r.layout.list_item_complex, parent, false); holder = new ViewHolder(); holder.textview = (TextView) convertview.findviewbyid(android.r.id.text1); holder.textview2 = (TextView) convertview.findviewbyid(android.r.id.text2); holder.imageview = (ImageView) convertview.findviewbyid(android.r.id.icon); convertview.settag(holder); else { holder = (ViewHolder) convertview.gettag(); holder.textview.settext(getitem(position).tostring()); holder.textview2.settext(getitem(position).tostring()); holder.imageview.setimageresource(getrandombaconimage()); return convertview; private static class ViewHolder { ImageView imageview; TextView textview; TextView textview2; 11
Fragments Mini-activities, egen lifecycle, byggstenar Lätt att optimera för tablet Använd INTE constructor Implementera en statisk factory metod private static final String EXTRA_SOME_INT = "extra_some_int"; public static MyFragment newinstance(int someint) { MyFragment myfragment = new MyFragment(); Bundle args = new Bundle(); args.putint(extra_some_int, someint); myfragment.setarguments(args); return myfragment; TIPS När du startar en activity, använd även där en statisk metod private static final String EXTRA_PARAM_1 = "extra_param_1"; private static final String EXTRA_PARAM_2 = "extra_param_2"; public static void startactivity(context context, String param1, int param2){ Intent intent = new Intent(context, ThisActivity.class); intent.putextra(extra_param_1, param1); intent.putextra(extra_param_2, param2); context.startactivity(intent); 12
Fragments - fortsättning Lägg till fragment, oncreate - check ifall det redan finns Fragment fragment = MyFragment.newInstance(20); FragmentManager fm = getsupportfragmentmanager(); if (fm.findfragmentbyid(android.r.id.content) == null) { fm.begintransaction().add(android.r.id.content, fragment).commit(); Back stack, animation, bakåtknapp FragmentTransaction transaction = fm.begintransaction(); transaction.replace(android.r.id.content, MyFragment.newInstance(20)); transaction.addtobackstack(null); transaction.settransition(fragmenttransaction.transit_fragment_open); transaction.commit(); 13
Trådhantering Async task Finns andra alternativ, bättre för lifecycle events Svårt med configchanges, mellan fragments, services etc <activity android:name="myactivity" android:configchanges="orientation keyboardhidden screensize" /> Headless fragment, lever utanför din activity setretaininstance(true); 14
Trådhantering - fortsättning Jobbigt med callbacks, tänk på activity lifecycle, och referensen till din activity Enkel lösning EventBus by Två steg Registrera din klass för att ta emot event (av en viss typ) Posta eventet Fungerar mellan ALLA klasser, i alla trådar, automagiskt 15
Trådhantering - EventBus demo Registrera event och implementera metoder EventBus.getDefault().register(this); public void onevent(myeventclass object){ dosomething(); public void oneventmainthread(myeventclass object){ dosomething(); Posta ditt event EventBus.getDefault().post(new MyEventClass()); EventBus innehåller en AsyncExecutor T.ex activity, kör i oncreate() OBS T.ex activity, kör i ondestroy() AsyncExecutor.create().execute(new RunnableEx() { @Override public void run() throws Exception { Glöm ej avregistrera din klass try{ EventBus.getDefault().unregister(this); Object result = backgroundoperation(); EventBus.getDefault().post(result); catch(exception ex){ ex.printstacktrace(); EventBus.getDefault().post(new Events.MyErrorEventClass(ex)); ); 16
Länkar ViewHolder pattern - http://www.codeofaninja.com/2013/09/androidviewholder-pattern-example.html Picasso - https://github.com/square/picasso Design Guidelines - http://developer.android.com/design/index.html Fragments - http://www.vogella.com/tutorials/androidfragments/ article.html EventBus - https://github.com/greenrobot/eventbus Slides - http://www.slideshare.net/greenrobot/eventbus-forandroid-15314813 Robospice - värt att kolla på - https://github.com/stephanenicolas/ robospice 17
Tack Frågor?