Vous êtes sur la page 1sur 107

Android in Action (part III)

Alexey Golubev, Dmitry Lukashev

What is the plan?

Java +Android
(basics) JVM, GC, Threads, SDK, NDK, Activity, Code style, etc.

Android UI
Layouts, ListView, Menu, Dialog, Widgets, Tips & tricks, etc.

Android in Action
Screen rotation, Memory analyze, AIDL, SAX, Debug, Wakelock, etc.

Part I

Part II

Part III

Agenda Debugging hints and tools Dealing with screen orientation Memory leaks analysis Working with Services Databases XML parsers Input methods, Search providers Battery life, wakelocks Flurry Publishing to Android Market

Agenda Debugging hints and tools Dealing with screen orientation Memory leaks analysis Working with Services Databases XML parsers Input methods, Search providers Battery life, wakelocks Flurry Publishing to Android Market

Debugging tools

Android Debug Bridge (ADB) Dalvik Debug Monitor Server (DDMS) Traceview logcat ADT plug-in DevTools SpareParts AXMLPrinter2

ADB

Install/Uninstall apps, port forwarding, scripting, files management Shell


$ adb -s emulator-5554 shell # sqlite3 /data/data/com.example.google.rss.rssexample/databases/rssitems.db SQLite version 3.3.12 Enter ".help" for instructions .... enter commands, then quit... sqlite> .exit

adb shell ls /system/bin adb kill-server

Monkey

Stress-test your application: generate pseudo-random streams of user events such as clicks, touches, or gestures, as well as a number of system-level events
$ adb shell monkey -p your.package.name -v 500

You can write your own script and execute thru telnet
press DPAD_CENTER sleep 4000 tap 290 40 sleep 1000 tap 290 40 sleep 500

You can even take screenshots thru command line


Monkey Demo

logcat
The priority is one of the following character values, ordered from lowest to highest priority: V Verbose (lowest priority) D Debug I Info W Warning E Error F Fatal S Silent (highest priority, on which nothing is ever printed)

adb logcat -b radio

DDMS

Threads info VM Heap info Allocation Tracker System info Emulator control Screen capture File Explorer

Demo

Performance Analysis: Traceview


In code:
Debug.startMethodTracing(path) // at /sdcard Debug.stopMethodTracing()

Using adb:
adb shell am profile com.gtug.project start /sdcard/filename adb shell am profile com.gtug.project stop

Impact performance!

<! AndroidManifest.xml //--> <application android:debuggable="true" ... />

Dev Tools

Account Tester Development Setting


Immediately destroy activities (test onSaveInstanceState()) Screen updates Running processes

Package Browser SyncTester

adb -e pull /system/app/Development.apk ./Development.apk adb -d install Development.apk

Spare Parts

Battery history Usage statistics

AXMLPrinter2

Converts Android binary XML to human-readable XML


http://code.google.com/p/android4me/downloads/list java -jar AXMLPrinter2.jar AndroidManifest.xml >> 1.txt
t 4 @ N Z x , 6 P d | : versionCode versionName icon label name minSdkVersion android *http://schemas.and roid.com/apk/res/android package manifes t com.yota.merge 1.0 application activity .MergeTest intent-filter action android.intent.action.M AIN category android.intent.category.LAUN CHER uses-sdk ` L <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.gtug.merge"> <application android:label="@7F040001" android:icon="@7F020000"> <activity android:label="@7F040001" android:name=".MergeTest"> <intent-filter> <action android:name="android.intent.action.MAIN"> </action> <category android:name="android.intent.category.LAUNCHER"> </category>

Agenda Debugging hints and tools Dealing with screen orientation Memory leaks analysis Working with Services Databases XML parsers Input methods, Search providers Battery life, wakelocks Flurry Publishing to Android Market

Screen Orientation: Default Behavior - Recreate


Start
onCreate(Bundle) onStart() onRestart()

onResume()

Running

foreground

foreground

onSaveInstanceState(Bundle) partly visible


onPause() Kill process no longer visible onStop()

Object onRetainNonConfigurationInstance()
onDestroy()

Stop

Screen Orientation: Dealing with recreate

Saving state variables:


onSaveInstanceState(Bundle) onRestoreInstanceState( Bundle)

Saving Activity data


Object onRetainNonConfigurationInstance() Object getLastNonConfigurationInstance()

Never save UI-dependent objects (even Adapters) using onRetainNonCofigurationInstance()!

Screen Orientation: Custom Behavior

onConfigurationChanged(Configuration) android.view. OrientationEventListener setContentView()


<activity android:configChanges=["mcc", "mnc", "locale", "touchscreen", "keyboard", "keyboardHidden", "navigation", "orientation", "fontScale"] android:screenOrientation=["unspecified" | "user" | "behind" | "landscape" | "portrait" | "sensor" | "nosensor"] ...</activity>

Agenda Debugging hints and tools Dealing with screen orientation Memory leaks analysis Working with Services Databases XML parsers Input methods, Search providers Battery life, wakelocks Flurry Publishing to Android Market

Screen Orientation The Fastest Way to Memory Leak

References to Activity/Service/Context
Avoid final, static and long-live references Use Application Context where possible

References to View, Drawable, Handlers


Any kind of View from findViewById stores whole ViewRoot Drawable callbacks

Register/unregister BroadcastReceivers Bind/unbind from Service


ServiceConnection AIDL Callbacks, RemoteCallbackList

Inner classes
Anonymous inner classes as class fields (ClickListeners)

Google issue #2423 (http://code.google.com/p/android/issues/detail?id=2423)

Memory Leaks demo

Memory Leaks Analysis: Debug Class

Activity.getInstanceCount() Debug
Binder transactions, dead objects, etc. Number of loaded classes setAllocationLimit(int) start/stopAllocationCounting()

Debug.getMemoryInfo(MemoryInfo)
Dalvik dirty pages Native dirty pages Other dirty pages

Memory Leaks Analysis: DDMS


Stand-alone DDMS in <android-sdk>/tools
NB: Only one DDMS instance should be launched Eclipse or stand-alone
Allocation Tracker

VM Heap
SysInfo -> Memory Usage

Memory Leaks Analysis: MAT

Stand-alone Memory Analyzer (MAT)


http://www.eclipse.org/mat/

Get memory dump using adb shell


$ adb shell chmod 777 /data/misc $ adb shell ps $ adb shell kill -10 [pid] $ adb pull /data/misc/heap-dump-tmXXX-pidXXX.hprof name.hprof

Convert hprof to Sun format Open new hprof dump in stand-alone Eclipse MAT
$ <android-sdk>/tools/hprof-conv name.hprof name4mat.hprof

Memory Analyzer demo

Agenda Debugging hints and tools Dealing with screen orientation Memory leaks analysis Working with Services Databases XML parsers Input methods, Search providers Battery life, wakelocks Flurry Publishing to Android Market

Interactions with Android Service

Context.start/stopService(Intent)
stopSelf()

Context.bind/unbindService()
Interaction AIDL interface

Permissions
checkCallingPermission(String)
<service android:exported=["true", "false"] android:permission="string" android:process="name".../>

Android Service Lifecycle


Started by bindService() startService()

onCreate() Kill process onStart() onBind() onLowMemory() Running with Running interactions onRebind()

stopSelf() or no onUnbind() callback

onDestroy()

Shut down

Android Service Lifecycle Extras (SDK 5)

onStartCommand()
Set:
START_FLAG_REDELIVERED START_FLAG_RETRY

Since platform 2.0!

Return:
START_STICKY_COMPATIBILITY START_STICKY START_NOT_STICKY START_REDELIVER_INTENT START_CONTINUATION_MASK

start/stopForeground()
With Notification

Android IPC, RPC & AIDL

IBinder interface

Defined by Android
Binder class

IPC InterProcess Communication RPC Remote Procedure Calls AIDL Android Interface Definition Language

Interface generated by the AIDL tool

Stub inner class

inner class used by Android

Defined by the application

Class that implements the interface


Used remotely
(by the Service)

AIDL definition
Used locally
(by clients of the Service)

Communicate with Android Service using IPC (1)

Service RemoteCallbackList<IMyCallback> IMyInterface.Stub

Activity
IMyInterface.aidl IMyCallback.aidl

ServiceConnection onServiceConnected()

onBind()

bindService()

mMyInterface = IMyInterface.Stub.asInterface(service); mMyInterface.registerCallback(cb);

onDestroy() onUnbind() unbindService()

onServiceDisconnected()
mMyInterface.unregisterCallback(cb); mMyInterface.unregisterCallback(cb);

Communicate with Android Service using IPC (2)


AIDL types restrictions:
Primitives String, CharSequence List, Map Other AIDL interfaces (import needed) Parcelable classes (import needed)

No Exceptions will be send back except RemoteException All IPC calls are synchronous Only methods, no fields

public void onCreate() { mCallbacks = new RemoteCallbackList<IMyCallback>(); } public void onDestroy() { mCallbacks.kill(); } IMyInterface.Stub { public void registerCallback(IMyCallback cb) { mCallbacks.register(cb); } public void unregisterCallback(IMyCallback cb) { mCallbacks.unregister(cb); }

private void notifyCallbacks(int data) { final int N = mCallbacks.beginBroadcast(); for (int i = 0; i < N; i++) { try { mCallbacks.getBroadcastItem(i).notify(data); } catch (RemoteException e) {} } mCallbacks.finishBroadcast(); }

Bundle, Parcel, Parcelable


Parcel
Primitives Active Objects IBinder Primitive Arrays[] IInterface Untyped Containers writeValue(Object) Object readValue()

ParcelFileDescriptor Parcelable

public class MyParcelable implements Parcelable {

Java Bundle key1 key2 key3 key4 key5 Value<int> Value<String> Value<ArrayList> Value<Parcelable> Value<Serializable>

int mData;

public static final Parcelable.Creator<MyParcelable> CREATOR


= new Parcelable.Creator<MyParcelable>() { public MyParcelable createFromParcel(Parcel in) {return new MyParcelable(in);} public MyParcelable[] newArray(int size) {return new MyParcelable[size];} }; private MyParcelable(Parcel in) {mData = in.readInt();} @Override public int describeContents() {return 0;} @Override public void writeToParcel(Parcel out, int flags) {out.writeInt(mData);}
}

...
AIDL

parcelable MyParcelable;

Agenda Debugging hints and tools Dealing with screen orientation Memory leaks analysis Working with Services Databases XML parsers Input methods, Search providers Battery life, wakelocks Flurry Publishing to Android Market

Databases (1)

Create database easily with SQLiteOpenHelper


private static class DatabaseHelper extends SQLiteOpenHelper { DatabaseHelper() { super(VKApplication.getAppContext(), DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE IF NOT EXISTS " + DATABASE_TABLE_FRIENDS + " (" + KEY_FRIEND_ID + " TEXT PRIMARY KEY," + KEY_FRIEND_NAME + " TEXT, + KEY_FRIEND_AVATAR + " TEXT, " + KEY_FRIEND_PHONE + " TEXT, " + KEY_FRIEND_EMAIL + " TEXT);"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE_FRIENDS); onCreate(db); }

}
mDb.query(DATABASE_TABLE_FRIENDS, null, null, null, null, null, null); //Cursor

Databases (2)

If you need DB on SD you should handle this on your own


String databasePath = Environment.getExternalStorageDirectory() + SLASH_DELIMITER + DATABASE_DIR + SLASH_DELIMITER + DATABASE_FILENAME; if (isSdMounted()) { try { mDb = SQLiteDatabase.openDatabase(databasePath, null, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.NO_LOCALIZED_COLLATORS); checkAndUpgradeDb(mDb); } catch (SQLiteException sqle) { File folder = new File(Environment.getExternalStorageDirectory() + SLASH_DELIMITER + DATABASE_DIR); if (!folder.exists()) { folder.mkdirs(); } mDb = SQLiteDatabase.openDatabase(databasePath, null, SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.NO_LOCALIZED_COLLATORS); db.execSQL(SQL_CREATE_DB); db.setVersion(DATABASE_VERSION); } } }

Lets Have a Break! 10 min

Agenda Debugging hints and tools Dealing with screen orientation Memory leaks analysis Working with Services Databases XML parsers Input methods, Search providers Battery life, wakelocks Flurry Publishing to Android Market

Work with XML in Android

SAX
org.xml.sax

Easier SAX
android.sax

DOM
javax.xml.parsers.DocumentBuilder

XML Pull (similar to StAX)


org.xmlpull.v1.XmlPullParser
SafeSaxTest.java in Git

SAX

Event-driven (faster parsering) Minimize memory footprints org.xml.sax.helpers.DefaultHandler


public class MyXmlHandler extends DefaultHandler{ @Override public void characters(char[] ch, int start, int length) throws SAXException {} @Override public void endElement(String uri, String localName, String name) throws SAXException {} @Override public void startDocument() throws SAXException {} @Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {} }

http://www.saxproject.org/

Easier SAX android.sax - a framework that makes it easy to write efficient and robust SAX handlers
RootElement root = new RootElement("rss"); final List<Message> messages = new ArrayList<Message>(); Element channel = root.getChild("channel"); Element item = channel.getChild(ITEM); item.setEndElementListener(new EndElementListener(){ public void end() { messages.add(currentMessage.copy()); } }); item.getChild(TITLE).setEndTextElementListener(new EndTextElementListener(){ public void end(String body) { currentMessage.setTitle(body); } }); try { Xml.parse(this.getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler()); } catch (Exception e) {} ElementListener EndElementListener EndTextElementListener StartElementListener TextElementListener

Element RootElement

DOM You require access to the entire document (XSLT) XML validation, random access
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); List<Message> messages = new ArrayList<Message>(); try { DocumentBuilder builder = factory.newDocumentBuilder(); Document dom = builder.parse(this.getInputStream()); Element root = dom.getDocumentElement(); NodeList items = root.getElementsByTagName(ITEM); for (int i=0;i<items.getLength();i++){ Message message = new Message(); Node item = items.item(i); NodeList properties = item.getChildNodes(); for (int j=0;j<properties.getLength();j++){ Node property = properties.item(j); String name = property.getNodeName(); if (name.equalsIgnoreCase(TITLE)){ message.setTitle(property.getFirstChild().getNodeValue()); } else if (){ } messages.add(message); } } catch (Exception e) { throw new RuntimeException(e); javax.xml.parsers.DocumentBuilder }

XML Pull (similar to StAX)

A median between tree based and event based approaches


List<Message> messages = null; XmlPullParser parser = Xml.newPullParser(); try { // auto-detect the encoding from the stream parser.setInput(this.getInputStream(), null); int eventType = parser.getEventType(); Message currentMessage = null; boolean done = false; while (eventType != XmlPullParser.END_DOCUMENT && !done){ String name = null; switch (eventType){ case XmlPullParser.START_DOCUMENT: messages = new ArrayList<Message>(); break; case XmlPullParser.START_TAG: name = parser.getName(); if (name.equalsIgnoreCase(ITEM)){ currentMessage = new Message(); } else if (currentMessage != null){ if (name.equalsIgnoreCase(LINK)){ currentMessage.setLink(parser.nextText()); } else if ()){ } } break;

case XmlPullParser.END_TAG: break; } eventType = parser.next(); } } catch (Exception e) { throw new RuntimeException(e); }

Agenda Debugging hints and tools Dealing with screen orientation Memory leaks analysis Working with Services Databases XML parsers Input methods, Search providers Battery life, wakelocks Flurry Publishing to Android Market

Input Method

Extend InputMethodService <intent-filter> and Settings Activity


onCreate

Candidates View

onCreateInput View()

onCreateCandid atesView()

onStartInputView()
Move to the next field

Input View

Edit text

onFinishInput () onDestroy ()
TYPE_CLASS_TEXT TYPE_CLASS_PHONE

Onscreen Input Modes

EditText attributes:
android:inputType android:inputMethod android:imeOptions android:imeActionId android:imeActionLabel

android:inputType="textEmailAddress"

Resize modes for Activity


android:windowSoftInputMode
["stateUnspecified ", "stateUnchanged", "stateHidden", "stateAlwaysHidden", "stateVisible", "stateAlwaysVisible", "adjustUnspecified, "adjustResize", "adjustPan"]

android:inputType="phone" android:imeOptions="actionSearch"

Search in Android (1)


Search
Invoke your search UI Type-to-search feature Invoke global/local search box Disable search

onSearchRequested(); setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); // search within your activity setDefaultKeyMode(DEFAULT_KEYS_SEARCH_GLOBAL); // search using platform global search @Override public boolean onSearchRequested() { return false; } @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); final Intent queryIntent = getIntent(); final String queryAction = queryIntent.getAction(); if (Intent.ACTION_SEARCH.equals(queryAction)) { } }

<intent-filter> <action android:name="android.intent.action.SEARCH" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />

Search in Android (2)

Global Search Box


<!-- Provides search suggestions for words and their definitions. --> <provider android:name="DictionaryProvider" android:authorities="dictionary" android:syncable="false" /> <searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/search_label" android:searchSettingsDescription="@string/settings_description" android:includeInGlobalSearch="true" android:searchSuggestAuthority="dictionary" android:searchSuggestIntentAction="android.intent.action.VIEW"> </searchable>

Agenda Debugging hints and tools Dealing with screen orientation Memory leaks analysis Working with Services Databases XML parsers Input methods, Search providers Battery life, wakelocks Flurry Publishing to Android Market

Coding for Battery Life

Why does this matter?


Each device has battery budget. When its gone, its gone. Apps need to work together to be good citizens of that shared resource

HTC G1
1340mAh

HTC Magic
1340mAh

Motorola Droid
1400mAh

Where does it all go?

Watching YouTube: 340mA = 3.4 hours Browsing 3G web: 225mA = 5 hours Airplane mode idle: 2mA = 24 days

Example

RSS feed reader (phone is in idle)


App wakes up every 10 minutes to update Takes about 8 seconds to update, 350mA Cost during a given hour:
3600 seconds * 5mA = 5mAh resting 6 times * 8 sec * 350mA = 4.6 mAh updating

Just one app waking up can trigger cascade Bulk data transfer 6MB song from:
EDGE (90kbps): 300mA * 9.1 min = 45 mAh 3G (300kbps): 210mA * 2.7 min = 9.5 mAh Wi-Fi (1Mbps): 330mA * 48 sec = 4.4 mAh

What developer can do? (1)

Networking

Respect users settings


NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); If(info == null ||!mConnectivityManager.getBackgroundDataSetting()){ return false; } Subscribe to android.net.conn.BACKGROUND_DATA_SETTING_CHANGED

Check network connection wait for 3G or Wi-Fi


int netType = info.getType(); int netSubtype = info.getSubtype(); if (netType == ConnectivityManager.TYPE_WIFI) { return info.isConnected(); } else if (netType == ConnectivityManager.TYPE_MOBILE && netSubtype == TelephonyManager.NETWORK_TYPE_UMTS && !mTelephony.isNetworkRoaming()) { return info.isConnected(); } else { return false; }

What developer can do? (2)

Networking

Use efficient data format and parser

What developer can do? (3)

Foreground apps

Be careful with Wakelocks


Wakelocks are costly
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag"); wl.acquire(); wl.release();

Pick lowest level possible, use specific timeouts Consider using android:keepScreenOn to ensure correctness

Use coarse network location, its much cheaper


GPS: 25 seconds * 140mA = 1mAh Network: 2 seconds * 180mA = 0.1mAh

Float math is expensive Produce less garbage

Accelerometer sensor: - Normal: 10mA (orientation) - Game: 80mA - Fastest: 90mA

GOOD Wakelock
@Override protected void onResume() { ... PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GTUG"); mWakeLock.acquire(); ... } @Override protected void onPause() { ... mWakeLock.release(); ... }

BAD Wakelock
@Override protected void onCreate(Bundle savedInstanceState) { ... PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GTUG"); mWakeLock.acquire(); ... } @Override protected void onDestroy() { ... mWakeLock.release(); ... }

Holding wakelock in background

GOOD hardware resource handling


@Override protected void onResume() { ... camera = Camera.open(); ... } @Override protected void onPause() { ... camera.release(); ... }

BAD hardware resource handling


@Override protected void onCreate(Bundle savedInstanceState) { ... camera = Camera.open(); ... } @Override protected void onDestroy() { ... camera.release(); ... }

Not releasing hardware resources

Debugging

adb bugreport >> 1.txt


analyse DUMP OF SERVICE power section analyse DUMP OF SERVICE media.camera section

adb shell dumpsys battery adb shell dumpsys batteryinfo adb shell dumpsys power

What developer can do? (4)

Background apps

Services should be short-lived; these arent daemons Trigger wake-up through AlarmManager
stopSelf() when finished
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, MyService.class); PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0); long interval = DateUtils.MINUTE_IN_MILLIS * 30; long firstWake = System.currentTimeMillis() + interval; am.setRepeating(AlarmManager.RTC, firstWake, interval, pendingIntent);

Update every 30 min Dont wake-up device

Start your service using <receiver> in manifest



<receiver android:name=".ConnectivityReceiver" Intent.ACTION_TIMEZONE_CHANGED, android:enabled="false"> ... ConnectivityManager.CONNECTIVITY_ACTION </receiver> Intent.ACTION_DEVICE_STORAGE_LOW ComponentName receiver = new ComponentName(context, Intent.ACTION_BATTERY_LOW ConnectivityReceiver.class); PackageManager pm = context.getPackageManager(); Intent.ACTION_MEDIA_MOUNTED pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

What developer can do? (5)

Background apps

Use setInexactRepeating()
Check current battery and network state before running full update
public void onCreate() { // Register for sticky broadcast and send default registerReceiver(mReceiver, mFilter); mHandler.sendEmptyMessageDelayed(MSG_BATT, 1000); } IntentFilter mFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { // Found sticky broadcast, so trigger update unregisterReceiver(mReceiver); mHandler.removeMessages(MSG_BATT); mHandler.obtainMessage(MSG_BATT, intent).sendToTarget(); } };

Agenda Dealing with screen orientation Memory leaks analysis Working with Services XML parser Databases

Input methods, Search providers Debugging hints and tools Battery life, wakelocks Flurry Publishing to Android Market

Mobile Analytics: Flurry, Motally, others

http://www.flurry.com/

http://www.motally.com/

Flurry

The easy way to analyze your application usage How to:


Register, obtain application KEY Set permissions Put FlurryAgent.jar in /libs Make calls from code
FlurryAgent.onEvent FlurryAgent.onError

public void onStart() { super.onStart(); FlurryAgent.onStartSession(this, "Y9QZANAAAAYZP32CGI44"); } public void onStop() { super.onStop(); FlurryAgent.onEndSession(this); }

Demo
http://www.flurry.com/

Agenda Dealing with screen orientation Memory leaks analysis Working with Services XML parser Databases

Input methods, Search providers Debugging hints and tools Battery life, wakelocks Flurry Publishing to Android Market

Signing your apps for Android Market (1)

Debug signature vs Private key signature Sign with the same certificate:
Application upgrade Run in the same process Data sharing through permissions

Debug certificate: Keystore name: "debug.keystore" Keystore password: "android" Key alias: "androiddebugkey" Key password: "android" CN: "CN=Android Debug,O=Android,C=US"

zipalign tool
zipalign -v 4 your_project_name-unaligned.apk your_project_name.apk

Eclipse export tool

Signing your apps for Android Market (2)

Before publishing dont forget:


Turnoff any Log Specify correct versionCode, versionName, min & target SDK versions Obtain Map key (http://code.google.com/android/add-ons/googleapis/mapkey.html) if you are using MapView Sign application with private key (a validity period ending after 22 October 2033)

Demo
http://market.android.com/publish

Android Market application on device

Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(mMarketUrl)); try { startActivity(intent); } catch (ActivityNotFoundException e) { // no market }

market://details?id=<packagename> market://search?q=pname:<package> market://search?q=pub:<Developer Name> market://search?q=<substring>

Devices without Android Market

Download .apk to SD card Check allow non-market applications setting Run Package Installer
int result = Settings.Secure.getInt(getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS, 0); if (result == 0) { // some dialog here } else { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(mLocalInstallationFileName)), application/vnd.android.package-archive"); startActivity(intent); finish(); } Intent intent = new Intent(); intent.setAction(Settings.ACTION_APPLICATION_SETTINGS); startActivity(intent);

Check for updates manually!

Install application from app memory


Download .apk to the app memory getAppContext().getCacheDir().getPath() Use out = getAppContext().openFileOutput(mFileName, Context.MODE_WORLD_READABLE); Run installation
File realFilePath = context.getFileStreamPath(mFileName); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(realFilePath), "application/vnd.android.package-archive"); context.startActivity(intent);

QR codes

http://qrcode.kaywa.com/ http://zxing.appspot.com/generator/ http://code.google.com/p/zxing/

ZXing Barcode Scanner


market://search?q=pname:com.google.zxing.client.android

We didnt tell you about

Sensor Location Media Testing and Instrumentation OpenGL Gestures (since SDK4) AccountManager (since SDK 5) SparseBooleanArray PorterDuffXfermode A lot more

Future reading
Application signing - http://developer.android.com/guide/publishing/appsigning.html Take screenshots through command line - http://android.amberfog.com/?p=168 Parsers in Adroid - http://www.ibm.com/developerworks/opensource/library/xandroid/index.html DEX decompiler - http://code.google.com/p/smali/

Recommended Blogs

http://android-developers.blogspot.com/ http://kohlerm.blogspot.com/ (Memory) http://jeremymanson.blogspot.com/ (Java) http://android.amberfog.com/ http://androidandme.com/ http://www.androidguys.com/ http://phandroid.com/

Partners

Contacts

Dmitry Lukashev
http://ru.linkedin.com/in/dmitrylukashev dmitry.lukashev@gmail.com

Alexey Golubev
http://ru.linkedin.com/in/golubevalexey goalstudio@gmail.com

Blog - http://android.amberfog.com/

Thank You!
Questions?

AudioTrack sample
public class AudioTrackSample implements Runnable { private static final int sBufferSize = 8000; private AudioTrack mTrack; private short mBuffer[]; private short mSample; class AudioTrackSample { mBuffer = new short[sBufferSize]; mTrack = new AudioTrack(STREAM_MUSIC, 44100, CHANNEL_OUT_MONO, ENCODING_PCM_16BIT, sBufferSize * 2, MODE_STREAM); mSample = 0; } public void run() { mTrack.play(); while(1) { // fill the buffer generateTone(mBuffer, sBufferSize); mTrack.write(mBuffer, 0, sBufferSize); } } public void generateTone(short [] data, int size) { for (int i = 0; i < size; i++) { pData[i] = mSample; mSample += 600; // ~400 Hz sawtooth }

AudioTrack JNI sample


public class JNISample implements Runnable { private static final int sBufferSize = 8000; private AudioTrack mTrack; private short mBuffer[] = new short[sBufferSize]; private int mSample; class JNISample { mBuffer = new short[bufferSize]; mTrack = new AudioTrack(STREAM_MUSIC, 44100, CHANNEL_OUT_MONO, ENCODING_PCM_16BIT, sBufferSize * 2, MODE_STREAM); mSample = 0; } public void run() { mTrack.play(); while(1) { // fill the buffer generateTone(mBuffer, sBufferSize); mTrack.write(mBuffer, 0, sBufferSize); } } static { System.loadLibrary(generate_tone); } public native int generateTone(short [] data, int size);

AudioTrack JNI sample (cont.)


jint Java_com_example_jnisample_JNISample_generateTone( JNIEnv *env, jobject thiz, jshortArray data, jint size) { if (size <= 0) { return ERR_NO_DATA; } // convert java short array to C pointer, pinning the array in memory pData = (short*) env->GetPrimitiveArrayCritical(data, NULL); if (!pData) { return ERR_NO_DATA; } // fill buffer with 16-bit PCM audio short sample = 0; for (int i = 0; i < size; i++) { pData[i] = sample; sample += 600; // ~400 Hz tone } // unpin the array env->ReleasePrimitiveArrayCritical(data, pData, 0); return SUCCESS; }

AudioRecord JNI sample


AudioRecord arec = null;

try { int buffersize = AudioRecord.getMinBufferSize(INPUT_FREQUENCY, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT) * 10;


int actualbuffersize = buffersize * 10; arec = new AudioRecord(MediaRecorder.AudioSource.MIC, INPUT_FREQUENCY, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, actualbuffersize); while (!stop) { int read = arec.read(audioBuffer, frameSize); if (stop) { break; } processBuffer(read); } } catch ... private native void processBuffer(int size) throws IOException;

Android 2.2 aka Froyo


Changes

New User Features - Keyboard Number pad and punctuation: swipe up from the keyboard to reveal two additional rows of keys. Change language: swipe left and right across the space bar will cycle the keyboard through any installed system languages.

New User Features Share internet connection

Portable Wi-Fi hotspot (can be shared with up to 8 devices) USB Tethering - using your phone as a modem via USB

New User Features Improved performance

Faster JavaScript in browser (V8 engine) Dalvik JIT Kernel Memory Management Boost (improved memory reclaim, faster app switching)

New User Features Misc (1)


Tips widget, fixed shortcuts to Phone and Browser Exchange support Improved Gallery and Camera New Android Market app: auto update/update all Copy/Past in E-mail application

New User Features Misc (2)


Drop-out menus in search Improved application manager Adobe Flash support (10.1 beta downloadable from Android Market)

New Platform Technologies

Media framework
New media framework (Stagefright) that supports local file playback and HTTP progressive streaming Continued support for OpenCore in Android 2.2

Bluetooth
Voice dialing over Bluetooth Ability to share contacts with other phones Support for Bluetooth enabled car and desk docks Improved compatibility matrix with car kits and headsets

2.6.32 kernel upgrade


HIGHMEM support for RAM >256MB SDIO scheduling and BT improvements

Whats new for developer?

Alexey brings gifts to Droid at Google IO 09

Cloud to Device Messaging Framework


It allows third-party application servers to send lightweight messages to their Android applications. C2DM makes no guarantees about delivery or the order of messages An application on an Android device doesnt need to be running to receive messages

http://code.google.com/android/c2dm/

Android Application Error Reports

Automatic crash reports Statistics available at Android Market Management console

android.app.admin

Public interface for managing policies enforced on a device


<uses-policies> <limit-password /> <watch-login /> <reset-password /> <force-lock /> <wipe-data /> </uses-policies>
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/ap p/DeviceAdminSample.html

android.app.backup

Perform backup of arbitrary data to remote storage Easily perform backup of SharedPreferences and files Restore the data saved to remote storage
http://developer.android.com/guide/topics/data/backup.html New bmgr tool for testing http://developer.android.com/guide/developing/tools/bmgr.html

android.os

DropBoxManager
Enqueues chunks of data. You can think of this as a persistent, systemwide, blob-oriented "logcat". DropBoxManager entries are not sent anywhere directly, but other system services and debugging tools may scan and upload entries for processing

RecoverySystem
RecoverySystem contains methods for interacting with the Android recovery system (the separate partition that can be used to install system updates, wipe user data, etc.)

android.app

SearchableInfo Searchability meta-data for an activity. Only applications that search other applications should need to use this class
http://developer.android.com/guide/topics/search/searchable-config.html

UiModeManager This class provides access to the system uimode services It provides functionality to disable the car mode and it gives access to the night mode setting

android.content

DialogInterface.OnShowListener
Interface used to allow the creator of a dialog to run some code when the dialog is shown

Entity and EntityIterator


A representation of a item using ContentValues. Useful in Contacts

PeriodicSync
Value type that contains information about a periodic sync

SyncInfo
Information about the sync operation that is currently underway

android.media AudioManager.OnAudioFocusChangeListener MediaScannerConnection.OnScanCompletedListener SoundPool.OnLoadCompleteListener CamcorderProfile


The CamcorderProfile class is used to retrieve the predefined camcorder profile settings for camcorder applications. These settings are read-only.

CameraProfile
The CameraProfile class is used to retrieve the pre-defined still image capture (jpeg) quality levels (0-100) used for low, medium, and high quality settings in the Camera application.

ThumbnailUtils
Thumbnail generation routines for media provider.

android.net and android.net.http SSLSessionCache


File-based cache of established SSL sessions. This is a persistent cache which can span executions of the application

TrafficStats
Class that provides network traffic statistics. These statistics include bytes transmitted and received and network packets transmitted and received, over all interfaces, over the mobile interface, and on a per-UID basis.

AndroidHttpClient
Subclass of the Apache DefaultHttpClient that is configured with reasonable default settings and registered schemes for Android

SslError
One or more individual SSL errors and the associated SSL certificate

android.view and android.gesture

ScaleGestureDetector ScaleGestureDetector.OnScaleGestureListener ScaleGestureDetector.SimpleOnScaleGestureListener GestureUtils


Utility functions for gesture processing & analysis feature extraction (e.g., samplers and those for calculating bounding boxes and gesture path lengths); geometric transformation (e.g., translation, rotation and scaling); gesture similarity comparison (e.g., calculating Euclidean or Cosine distances between two gestures).

android.graphics and android.opengl

ImageFormat YuvImage New APIs for OpenGL ES 2.0, working with YUV image format, and ETC1 for texture compression.
ETC1 ETC1Util ETC1Util.ETC1Texture GLES20

android.widget

HeterogeneousExpandableList
Different view types for group items getGroupType(int groupPosition) getGroupTypeCount() getChildTypeCount() getChildType(int groupPosition, int childPosition)

android.speech

RecognitionListener
Used for receiving notifications from the SpeechRecognizer when the recognition related events occu

RecognitionService and RecognitionService.Callback


This class provides a base class for recognition service implementations This class should be extended only in case you wish to implement a new speech recognizer

SpeechRecognizer
This service allows access to the speech recognizer

Other
android.hardware Camera.OnZoomChangeListener android.webkit ConsoleMessage ConsoleMessage.MessageLevel WebSettings.PluginState android.test.mock MockContentProvider MockCursor android.text.style LeadingMarginSpan.LeadingMarginSpan2 android.util Base64 Base64InputStream Base64OutputStream EventLog EventLog.Event Patterns

Thank You!

Vous aimerez peut-être aussi