Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Networking (Without Going Crazy)

Android Networking (Without Going Crazy)

Phil Shadlyn

August 13, 2015
Tweet

More Decks by Phil Shadlyn

Other Decks in Programming

Transcript

  1. 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.
  2. 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
  3. 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)
  4. 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
  5. java.lang.Thread final int teamId = 21; new Thread(new Runnable() {

    @Override public void run() { ArrayList<Player> 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();
  6. 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
  7. AsyncTask new AsyncTask<Integer , Void, List<Player>>(){ @Override protected List<Player> doInBackground

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

    results to onPostExecute • onPostExecute runs on UI thread, can update Views
  9. 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)
  10. 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<Player> 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));
  11. 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
  12. 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
  13. 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)
  14. EventBus (greenrobot) // Event Class public class PlayerListEvent { private

    List<Player> players; public PlayerListEvent(List<Player> players) { this.players = players; } public List<Player> 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... }
  15. 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/
  16. Retrofit • Define interface methods public interface SportsApi { @GET("/teams/{id}/players")

    void getPlayerList(@Path("id") int teamId, Callback<List<Player>> callback); } • Handle method callbacks SportsApiClient.getInstance().getPlayerList(teamId, new Callback<List<Player>>() { @Override public void success(List<Player> players, Response response) { // called on main thread, update UI... } @Override public void failure(RetrofitError error) { // uh oh, there was a problem... } });
  17. 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