$30 off During Our Annual Pro Sale. View Details »

Android Best Practices

Android Best Practices

Android Best Practices


April 26, 2015

More Decks by jmortegac

Other Decks in Programming


  1. Android Best Practices José Manuel Ortega DroidCon July 2014

  2. https://techfest.uc3m.es/programa/android-in-practice/


  4. UI Design  http://developer.android.com/design/index.html Ways to specify the size of

    an item:  dp/dip: Density independent pixel.  sp/sip: Scale independent pixel.Used in font sizes.  pt: Point.  px: Pixel. Not use  layout_width,layout_height  match_parent:takes all the space available.  wrap_content: uses the space needed  fill_parent:equivalent to match_parent
  5. Android Asset Studio  Generate icons and graphic elements for

    each resolution  http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html
  6. Resources /Screen support  External elements you want to include

    and reference in the application.  Declaratively include in /res ,accesing by @<type>/<nname>  Are programmatically accessible via the R class (compiled with Android Asset Packaging Tool)  Android automatically selects the resource that adapts to the environment  Each resource type in a folder / res.  drawable: Images, Icons.  layout: Layout to organize views.  values:  string.xml: Text strings  colors.xml  dimens.xml: font sizes,margins,paddings  anim: Animations  raw: Other resources like audio or video  menu: Menus and dialogs  xml: Other xml (preferences, app widget, …) <supports-screens android:anyDensity="true" android:xlargeScreens="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true" />
  7. Includes / Reusing layouts

  8. Styles <!-- estilo para TextView --> <style name="CodeStyleTextView" parent="@android:style/TextAppearance.Medium"> <item

    name="android:layout_width">match_parent</item> <item name="android:layout_height">wrap_content</item> <item name="android:paddingTop">50dp</item> <item name="android:textColor">@color/negro</item> <item name="android:background">@color/gris_claro</item> <item name="android:textSize">35sp</item> </style> <!-- estilo para Button--> <style name="CodeStyleButton" parent="android:Widget.Button"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">wrap_content</item> <item name="android:textSize">20sp</item> <item name="android:drawableTop">@drawable/logo_empresa</item> </style>
  9. Styles <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/info_empresa" style="@style/CodeStyleTextView" /> <Button android:id="@+id/btnChangeImage" android:layout_width="match_parent"

    android:layout_height="wrap_content" android:text="@string/cambiar_imagen_fondo" style="@style/CodeStyleButton" />
  10. Action Bar Search View

  11. Action Bar Search View @Override public boolean onCreateOptionsMenu(Menu menu) {

    mSearchView = (SearchView) searchItem.getActionView(); mSearchView.setQueryHint("Search..."); mSearchView.setOnQueryTextListener(this); return true; } <item android:id="@+id/action_search" android:showAsAction="always" android:title="@string/search" android:icon="@android:drawable/ic_menu_search" android:actionViewClass= "android.support.v7.widget.SearchView" /> private SearchView mSearchView;
  12. Action Bar Search View  Implement interface OnQueryTextListener  Override

    methods onQueryTextSubmit, onQueryTextChange @Override public boolean onQueryTextSubmit(String query) { UniversityListFragment fragmentList = (UniversityListFragment)getSupportFragmentManager().findFragmentBy Tag("list_fragment"); fragmentList.searchData(query); return true; } @Override public boolean onQueryTextChange(String query) { return true; }
  13. ACTION BAR PROGRESS  Avoid modal Dialogues and Activities 

    Always update the user on progress(ProgressBar and ProgressDialog)  Render the main view and fill in data as it arrives
  14. ACTION BAR PROGRESS  Progress bar in Action Bar while

    url loading private Activity activity = this; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.getWindow().requestFeature(Window. FEATURE_INDETERMINATE_PROGRESS); ActionBar ab = getSupportActionBar(); ……… } activity.setProgressBarIndeterminateVisibility(true); viewer.setWebViewClient(new WebViewClient() { public void onPageFinished(WebView view, String url) { activity.setProgressBarIndeterminateVisibility(false); }  Show the progress bar to start loading and hide when finished.
  15. Accessibility / TalkBack

  16. Accessibility http://developer.android.com/training/accessibility/index.html <Button android:id="@+id/button" android:src="@drawable/button" android:contentDescription="@string/text_description"/>  Through layout 

    Through code label.setContentDescription(getText(R.string.text_description));  Focus navigation. Next view to receive focus when user navigates <EditText android:id="@id/editText" android:layout_alignBottom="@+id/button" android:layout_toLeftOf="@id/button" android:nextFocusUp="@+id/button" android:nextFocusDown="@+id/button" android:nextFocusLeft="@+id/button" android:nextFocusRight="@+id/button" android:nextFocusForward="@+id/button"/>
  17. Network connection import android.net.ConnectivityManager; import android.net.NetworkInfo; ConnectivityManager connectivityManager; connectivityManager =

    (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); Boolean connected = networkInfo != null && networkInfo.isAvailable() && networkInfo.isConnected(); <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  18. Network connection  Enable Wifi / Check connection type NetworkInfo

    wifiInfo=connectivityManager.getNetworkInfo (ConnectivityManager.TYPE_WIFI); NetworkInfo mobileInfo = connectivityManager.getNetworkInfo (ConnectivityManager.TYPE_MOBILE); if(wifiInfo.isConnected()){ Toast.makeText(context, "Wifi is connected", Toast.LENGTH_LONG).show(); } if(mobileInfo.isConnected()){ Toast.makeText(context, "3G/4G is connected", Toast.LENGTH_LONG).show(); } WifiManager wifiManager=(WifiManager) context.getSystemService(Context.WIFI_SERVICE); wifiManager.setWifiEnabled(true); <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
  19. Network connection  HTTP Request HttpGet httpGet = new HttpGet("http://www.google.com");

    HttpParams httpParameters = new BasicHttpParams(); int timeoutConnection = 3000; HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); int timeoutSocket = 5000; HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters); try { Log.d("isNetworkAvailable", "Checking network connection..."); httpClient.execute(httpGet); Log.d("isNetworkAvailable", "Connection OK"); return true; } catch (ClientProtocolException e) {e.printStackTrace(); } catch (IOException e) {e.printStackTrace(); } return false;
  20. Responsive Avoid ANR(Application Not Responding) No response to an input

    event (such as key press or screen touch events) within 5 seconds. Do not block the main UI thread with heavy work Web Service call, Http Request Communication with UI Thread is made with: • Thread / Handler • ThreadPoolExecutor • AsyncTask  Goal of AsyncTask is to take care of thread management for you.
  21. Asynctask  This class will allow us to perform background

    tasks without using neither directly nor Handlers Threads, trying these elements in a fully transparent way to the programmer.  When we define a AsyncTask class must define the type of three elements, the input parameters, its progress and outcome.  Override onPreExecute(),doInBackground(),onPostExecute(),onProgressUpdate() class RequestTask extends AsyncTask<String, String, String>{ @Override protected void onPreExecute() { } @Override protected void onProgressUpdate(Integer... values) { } @Override protected String doInBackground(String... uri) { } @Override protected void onPostExecute(String result) { super.onPostExecute(result); } new RequestTask().execute(url);
  22. Services  Perform the activity in an AsyncTask.  Kill

    the service when the task is complete.  Leaving a service running when it’s not needed is one of the worst memory management mistakes an Android app can make.  Service problem is always execute in main thread.  The best way to limit the lifespan of your service is to use an IntentService, which finishes itself as soon as it's done handling the intent that started it.  IntentService always execute in own thread.  Allows to launch a service in a new thread, avoiding blocking the main thread.  Example:ActivityRecognitionService
  23. Fragments  A fragment represents a certain behavior or a

    portion of a user interface activity.  Multiple fragments can be combined.  A fragment must always be part of an activity.  They emerged to provide greater flexibility to build the user interface  Override methods @Override //called when finish onCreate method in activity public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onCreate(Bundle savedInstanceState) {//inicializar componentes super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { } http://developer.android.com/guide/components/fragments.html
  24. Fragments  Add a fragment to view  by layout

    xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment class="com.proyecto.spaincomputing.fragment.UniversidadesFragment" android:id="@+id/FrgListado" android:layout_width="375dp" android:layout_height="match_parent"/> <fragment class="com.proyecto.spaincomputing.fragment.FragmentDetalle" android:id="@+id/FrgDetalle" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
  25. Fragments  Add a fragment to view  By code

    //Fragments array Fragment[] fragments = new Fragment[]{new PortadaFragment(), new UniversityListFragment(),new UniversidadesImagesFragment()}; FragmentManager manager = getSupportFragmentManager(); manager.beginTransaction() .add(R.id.contentFrame, fragments[0]) .add(R.id.contentFrame, fragments[1]) .add(R.id.contentFrame, fragments[2]) .commit(); //show/hide manager.beginTransaction().show(fragments[0]).commit(); manager.beginTransaction().hide(fragments[1]).commit(); manager.beginTransaction().hide(fragments[2]).commit();
  26. Fragments/ Master-detail PORTRAIT LANDSCAPE

  27. Fragments/ Master-detail PORTRAIT LANDSCAPE

  28. Fragments/ Master-detail  2 layout  layout\fragment_universidades_list.xml <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout>
  29. Fragments/ Master-detail  2 layout  layout-land\fragment_universidades_list.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent" android:layout_height="match_parent" android:baselineAligned="false" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="horizontal" tools:context=".TabsActivity" > <ListView android:id="@+id/listView" android:layout_width="0px" android:layout_height="wrap_content" android:layout_weight="1.5"> </ListView> <fragment android:id="@+id/fragmentUniversidadInfo" android:name="com.proyecto.spaincomputing.fragment.UniversidadInfoFragment" android:layout_width="0px" android:layout_height="wrap_content" android:layout_weight="4" tools:layout="@layout/fragment_universidad_info" /> </LinearLayout>
  30. Fragments/ Master-detail  Check orientation to display the detail page

    UniversidadBean ub=listado.get(position); if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { FragmentManager manager = getActivity().getSupportFragmentManager(); UniversidadInfoFragment fragment = (UniversidadInfoFragment) manager.findFragmentById(R.id.fragmentUniversidadInfo); fragment.loadWebViewContent(ub.getEnlace()); getActivity().invalidateOptionsMenu(); } else { Intent intent = new Intent(getActivity().getApplicationContext(), UniversityDetailActivity.class); intent.putExtra(UniversityDetailActivity.URL, ub.getEnlace()); url=ub.getEnlace(); intent.putExtra(UniversityDetailActivity.UNIVERSIDAD, ub.getNombre()); startActivity(intent); }
  31. Navigation patterns  Navigation drawer  View Pager  Tabs

    navigation in Action Bar actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);  Drop-down Navigation in Action Bar actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);  NavUtils in library support <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
  32. Navigation Drawer  http://developer.android.com/training/implementing-navigation/nav- drawer.html

  33. View Pager http://developer.android.com/intl/es/training/animation/screen-slide.html

  34. Tabs navigation in Action bar http://developer.android.com/intl/es/guide/topics/ui/actionbar.html#Tabs

  35. Drop-down navigation in Action bar http://developer.android.com/intl/es/guide/topics/ui/actionbar.html#Dropdown

  36. NavUtils import android.support.v4.app.NavUtils; NavUtils.navigateUpTo(this, new Intent(this, ListadoActivity.class)); http://developer.android.com/design/patterns/navigation.html Intent intent

    = NavUtils.getParentActivityIntent(this); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP); NavUtils.navigateUpTo(this, intent); NavUtils.navigateUpFromSameTask(this); <activity android:name=".DetalleUniversidadActivity" android:parentActivityName=".ListadoActivity" <!-- Parent activity meta-data to support 4.0 and lower --> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".ListadoActivity" /> </activity>
  37. Singleton  Application class <application android:allowBackup="true" android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/Theme.Styled" android:name=

    "com.proyecto.spaincomputing.singleton.MySingleton"> public class MySingleton extends Application { private static MySingleton instance; public static Context context; public static MySingleton getInstance(Context context){ if (instance == null) { // Create the instance instance = new MySingleton(context.getApplicationContext()); } return instance; } @Override public void onCreate() { super.onCreate(); context = getApplicationContext(); }}
  38. Adapter Pattern  Link between the source data and the

    view  It works with ListView or GridView  There are many types of adapter  You can perform a custom adapter  The most used ArrayAdapter / CursorAdapter  The Adapter interacts with a collection of data objects for display in View ArrayList<UniversidadBean> listado=newArrayList<UniversidadBean>(); private ListView lstListado; lstListado=(ListView)getView().findViewById (R.id.LstListado); lstListado.setAdapter (new UniversidadAdapter(this,listado));
  39. View Holder/View Container Pattern  ViewContainer static class ViewContainer{ public

    ImageView imagen; public TextView nombre; public TextView descripcion; }  Improve the performance of listview  The viewholder is used to avoid calling findViewById whenever prompted a new row to the adapter. Thus, instead of calling findViewById each time you use the references to the fields you have stored in the viewholder.  This pattern will help us to limit the number of calls to findViewById method. The idea would be to call it once, and then save the view daughter that refers to the instance of ViewHolder to be associated with the object by the method convertView View.setTag ()  Its recommend using a static class to store the items of each row in the view, functioning as a kind of cache for our view.
  40. View Holder/View Container Pattern @Override public View getView(int position, View

    convertView,ViewGroup parent) { ViewContainer viewContainer; //si es la primera vez que se imprime la fila if(convertView==null){ LayoutInflater inflater = context.getLayoutInflater(); convertView = inflater.inflate(R.layout.row, null,true); //crea una vista para el objeto contenedor viewContainer=new ViewContainer() //obtiene una referencia a todas las vistas de la fila viewContainer.nombre=(TextView)convertView.findViewById(R.id.textView_superior); viewContainer.descripcion=(TextView)convertView.findViewById(R.id.textView_inferior); viewContainer.imagen=(ImageView)convertView.findViewById(R.id.imageView_imagen); //asigna el contenedor de la vista a rowView convertView.setTag(viewContainer); }else{ viewContainer=(ViewContainer) convertView.getTag(); //recicling } //personaliza el contenido de cada fila basándone en su posición viewContainer.nombre.setText(listado.get(position).getNombre()); viewContainer.descripcion.setText(listado.get(position).getDescripcion()); viewContainer.imagen.setImageResource(listado.get(position).getIdImagen()); return(convertView); }
  41. View Holder/View Container Pattern  Debug

  42. Criteria Geolocation  LocationManager / android.location package  ACCESS_COARSE_LOCATION/ACCESS_FINE_LOCATION //Obtain

    Location Manager LocationManager locationManager = (LocationManager)this.getSystemService (Context.LOCATION_SERVICE); Criteria criteria = new Criteria(); //criteria.setAccuracy(Criteria.ACCURACY_FINE); //GPS criteria.setAccuracy(Criteria.ACCURACY_COARSE); // WIFI criteria.setPowerRequirement(Criteria.POWER_LOW); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setSpeedRequired(false); criteria.setCostAllowed(false); String provider = locationManager.getBestProvider(criteria, true); // In order to make sure the device is getting the location, request // updates [wakeup after changes of: 5 sec. or 10 meter] locationManager.requestLocationUpdates(provider, 5, 10, this); locationBridge.setNewLocation(locationManager.getLastKnownLocation(provider ));
  43. Obtain user moving  LocationListener onLocationChanged()  Activity Recognition API

    <uses-permission android:name="com.google.android- gms.permission.ACTIVITY_RECOGNITION"/> <service android:name="ActivityRecognitionService"/> IntentFilter filter = new IntentFilter(); filter.addAction("com.example.myactivityrecognition.ACTIVITY_RECOGNITION_ DATA"); registerReceiver(receiver, filter);  Register broadcast receiver on activity
  44. Obtain user moving / ActivityRecognitionService public class ActivityRecognitionService extends IntentService

    { @Override protected void onHandleIntent(Intent intent) { if(ActivityRecognitionResult.hasResult(intent)){ ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent); Intent i = new Intent("com.example.myactivityrecognition.ACTIVITY_RECOGNITION_DATA"); i.putExtra("Activity", getType(result.getMostProbableActivity().getType()) ); i.putExtra("Confidence", result.getMostProbableActivity().getConfidence()); sendBroadcast(i); } } private String getType(int type){ if(type == DetectedActivity.UNKNOWN) return "Unknown"; else if(type == DetectedActivity.IN_VEHICLE) return "In Vehicle"; else if(type == DetectedActivity.ON_BICYCLE) return "On Bicycle"; else if(type == DetectedActivity.ON_FOOT) return "On Foot"; else return ""; } }
  45. Performance / Save Battery life  Useful for background tracking

    applications  Use “PASSIVE_PROVIDER” LocationProvider (instead of “GPS_PROVIDER”)  LocationListener has three primary settings: “provider” positioning technology (e.g. GPS, NETWORK) “minTime” requested time (milliseconds) between location updates “minDistance” requested distance (m) that triggers updates if (user_moving){ -Decrease LocationListener “minTime” } else{ if(Stopped for a reasonable amount of time){ -Increase LocationListener “minTime” } }
  46. Performance /Instruction count Debug.InstructionCount icount =new Debug.InstructionCount(); icount.resetAndStart(); ………. if(icount.collect()){

    Log.d("DEBUG","Total instructions executed"+icount.globalTotal()); Log.d("DEBUG","Method invocations"+icount.globalMethodInvocations()); }
  47. DEPENDENCY INYECTION  RoboGuice / Dagger / ButterKnife  RoboGuice

    is a framework that brings the simplicity and ease of Dependency Injection to Android. public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); name = (TextView) findViewById(R.id.name); myName = getString(R.string.app_name); name.setText("Hello, " + myName); } @ ContentView(R.layout.main) class MyActivity extends RoboActivity{ @InjectView(R.id.name) TextView name; @InjectView(R.id.thumbnail) ImageView thumbnail; @InjectResource(R.drawable.icon) Drawable icon; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); name.setText("Hello, " + myName); }}
  48. ButterKnife  Eliminate findViewById calls by using @InjectView  Eliminate

    anonymous inner-classes for listeners by annotating methods with @OnClick class ExampleActivity extends Activity { @InjectView(R.id.name) EditText name; @OnClick(R.id.submit) void submit() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ButterKnife.inject(this); } } https://github.com/JakeWharton/butterknife
  49. Annotations @EActivity(R.layout.translate) // Sets content view to R.layout.translate public class

    TranslateActivity extends Activity { @ViewById // Injects R.id.textInput EditText textInput; @ViewById(R.id.myTextView) // Injects R.id.myTextView TextView result; @AnimationRes // Injects android.R.anim.fade_in Animation fadeIn; @Click // When R.id.doTranslate button is clicked void doTranslate() { translateInBackground(textInput.getText().toString()); } @Background // Executed in a background thread void translateInBackground(String textToTranslate) { String translatedText = callGoogleTranslate(textToTranslate); showResult(translatedText); } @UiThread // Executed in the ui thread void showResult(String translatedText) { result.setText(translatedText); result.startAnimation(fadeIn); } http://androidannotations.org/
  50. Features  Check for API availability before using features PackageManager

    pm = getPackageManager(); boolean hasCamera = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA); if (hasCamera) { // do things that require the camera } boolean hasBlueTooth = pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); if (hasBlueTooth) { // do things that require the blueTooth } <uses-feature android:name="android.hardware.bluetooth"/> <uses-feature android:name="android.hardware.camera"/>
  51. Restore state in activity • If you support both orientations,

    save the instance state while orientation changes for more responsiveness.  Before finish() an activity, onSaveInstanceState() is called to save UI state.  Restore the Activity state after being created @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Always call the superclass so it can save the view hierarchy state super.onSaveInstanceState(savedInstanceState); } public void onRestoreInstanceState(Bundle savedInstanceState) { // Always call the superclass so it can restore the view hierarchy super.onRestoreInstanceState(savedInstanceState); }
  52. LINT  Android comes with a tool called lint that

    can be used for identifying and correcting structural problems with your code.  Each detection has an associated description and severity level so it can be prioritized.  Can be invoked directly from the command-line, automated build system or directly from Eclipse
  53. VOLLEY https://android.googlesource.com/platform/frameworks/volley https://github.com/mcxiaoke/android-volley  Unzip and import from Eclipse as

    a new project with code available. Export the project as Java Volley / jar checking only the "src" folder.  Volley is a library that facilitates and speeds up the creation of applications that make use of networking in Android handling concurrency and network requests.  The advantage is that volley is responsible for managing the request threads transparently to the developer.  libs\volley.jar  Objects  RequestQueue  Request: Contains all the necessary details of API calls to Web. For example, the method to use (GET or POST), application data, listeners, error listeners.
  54. VOLLEY REQUEST import com.android.volley.*; public static RequestQueue requestQueue; @Override protected

    void onCreate(Bundle savedInstanceState) { requestQueue = Volley.newRequestQueue(this); }  JSON Request with volley.Request object JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, url, null, successListener,null); requestQueue.add(jsObjRequest);  Instagram Activity
  55. VOLLEY RESPONSE //Callback that is executed once the request has

    completed Response.Listener<JSONObject> successListener = new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { } }  JSON Response by volley.Response object  More volley examples https://github.com/PareshMayani/Android-Volley-Example
  56. Images  LRU Cache  Other libraries https://github.com/nostra13/Android-Universal-Image-Loader • Universal

    Image Loader http://square.github.io/picasso/ • Picasso
  57. Volley image loader public InstagramImageAdapter(Context context, ArrayList<InstagramImage> dataArray) { this.dataArray

    = dataArray; this.inflater = LayoutInflater.from(context); this.imageLoader = new ImageLoader(InstagramActivity.requestQueue, new BitmapLRUCache()); } private InstagramImageAdapter adapter; private ArrayList<InstagramImage> imagArray; imagArray=new ArrayList<InstagramImage>(); adapter=new InstagramImageAdapter(this,imagArray); Response.Listener<JSONObject> successListener = new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { JSONArray data = response.getJSONArray("data"); imagArray.addImage(data); }
  58. Developer libraries in google play

  59. Libraries  Indicator in ViewPager  http://viewpagerindicator.com/  https://github.com/chrisbanes/ActionBar-PullToRefresh 

    Pager Sliding Tabstrip  https://github.com/astuetz/PagerSlidingTabStrip  Show routes in map.  https://github.com/tyczj/MapNavigator
  60. Sliding Menu  Library to implement a sliding flyout with

    similar behavior to navigation drawer  https://github.com/jfeinstein10/SlidingMenu MessageBar  Library to improve toast messages  http://simonvt.github.io/MessageBar/
  61. Fading Action Bar  Used in Google play music 

    https://github.com/ManuelPeinado/FadingActionBar +  http://www.androidviews.net/  http://www.androidpatterns.com/
  62. Books

  63. About me https://github.com/jmortega/apps https://github.com/jmortega/android https://www.linkedin.com/in/jmortega1 @jmortegac https://play.google.com/store/apps/developer?id=Jos%C3%A9+Manuel+Ortega+Candel https://speakerdeck.com/jmortega/