Académique Documents
Professionnel Documents
Culture Documents
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
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
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)
DDMS
Threads info VM Heap info Allocation Tracker System info Emulator control Screen capture File Explorer
Demo
Using adb:
adb shell am profile com.gtug.project start /sdcard/filename adb shell am profile com.gtug.project stop
Impact performance!
Dev Tools
Spare Parts
AXMLPrinter2
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
onResume()
Running
foreground
foreground
Object onRetainNonConfigurationInstance()
onDestroy()
Stop
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
References to Activity/Service/Context
Avoid final, static and long-live references Use Application Context where possible
Inner classes
Anonymous inner classes as class fields (ClickListeners)
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
VM Heap
SysInfo -> Memory Usage
Convert hprof to Sun format Open new hprof dump in stand-alone Eclipse MAT
$ <android-sdk>/tools/hprof-conv name.hprof name4mat.hprof
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
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".../>
onCreate() Kill process onStart() onBind() onLowMemory() Running with Running interactions onRebind()
onDestroy()
Shut down
onStartCommand()
Set:
START_FLAG_REDELIVERED START_FLAG_RETRY
Return:
START_STICKY_COMPATIBILITY START_STICKY START_NOT_STICKY START_REDELIVER_INTENT START_CONTINUATION_MASK
start/stopForeground()
With Notification
IBinder interface
Defined by Android
Binder class
IPC InterProcess Communication RPC Remote Procedure Calls AIDL Android Interface Definition Language
AIDL definition
Used locally
(by clients of the Service)
Activity
IMyInterface.aidl IMyCallback.aidl
ServiceConnection onServiceConnected()
onBind()
bindService()
onServiceDisconnected()
mMyInterface.unregisterCallback(cb); mMyInterface.unregisterCallback(cb);
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(); }
ParcelFileDescriptor Parcelable
Java Bundle key1 key2 key3 key4 key5 Value<int> Value<String> Value<ArrayList> Value<Parcelable> Value<Serializable>
int 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)
}
mDb.query(DATABASE_TABLE_FRIENDS, null, null, null, null, null, null); //Cursor
Databases (2)
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
SAX
org.xml.sax
Easier SAX
android.sax
DOM
javax.xml.parsers.DocumentBuilder
SAX
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 }
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
Candidates View
onCreateInput View()
onCreateCandid atesView()
onStartInputView()
Move to the next field
Input View
Edit text
onFinishInput () onDestroy ()
TYPE_CLASS_TEXT TYPE_CLASS_PHONE
EditText attributes:
android:inputType android:inputMethod android:imeOptions android:imeActionId android:imeActionLabel
android:inputType="textEmailAddress"
android:inputType="phone" android:imeOptions="actionSearch"
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" />
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
HTC G1
1340mAh
HTC Magic
1340mAh
Motorola Droid
1400mAh
Watching YouTube: 340mA = 3.4 hours Browsing 3G web: 225mA = 5 hours Airplane mode idle: 2mA = 24 days
Example
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
Networking
Networking
Foreground apps
Pick lowest level possible, use specific timeouts Consider using android:keepScreenOn to ensure correctness
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(); ... }
Debugging
adb shell dumpsys battery adb shell dumpsys batteryinfo adb shell dumpsys power
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);
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
http://www.flurry.com/
http://www.motally.com/
Flurry
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
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
Demo
http://market.android.com/publish
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(mMarketUrl)); try { startActivity(intent); } catch (ActivityNotFoundException e) { // no 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);
QR codes
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
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 }
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.
Portable Wi-Fi hotspot (can be shared with up to 8 devices) USB Tethering - using your phone as a modem via USB
Faster JavaScript in browser (V8 engine) Dalvik JIT Kernel Memory Management Boost (improved memory reclaim, faster app switching)
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
http://code.google.com/android/c2dm/
android.app.admin
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
PeriodicSync
Value type that contains information about a periodic sync
SyncInfo
Information about the sync operation that is currently underway
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.
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
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
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!