Upload
lekhanh
View
218
Download
2
Embed Size (px)
Citation preview
Challenges
● Data connections are slow and unreliable
● CPU/Memory constraints
● Aggressive power management
● Touch UI accentuates performance issues
Basics
● Two networking APIs:○ Apache HttpClient○ HttpUrlConnection■ Recommended API for >2.2
● org.json.* for parsing JSON● XML Parsing○ org.xml.sax○ org.xmlpull - Android recommended
Helpful Libraries
● Parsing○ GSON - converts JSON to POJOs
● Networking○ AsyncHttp - abstracts async network
requests, returns JSON○ Volley - from Google, supports SPDY and
image loading○ OkHttp - from Square, mirrors Apache
HTTPClient API, supports SPDY
Battery Life
● Mobile devices achieve long battery life by
sleeping as much as possible
● Reduce battery consumption by:
○ Batching network activity
○ Sync only on WiFi or when charging
○ Coordinating syncing with other apps
● Use a wake lock to keep device awake
ConnectivityManager mgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = mgr.getActiveNetworkInfo();if (info != null && info.isConnected()) { // Good to go}
Detect active network
Detecting WiFi
NetworkInfo info = mgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (info != null && info.isConnected()) { // You’ve got WiFi}
Monitor changes in connectivity
● Register to receive android.net.conn.
CONNECTIVITY_CHANGE or android.net.wifi.
STATE_CHANGE
● Happens often, so disable when not needed
● BroadcastReceivers are short lived: start a
Service
Manifest example
<receiver android:name="com.example.xdacon.ConnectivityReceiver" android:enabled="true" > <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> </intent-filter></receiver>
BroadcastReceiver
public class ConnectivityReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) { ConnectivityManager mgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = mgr.getActiveNetworkInfo(); // Check connection and start networking... } }
Detecting charge state
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);Intent intent = context.registerReceiver(null, filter);
intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
Caching - File Cache
● Internal cache○ File file = Context.getCacheDir();○ Limited space○ Periodically flushed by the OS
● External cache○ File file = Context.getExternalCacheDir();
● Both caches are cleared when your app is uninstalled
● OSS Library: DiskLruCache
Caching - Database
● Use SqliteOpenHelper to manage DB○ Handles creation and versioning
● Use ContentProvider as interface to DB○ Thread safe○ Supports Loaders○ Works across apps○ Required by SyncAdapter
● OSS library: ProviGen
ContentProvider
@Overridepublic Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// query for a database cursor // ... return cursor;}
URIs
● Access a ContentProvider using a URI
● URIs are strings representing content. Like URLs.
○ Example: content://media/audio/artists/41
● Use path to refer to all items
○ Example: content://media/audio/artists/ for all
artists
ContentResolver
Uri uri = Uri.parse("content://com.example.xdacon/my_table/3");
ContentValues values = new ContentValues();values.put("my_int", 0);
context.getContentResolver().insert(uri, values);
Optimizing UI
● The Main Thread
○ Also called the UI Thread
○ All UI drawing is done on this thread
○ Also used for callbacks into your code
○ All interaction with the UI must be done by
the main thread
● DO NOT BLOCK THE MAIN THREAD
StrictMode
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); if (BuildConfig.DEBUG) StrictMode.enableDefaults(); }}
● Detects blocking of the Main Thread
● Can generate logs, dialogs, or crash your app
● Don’t run it in production
AsyncTask
public class MyAsyncTask extends AsyncTask<String, Integer, Void> {
@Overrideprotected Void doInBackground(String... params) {
// Long running operation...
publishProgress(progress);
return null;}
AsyncTask
@Overrideprotected void onPreExecute() { // Runs before doInBackground}
@Overrideprotected void onProgressUpdate(Integer... values) { // Runs after publishProgress}
@Overrideprotected void onPostExecute(Void result) { // Runs after doInBackground}
IntentService
● Inherits from Service
● Uses a Handler to run a background thread
● onHandleIntent - your code goes here
● Block as long as you wish
IntentService
public class ExampleIntentService extends IntentService {
public ExampleIntentService() { super("ExampleIntentService"); }
@Override protected void onHandleIntent(Intent intent) { // Runs on a background thread }}
Sending Data to Services
String url = "www.google.com";Intent intent = new Intent(this, ExampleService.class);intent.putExtra("url", url);startService(intent);
protected void onHandleIntent(Intent intent) { String url = intent.getStringExtra("url"); // connect to your web service}
Activ
itySe
rvic
e
Loaders
● Simplifies querying for data and displaying it
● Reloads when data changes
● Handles Activity lifecycle for you
● Comes in two flavors: AsyncTaskLoader and
CursorLoader
Loader Example
public class ExampleListActivity extends ListActivityimplements LoaderCallbacks<Cursor> {
CursorAdapter mAdapter;
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create adapter...
setListAdapter(mAdapter);getLoaderManager().initLoader(0, null, this);
}
// Rest of code...
Loader Example
@Overridepublic Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (id == 0) {return new CursorLoader(this, uri, projection,
selection, selectionArgs, sortOrder);}return null;
}
@Overridepublic void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
mAdapter.swapCursor(cursor);}
Syncing Data
● AlarmManager to schedule periodic sync
● Better: Use SyncAdapter to coordinate sync
with other apps
● Best: Use GCM to initiate sync only when new
data available
AlarmManager
● Schedule repeating alarms
○ Repeating vs. Inexact Repeating
● RTC vs ELAPSED_REALTIME
● Use WAKEUP to wake device from sleep
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);am.setInexactRepeating(AlarmManager.RTC_WAKEUP, t0, interval, pi);
SyncAdapter
● Synchronizes network access across apps● Optimizes power consumption based on
connection status● Includes retry and backoff logic● Can be set to run when data changes● Tutorial from Any.DO: http://udinic.wordpress.
com/2013/07/24/write-your-own-android-sync-adapter/
SyncAdapter Requirements
● ContentProvider
● AbstractAccountAuthenticator and bound
service
● AbstractThreadedSyncAdapter and bound
service
● XML files for authenticator and SyncAdapter
● Add all of above to AndroidManifest
AbstractAccountAuthenticator
public class Authenticator extends AbstractAccountAuthenticator {
public Bundle addAccount( AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {...}
public Bundle getAuthToken( AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {...}
// ...
AddAccount
public Bundle addAccount(...) { Intent intent = new Intent(mContext.get(), LoginActivity.class); intent.putExtra( AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); Bundle b = new Bundle(); b.putParcelable(AccountManager.KEY_INTENT, intent); return b;}
AccountAuthenticatorActivity
String authToken = ... // Get auth token from REST server
Bundle bundle = new Bundle();bundle.putString(AccountManager.KEY_ACCOUNT_NAME, userName);bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);bundle.putString(AccountManager.KEY_AUTHTOKEN, authToken);
final Account account = new Account(userName, accountType);mAccountManager.addAccountExplicitly(account, password, userData);
setAccountAuthenticatorResult(bundle);finish();
Bound Service
public class AuthenticatorService extends Service { private Authenticator mAuthenticator; @Override public void onCreate() { mAuthenticator = new Authenticator(this); } @Override public IBinder onBind(Intent intent) { return mAuthenticator.getIBinder(); }}
AbstractThreadedSyncAdapter
public class SyncAdapter extends AbstractThreadedSyncAdapter {
@Override public void onPerformSync( Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
// run network sync
}
// ...}
Manual Sync
Account account = new Account(userName, accountType);Bundle bundle = new Bundle();bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);ContentResolver.requestSync(account, authority, bundle);
SyncAdapter Gotchas
● New permissions
● Runs in a separate process
○ Reading preferences is difficult
● Beware sync settings
● Passwords are unencrypted
Where to get Help
● Android Training: http://developer.android.
com/training/index.html
● Android Source: https://github.
com/android/platform_frameworks_base
● My Book: http://www.peachpit.
com/androiduifundamentals
● Follow me on Twitter @jasonostrander
OSS Links
● Android Async Http: http://loopj.com/android-async-http/
● Volley: https://android.googlesource.com/platform/frameworks/volley
● Google-Gson: https://code.google.com/p/google-gson/
● OkHttp: http://square.github.io/okhttp/● Provigen: https://github.
com/TimotheeJeannin/ProviGen