Slide 1

Slide 1 text

Handling Android Networking (without going crazy)

Slide 2

Slide 2 text

Why do I care? ● Most Android apps need to talk to a server or somewhere on the Internet ● Data sync, user authentication, stream video, show ads, etc.

Slide 3

Slide 3 text

A bit about the UI thread ● Android apps run in a single threaded environment ● Long-running operations “block” the UI thread, causing lag / frustration / swearing ● As of API 11, Android won’t allow networking operations on the UI thread

Slide 4

Slide 4 text

What should I do? ● Spawn separate thread to handle any network calls ● Update the UI when complete ● UI elements (Views) must be updated on thread that created them (UI thread)

Slide 5

Slide 5 text

Network Threading Options ● java.lang.Thread ● AsyncTask ● IntentService

Slide 6

Slide 6 text

Example ● Download list of baseball players from a specified team, through a REST API ● Display player list to the user ● Assume we have Java client to talk to API

Slide 7

Slide 7 text

java.lang.Thread final int teamId = 21; new Thread(new Runnable() { @Override public void run() { ArrayList players = ApiClient. getInstance().getPlayerList( teamId); // send data to UI thread to update Message msg = new Message(); Bundle data = new Bundle(); data.putParcelableArrayList( "player_list" , players); msg.setData(data) ; mHandler.sendMessage(msg) ; } }).run();

Slide 8

Slide 8 text

java.lang.Thread ● Spawn separate thread for network request ● When completed send data back to UI thread to update ● Remember, View objects can only be updated on UI thread

Slide 9

Slide 9 text

AsyncTask new AsyncTask>(){ @Override protected List doInBackground (Integer... params) { int teamId = params[ 0]; return ApiClient.getInstance().getPlayerList(teamId) ; } @Override protected void onPostExecute (List players) { // this method runs on UI thread, so update list of players } }.execute(teamId) ;

Slide 10

Slide 10 text

AsyncTask ● doInBackground method runs on a separate thread, passes results to onPostExecute ● onPostExecute runs on UI thread, can update Views

Slide 11

Slide 11 text

AsyncTask ● Looks great, right? ● Try rotating your device...

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

AsyncTask Problems ● Activity is destroyed and recreated on rotation, so running AsyncTask tries to update views from old Activity ● AsyncTask.cancel() is broken ● Best used for very short tasks (< 1s)

Slide 14

Slide 14 text

IntentService FTW! public class PlayerListService extends IntentService { public static final String ACTION_PLAYER_LIST_DOWNLOADED = "com.test.network.ACTION_PLAYER_LIST_DOWNLOADED" ; public static final String EXTRA_PLAYER_LIST = "com.test.network.EXTRA_PLAYER_LIST" ; @Override protected void onHandleIntent (Intent intent) { List players = ApiClient. getInstance().getPlayerList(teamId) ; // Send results back to UI thread Intent i = new Intent(ACTION_PLAYER_LIST_DOWNLOADED); i.putParcelableArrayListExtra( EXTRA_PLAYER_LIST, players); LocalBroadcastManager. getInstance(this).sendBroadcast(i) ; } } // Start with intent from UI thread startService(new Intent(this, PlayerListService. class));

Slide 15

Slide 15 text

IntentService ● Runs on separate thread, override onHandleIntent() method ● Completely separate from Activity lifecycle, shuts down when work is complete ● Send data back to UI thread via Broadcast

Slide 16

Slide 16 text

Sending data to the UI Thread ● Primitive data types can be sent in message data bundle or as Intent extra ● Custom objects must implement Serializeable or Parcelable interfaces to be sent ● http://www.parcelabler.com/ to generate code

Slide 17

Slide 17 text

Sending data to the UI Thread ● Can also use ResultReceiver or an event bus to send data to UI thread ● Event Bus uses publisher/subscriber model, deliver events on bus to all subscribers ● Popular event buses include EventBus (greenrobot) or Otto (Square)

Slide 18

Slide 18 text

EventBus (greenrobot) // Event Class public class PlayerListEvent { private List players; public PlayerListEvent(List players) { this.players = players; } public List getPlayers() { return players; } } // Register in onCreate, onResume, onAttach, etc EventBus.getDefault().register( this); // Send Player list from IntentService EventBus.getDefault().post(new PlayerListEvent (players)); // Public method to which EventBus delivers event public void onEventMainThread (PlayerListEvent event) { mPlayers = event.getPlayers() ; // update UI... }

Slide 19

Slide 19 text

An Even Better Idea? ● Retrofit turns REST API calls into a Java interface and a series of async method calls ● Built on top of OkHttp (Java networking) and Okio (java.io replacement) ● http://square.github.io/retrofit/

Slide 20

Slide 20 text

Retrofit ● Define interface methods public interface SportsApi { @GET("/teams/{id}/players") void getPlayerList(@Path("id") int teamId, Callback> callback); } ● Handle method callbacks SportsApiClient.getInstance().getPlayerList(teamId, new Callback>() { @Override public void success(List players, Response response) { // called on main thread, update UI... } @Override public void failure(RetrofitError error) { // uh oh, there was a problem... } });

Slide 21

Slide 21 text

Summary ● No network calls on the UI thread! ● View objects must be updated from UI thread ● Android networking can be hard, but there are some great tools out there to help you

Slide 22

Slide 22 text

Questions?