android apps the right way
Upload: new-york-city-college-of-technology-computer-systems-technology-colloquium
Post on 14-Jul-2015
476 views
TRANSCRIPT
![Page 1: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/1.jpg)
![Page 2: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/2.jpg)
Isn’t Android just Java?
≠
![Page 3: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/3.jpg)
Hint: If you know Android well, put “Android” on your resume.
![Page 4: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/4.jpg)
Key Differences
• Heterogeneous device capabilities
• Limited system resources
• Background tasks periodically killed
• Apps “stack” Activities
• Events handled by the OS
• Background processing common
• Blocking in UI thread yields an ANR
• Homogeneous virtual machine
• Lots of CPU and memory
• Lots of battery power
• Apps run in a dispatch loop
• Events handled within the app
• Background processing unusual
• Blocking in UI events semi-OK.
![Page 5: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/5.jpg)
What happens when you get it wrong?
• Weird behavior when launching app• App doesn’t function when phone sleeps• Battery life and network issues• Now you can’t access locks.
![Page 6: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/6.jpg)
Common Pitfalls: Always Foreground
Problem: Android can kill background apps at any time to free resources.
Naïve solution #1: Ignore this.
“Why did I stop receiving{mail, notifications, cat pictures} from your app?”
“It was supposed to alert me when ____, but didn’t”
“My music stopped playing in the middle of a song”
xkcd.com/937
![Page 7: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/7.jpg)
When you know you’re doing it wrongBut don’t want to fix it
Can’t close this, ever… “…Or you’ll die in a car crash” So it kills your battery instead
![Page 8: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/8.jpg)
The Right Way
Android apps can be killed any time they’re in the background. Accept this.
“Two hands clap and there is a sound.
What is the sound of one hand?”
![Page 9: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/9.jpg)
The Right Way
Android will start your app again and restore its state when…
1. “Something interesting happens”, or2. The user launches it again from history
onRestoreInstanceState()The catch: you have to write
The catch: you have to tell it what’s interesting!
![Page 10: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/10.jpg)
Expressing Interest With Intents
PendingIntent
Intent
Intents will start your activity up again if it’s down.PendingIntents tell Android to send them when certain things happen.
![Page 11: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/11.jpg)
The Bad Way
package example;
import android.app.IntentService;import android.content.Intent;
import java.util.concurrent.TimeUnit;
/*** Prints out a message after 5 minutes - how not to do it.*/public class BadService extends IntentService {public BadService() {super("BadService");
}
@Override protected void onHandleIntent(Intent intent) {try {Thread.sleep(TimeUnit.MINUTES.toMillis(5));
} catch (InterruptedException e) {// Because this is really bad code, we also ignore interrupts.
}
System.out.println("Your eggs are ready!");}
}
![Page 12: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/12.jpg)
The Right Way: Use Intents to Wake Your App
package example;
import android.app.AlarmManager;import android.app.IntentService;import android.app.PendingIntent;import android.content.Context;import android.content.Intent;
import java.util.Calendar;
/*** Prints out a message after 5 minutes.*/public class GoodService extends IntentService {public GoodService() {super("GoodService");
}
public static void schedule(Context sender) {AlarmManager alarmManager = (AlarmManager) sender.getSystemService(Context.ALARM_SERVICE);Calendar alarmTime = Calendar.getInstance();alarmTime.add(Calendar.MINUTE, 5);
Intent startGoodService = new Intent(sender, GoodService.class);alarmManager.setExact(AlarmManager.RTC_WAKEUP, alarmTime.getTimeInMillis(),
PendingIntent.getService(sender, 0, startGoodService, 0));}
@Override protected void onHandleIntent(Intent intent) {System.out.println("Your eggs are ready!");
}}
![Page 13: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/13.jpg)
Common Pitfalls: Work on the UI Thread
Draw! Draw!
I have to find this file first!
The UI thread is busy responding to the user. Never distract it.
Jeff Miracola, Wizards of the Coast – “Frantic Search”
![Page 14: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/14.jpg)
The Bad Waypackage example;
import android.app.Activity;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.util.Log;
import java.io.InputStream;import java.net.URL;
/*** Displays a cat picture to the user, but crashes with a NetworkOnMainThreadException first.*/public class CatPictureActivity extends Activity {
@Overridepublic void onCreate(Bundle bundle) {super.onCreate(bundle);try {
drawCatPics();} catch (Exception e) {
Log.e(getClass().getName(), "I haz an exception :(", e);finish();
}}
private void drawCatPics() throws Exception {URL catApi = new URL("http://thecatapi.com/api/images/get");InputStream catStream = (InputStream) catApi.getContent();findViewById(R.id.cat_pics).setImageDrawable(Drawable.createFromStream(catStream, "Cats"));
}}
![Page 15: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/15.jpg)
The Right Way: AsyncTasks / Threadspackage example;
import …;
/*** Displays a cat picture to the user when the download finishes.*/public class CatPictureActivity extends Activity {@Overridepublic void onCreate(Bundle bundle) {super.onCreate(bundle);final ListenableFutureTask<Drawable> catDownloader = ListenableFutureTask.create(new CatCall());catDownloader.addListener(new Runnable() {@Override public void run() {try {findViewById(R.id.cat_pics).setImageDrawable(catDownloader.get());
} catch (Exception e) {Log.e(getClass().getName(), "I haz an exception :(", e);finish();
}}
}, Executors.newSingleThreadExecutor());}
private class CatCall implements Callable<Drawable> {@Override public Drawable call() throws Exception {URL catApi = new URL("http://thecatapi.com/api/images/get");InputStream catStream = (InputStream) catApi.getContent();return Drawable.createFromStream(catStream, "Cats");
}}
}
![Page 16: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/16.jpg)
Common Pitfalls: Assuming Network Reliabilitypackage example;
import …;
/*** Displays a cat picture to the user when the download finishes.*/public class CatPictureActivity extends Activity {@Overridepublic void onCreate(Bundle bundle) {super.onCreate(bundle);final ListenableFutureTask<Drawable> catDownloader = ListenableFutureTask.create(new CatCall());catDownloader.addListener(new Runnable() {@Override public void run() {try {findViewById(R.id.cat_pics).setImageDrawable(catDownloader.get());
} catch (Exception e) {Log.e(getClass().getName(), "I haz an exception :(", e);finish();
}}
}, Executors.newSingleThreadExecutor());}
private class CatCall implements Callable<Drawable> {@Override public Drawable call() throws Exception {URL catApi = new URL("http://thecatapi.com/api/images/get");InputStream catStream = (InputStream) catApi.getContent();return Drawable.createFromStream(catStream, "Cats");
}}
}
What if Wifi is down?
No cat pics :(
![Page 17: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/17.jpg)
The Right Way: Network State Intents
android.net.ConnectivityManager.CONNECTIVITY_ACTION
Android broadcasts an intent called
When the network state changes
and then you can check
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
// Cat pics, here we come!
}
![Page 18: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/18.jpg)
The Right Waypublic class CatPictureActivity extends Activity {
@Overridepublic void onCreate(Bundle bundle) {
super.onCreate(bundle);registerReceiver(new NetReceiver(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
private void setupTask() {final ListenableFutureTask<Drawable> catDownloader = ListenableFutureTask.create(new CatCall());catDownloader.addListener(new Runnable() {
@Override public void run() {try {
findViewById(R.id.cat_pics).setImageDrawable(catDownloader.get());} catch (Exception e) {
Log.e(getClass().getName(), "I haz an exception :(", e);finish();
}}
}, Executors.newSingleThreadExecutor());}
private class NetReceiver extends BroadcastReceiver {@Override public void onReceive(Context context, Intent intent) {
ConnectivityManager cm =(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();if (info != null && info.isConnected()) {
unregisterReceiver(this); // Prevents a second run if the network goes down.setupTask();
}}
}
private class CatCall implements Callable<Drawable> {@Override public Drawable call() throws Exception {
URL catApi = new URL("http://thecatapi.com/api/images/get");InputStream catStream = (InputStream) catApi.getContent();return Drawable.createFromStream(catStream, "Cats");
}}
}
![Page 19: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/19.jpg)
Summary
![Page 20: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/20.jpg)
Android is not Java
≠
![Page 21: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/21.jpg)
Your app is ephemeral
Use Intents, don’t try to keep it running
![Page 22: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/22.jpg)
Don’t block the UI thread
Do work asynchronously on another thread
![Page 23: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/23.jpg)
Check for connectivity
It can go up and down at any time
![Page 24: Android Apps the Right Way](https://reader036.vdocument.in/reader036/viewer/2022062406/55a525691a28abe50e8b468f/html5/thumbnails/24.jpg)
And if you know Android well, put it on your resume.