54
Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 1 Who I am Born in the past millenium and still an happy software developer Mobile addicted Android enthusiastic Free software fan Proud rider … and Tiramisu' lover rainbowbreeze

Android Survival Guide - Two years of software development

Embed Size (px)

DESCRIPTION

During the session, I'll explore lot of useful tricks I use during my everyday life as Android developer. Testing, background tasks, smartphone and tablet optimization, avoid memory leaks, UI view management, good external libraries to take into account, mobile design patterns and some best practices I found.

Citation preview

Page 1: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 1

Who I am

Born in the past millenium and still an happy software developer

Mobile addictedAndroid enthusiastic

Free software fanProud rider

… and Tiramisu' lover

rainbowbreeze

Page 2: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 2

Overview

Online learnig resources

Paintless rotation with threads

Easy IoC/DI framework

Testing, from unit to automation

Honeycomb and backward compatibility

Libraries and frameworks

Q&A session

Page 3: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 3

Chocolate Interaction model

Don't be scare: interact, collaborate, share your fun!

Page 4: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 4

Useful online material – Patterns

Designing and Implementing Android UIshttp://www.google.com/events/io/2011/sessions/designing-and-implementing-android-uis-

for-phones-and-tablets.html http://code.google.com/p/iosched/

Advanced Topics for Expert Android App Devshttp://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-

android-app-developers.html

Developing Android REST client applicationshttp://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html

Page 5: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 5

Useful online material - ListView

The world of ListViewhttp://www.google.com/events/io/2010/sessions/world-of-listview-android.html

Lazy-loading of remote thumbnailshttp://android-developers.blogspot.com/2010/07/multithreading-for-performance.html

Drag and Drop capable ListView https://github.com/commonsguy/cwac-touchlist

Page 6: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 6

Background thread, progress bar and rotation

Your application have to be smooth, don't use UI thread for long operation (> 200ms)

Yuo cannot update UI Thread from external threads

Use Activity.runOnUiThread(Runnable), View.post(Runnable), View.postDelayed(Runnable,

long), Handler to bypass the problem

Page 7: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 7

Background thread, progress bar and rotation

public void onClick(View v) { //background thread new Thread(new Runnable() { public void run() { final Bitmap b = loadImageFromNetwork(); //update ui thread mImageView.post(new Runnable() { public void run() { mImageView.setImageBitmap(b); } }); } }).start();}

Page 8: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 8

Background thread, progress bar and rotation

The simplest way

AsyncTaskCan access to UI Thread from separate thread

http://android-developers.blogspot.com/2009/05/painless-threading.html

Page 9: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 9

Background thread, progress bar and rotation

protected void onCreate(Bundle savedInstanceState) { ... mLblResult = (TextView) findViewById(R.id.lblResult); LongTask longTask = new LongTask(); longTask.execute(); …}

private class LongTask extends AsyncTask<Void, Void, String> ... protected void onPostExecute(String result) { mLblResult.setText(result); }

Page 10: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 10

Background thread, progress bar and rotation

But if the screen is rotated while the backgroud thread is still in execution?

UI not updated, dialogs disappear, NullPointerException, memory leaks...

OMG!

Page 11: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 11

Background thread, progress bar and rotation

The clean way

- Define an Handler inside the Activity that process thread tasks (update/result)

- Create background thread passing the handler- Call the handler from the thread when a progress must be

published or the thread finish- Update activity reference inside thread using OnPause()

and OnResume()- Pay attention to OnStart and other Activity lifecycle events

http://code.google.com/p/rainbowlibs/source/browse/android/trunk/rainbowlibs/src/it/rainbowbreeze/libs/logic/RainbowBaseBackgroundThread.java

http://code.google.com/p/rainbowlibs/source/browse/android/trunk/rainbowlibs/src/it/rainbowbreeze/libs/ui/RainbowSplashScreenActivity.java

Page 12: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 12

Background thread, progress bar and rotation

public class WebcamActivity extends Activity() {

private Handler mActivityHandler = new Handler() {

public void handleMessage(Message msg) { Log.debug("Message from external thread" + msg.what); switch (msg.what) { case RotationThread.OPERATION_STARTS: //create progress dialog + other UI operations break; case RotationThread.OPERATION_COMPLETED:

//remove the dialog + additional logic break; case RotationThread.OPERATION_ERROR: //remove the dialog + additional error logic

Page 13: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 13

Background thread, progress bar and rotation

public class WebcamActivity extends Activity() {

private RotatingThread mRotatingThread;

private void showWebcam() { //show a progress dialog showDialog(DIALOG_PREPARE_FOR_FULLSCREEN);

mRotatingThread = new RotatingThread( mActivityHandler,

webcamToShowId); mRotatingThread.start(); }

Page 14: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 14

Background thread, progress bar and rotation

public class RotatingThread() extends Thread { private WeakReference<Handler> mCallerHandler;

public RotatingThread(Handler handler, int webcamId) { registerCallerHandler(handler); … }

public void registerCallerHandler(Handler newHandler { mCallerHandler = new WeakReference<Handler>(newHandler); }

public void unregisterCallerHandler() { mCallerHandler = null; }

Page 15: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 15

Background thread, progress bar and rotation

public class RotatingThread() extends Thread { ...

public void run() { callHandlerAndRetry(OPERATION_STARTS);

//your long operation here

callHandlerAndRetry(OPERATION_COMPLETED); }

Page 16: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 16

Background thread, progress bar and rotation

protected void callHandlerAndRetry(int messageCode) { for (int retries = 0; retries < TOTAL_RETRIES; retries++) {

if (null != mCallerHandler && null != mCallerHandler.get()) { Message message = mCallerHandler.get().obtainMessage(messageCode); message.arg1 = arg1; mCallerHandler.get().sendMessage(message); break; }

try { //what some times, maybe next time activity is ready Thread.sleep(INTERVAL_BETWEEN_RETRIES); } catch (InterruptedException ignoreExcepition) {} }}

Page 17: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 17

Background thread, progress bar and rotation

public class WebcamActivity extends Activity() {

@Override protected void onPause() { mRotatingThread.unregisterCallerHandler(); super.onPause(); }

@Override protected void onResume() { mRotatingThread.registerCallerHandler(mActivityHandler); super.onResume(); }

Page 18: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 18

Background thread, progress bar and rotation

public class WebcamActivity extends Activity() {

@Override public Object onRetainNonConfigurationInstance() { return mRotatingThread; }

@Override protected void onStart() { super.onStart(); mRotatingThread = (RotatinThread)getLastNonConfigurationInstance(); //nothing saved, first run of the activity if (null == mRotatingThread) showWebcam(); }

Page 19: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 19

Background thread, progress bar and rotation

The short (but no totally complete) way

Use a Fragment and setRetainInstance(true)http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/

app/FragmentRetainInstance.html

Page 20: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 20

Lazy loading singleton

Singleton PatternEnsure that only one instance of a class is created and provide a

global point of access to the object.

Create your own singleton or extend android.app.Application and modify its onCreate()

method.Base class for those who need to maintain global application state. You can provide your own implementation by specifying its name in

your AndroidManifest.xml’s <application> tag, which will cause that class to be instantiated for you when the process for your

application/package is created.

Page 21: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 21

Lazy loading singleton

public class App extends Application { public static int myGlobalStaticValue; public int myGlobalValue;

@Override public void onCreate() { super.onCreate(); myGlobalStaticValue = 10; myGlobalValue = 20; }

<application android:name="it.rainbowbreeze.singleton.App">

int value = App.myGlobalStaticValue;int value = ((App)context.getApplication()).myGlobalValue;

Page 22: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 22

Lazy loading singleton

DrawbacksSingleton is a pattern or an anti-pattern?

http://stackoverflow.com/questions/3826905/singletons-vs-application-context-in-android

OS may kill your application process, including the Application subclass instance. As a result the state is lost. When you later return to the application, then the OS will restore its activity

stack and Application subclass instance, but its fields will be null.

If you really need singleton, at least use lazy-loading singleton and avoid static fields to store

application lifecycle data

Page 23: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 23

Lazy loading singleton

public class MySingleton() { private MySingleton mInstance;

public synchronized MySingleton getInstance(Context c) { if (null == mInstance) { mInstance = new MySingleton(context); } return mInstance; }

private MySingleton(Context appContext) { //initializes the object //reload SharedPreferences data }

Page 24: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 24

Inversion of Control / Dependency Injection

Dependency Injection PatternThe object does not need to know in advance about how the

other part of the system works. Instead, the programmer provides (injects) the relevant system component in advance

along with a contract that it will behave in a certain way.http://en.wikipedia.org/wiki/Dependency_injection

Reduce the coupling among software components: better code testability, useful in libraries, clean

code.

Page 25: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 25

Inversion of Control / Dependency Injectionpublic class ItemDao implements ItemDao {

public ItemDao(Context appContext) { //performs initialization }}

public DataManager implements IDataManager { INetManager mNetManager; IItemDao mItemDao;

public DataManager(INetManager netMngr, IItemDao itemDao) { mNetManager = netMngr; mItemDao = itemDao; }

Page 26: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 26

Inversion of Control / Dependency Injection

DrawbacksComplex and less readable code

Chain of dependenciesMore code to write

SolutionsIoc/DI frameworks manage all the boring things!

Page 27: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 27

Inversion of Control / Dependency Injection

public class AppEnv() { public static AppEnv i(Context appContext) { … mInstance = new AppEnv(appContext); return mInstance; }

private AppEnv(Context appContext) { mItemDao = new ItemDao(appContext); mDataManager = new DataManager(mNetMngr, mItemDao); }

ItemsDao mItemDao; public ItemsDao getItemDao(){ return mItemDao; }

Page 28: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 28

Inversion of Control / Dependency Injection

DrawbacksCannot inject mock for testiong purposes

SolutionsSeparate the object factory from the singleton

Page 29: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 29

Inversion of Control / Dependency Injection

public class ObjFactory {

public ItemDao createDao(Context appContext) { return new ItemDao(appContext); }

public DataManager createDataManager( INetManager netMngr, ItemDao itemDao) { return new DataManager(netManager, itemDao); }

}

Page 30: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 30

Inversion of Control / Dependency Injection

public class AppEnv() { private static ObjFactory mObjFactory = new ObjFactory();

public static AppEnv i(Context c) { … mInstance = new AppEnv(c, mObjFactory); return mInstance; }

public static AppEnv i(Context c, ObjFactory customFactory) { … mInstance = new AppEnv(c, customFactory); return mInstance; }

Page 31: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 31

Inversion of Control / Dependency Injection

public class AppEnv() { …

private AppEnv(Context appContext, ObjFactory objFactory) { mDao = objFactory.createDao(appContext); //... other initialization mDataManager = objFactory.createDataManager( mNetMngr, mDao); }

private ItemsDao mDao; public ItemsDao getItemDao(){ return mDao; }

Page 32: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 32

Inversion of Control / Dependency Injection

--- inside your activity / component ---AppEnv appEnv = AppEnv.i(getContext());ItemDao dao = appEnv.getItemDao();

--- inside your test class ---MockObjFactory mockFactory = new MockObjFactory() { @Overrides public ItemDao createDao(Context appContext) { return new MockItemDao(appContext); }};AppEnv appEnv = AppEnv.i(getContext(), mockFactory);ItemDao dao = appEnv.getItemDao();

Page 33: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 33

Inversion of Control / Dependency Injection

RoboGuiceLike Google Guice, but for Android

http://code.google.com/p/roboguice/http://stackoverflow.com/questions/5067681/guice-performance-on-android

Other solutionshttp://stackoverflow.com/questions/1029696/the-hunt-for-the-j2me-friendly-ioc-container-is-on

Page 34: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 34

Testing - basic

Software testing = reduce risks of software implementation

Lot of support Android sidehttp://developer.android.com/guide/topics/testing/testing_android.html

Page 35: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 35

Testing - first steps

Create new “Android Test Project”Create a class that extends TestCase

Code first test

Red, Green, Refactor!

http://developer.android.com/resources/tutorials/testing/helloandroid_test.html

Page 36: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 36

Testing - first steps

public class MyFirstTest extends TextCase() { Private MyStringConverter mConverter;

public void setUp() { mConverter = new MyStringConverter(); }

public testUpperCaseConversion() { String result = mConverter.toUppercase(“ota2011”); assertEquals(“Wrong value”, “OTA2011”, result); }}

Page 37: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 37

Testing with special Android Mock

AndroidTestCaseaccess to a context

http://developer.android.com/reference/android/test/AndroidTestCase.html

ApplicationTestCasetest app lifecycle, inject mock context

http://developer.android.com/reference/android/test/ApplicationTestCase.html

Activity Testing APItest activity lifecycle, inject mocks, send key or touch events, etc

http://developer.android.com/resources/tutorials/testing/activity_test.html

http://developer.android.com/guide/topics/testing/activity_testing.html

Page 38: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 38

Testing with special Android Mock

public class SpinnerActivityTest extends ActivityInstrumentationTestCase2<SpinnerActivity> {

protected void setUp() throws Exception { … mActivity = getActivity(); mSpinner = (Spinner) mActivity.findViewById(R.id.Spinner01); … } public void testSpinnerUI() { this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER); mPos = mSpinner.getSelectedItemPosition(); mSelection = (String)mSpinner.getItemAtPosition(mPos); assertEquals(resultText, mSelection);

Page 39: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 39

Testing with special Android Mock

ProviderTestCase2test contentProvicer with isolated context

http://developer.android.com/guide/topics/testing/contentprovider_testing.html

ServiceTestCasetest the service lifecycle, not the logic (detached)http://developer.android.com/guide/topics/testing/service_testing.html

ViewAsserts, MoreAssertsextended assertsextended asserts

Page 40: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 40

Test automation with monkey

adb shell monkey -p your.package.name -v 500sends sequences of random events

http://developer.android.com/guide/developing/tools/monkey.html

monkeyrunner A Python program that runs an application, sends keystrokes to it,

takes screenshots of its user interface, and stores themhttp://developer.android.com/guide/developing/tools/monkeyrunner_concepts.html

Page 41: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 41

Testing with external tools

RobotiumAutomatic black-box test cases for Android applications, with

gesture and actionshttp://code.google.com/p/robotium/

RobolectricFast and easy TDD, runs tests in normal JavaVM with mock

Android classes, no need to deploy on devicehttp://pivotal.github.com/robolectric/

Page 42: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 42

Honeycomb and Backward Compatibility

Nowadays Android has two separate branches, but Ice Cream Sandwich will merge them

Avoid different versions of same app and prefer one adaptive Use alternative resources

AndroidManifest.xml filters for sdk, screen, hwPut some dirty if in code

http://code.google.com/p/iosched/

Page 43: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 43

Honeycomb and Backward Compatibility

Resources

res/layout/main_activity.xml # For phonesres/layout-xlarge/main_activity.xml # Large screenres/layout-sw600dp/main_activity.xml # For 7” tabletsres/layout-sw720dp/main_activity.xml # For 10” tablets… and much more!

http://android-developers.blogspot.com/2011/07/new-tools-for-managing-screen-sizes.html

Page 44: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 44

Honeycomb and Backward Compatibility

<!-- Tablet-only application --><manifest ... > <supports-screens android:smallScreens="false" android:normalScreens="false" android:largeScreens="false" android:xlargeScreens="true" android:requiresSmallestWidthDp="600" /> <application ... > ... </application></manifest>

http://android-developers.blogspot.com/2011/09/preparing-for-handsets.html http://android-developers.blogspot.com/2011/07/new-mode-for-apps-on-large-

screens.html

Page 45: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 45

Testing with special Android Mock

Dirty if

private static boolean fragmentsSupported = false;

private static void checkFragmentsSupported()throws NoClassDefFoundError { fragmentsSupported = android.app.Fragment.class != null;}

static { try { checkFragmentsSupported(); } catch (NoClassDefFoundError e) { fragmentsSupported = false; }

Page 46: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 46

Testing with special Android Mock@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

Intent intent = null; if (!fragmentsSupported) intent = new Intent(this, MainNonFragmentActivity.class); else intent = new Intent(this, MainFragmentActivity.class);

startActivity(intent); finish(); }}

http://blog.radioactiveyak.com/2011/02/strategies-for-honeycomb-and-backwards.html

Page 47: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 47

Honeycomb and Backward Compatibility

Android Compatibility PackageBackport some 3.x APIs to 1.6 and 2.x

http://developer.android.com/sdk/compatibility-library.html

Support for Fragment, Loader, ViewPager

Native code on 3.x, library code on 2.x

Page 48: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 48

Honeycomb and Backward Compatibility

Fragment

http://android-developers.blogspot.com/2011/03/fragments-for-all.html

Page 49: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 49

Honeycomb and Backward Compatibility

setRetainInstance(true)activity is rotated but fragment is not destroyed and

recreated, lifecycle events are called.Finally!

Bug: http://code.google.com/p/android/issues/detail?id=17423Bug: http://stackoverflow.com/questions/6250580/fragment-already-added-

illegalstateexception

Page 50: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 50

Honeycomb Backward Compatibility

ActionBarSherlockLibrary that uses native code for 3.x or its own code for 2.x

http://actionbarsherlock.com/

GreenDroidBrand new actionbar implementation

http://android.cyrilmottier.com/?p=274

Page 51: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 51

Useful libraries and resources

Android UI patterns blogshttp://www.androiduipatterns.com http://www.androidpatterns.com

Android-ui-utilsAsset Studio, Pencil stencils, icon templates

http://code.google.com/p/android-ui-utils/

Additional Eclipse plugins for Androidsorce code, api level analysishttp://code.google.com/p/adt-addons/

Maven Android pluginhttp://code.google.com/p/maven-android-plugin/

Page 52: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 52

Useful libraries and resources

Kernel sourceto learn, to get inspired and to solve bugs!

http://grepcode.com/snapshot/repository.grepcode.com/java/ext/com.google.android/android/2.3.4_r1/

Clean code in AndroidIoC, Binding, Annotation etc

http://blog.springsource.com/2011/08/26/clean-code-with-android

Crash reporthttp://androidblogger.blogspot.com/2010/03/crash-reporter-for-android-slight.html

Page 53: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 53

Useful libraries and resources

Use Apache HTTP library instead of Java.NetHttps bugs, bufferization problems, etchttp://code.google.com/p/android/issues/detail?id=3164

http://groups.google.com/group/android-developers/msg/4ddd2e502f195e3a http://stackoverflow.com/questions/2105364/

Be part of communitiesmailing list, StackOveflow, ...

http://developer.android.com/resources/community-groups.html

Page 54: Android Survival Guide - Two years of software development

Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 54

Conclusion

Q & A(example: “Isn't it lunch time yet?”)