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

Android Best Practices

Android Best Practices

Android Best Practices

jmortegac

April 26, 2015
Tweet

More Decks by jmortegac

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

  3. Index
     UI DESIGN
     INCLUDES / REUSING LAYOUTS
     STYLES
     ACTION BAR SEARCH VIEW / PROGRESS BAR
     ACCESSIBILITY / TALLBACK
     NETWORK CONNECTION
     ASYNCTASK / SERVICES
     FRAGMENTS
     NAVIGATION PATTERNS
     GEOLOCATION / PERFORMANCE
     DEPENDENCY INYECTION / ANNOTATIONS
     TOOLS / VOLLEY / LIBRARIES / /BOOKS
    http://developer.android.com/intl/es/training/index.html

    View Slide

  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

    View Slide

  5. Android Asset Studio
     Generate icons and graphic elements for each resolution
     http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html

    View Slide

  6. Resources /Screen support
     External elements you want to include and reference in the application.
     Declaratively include in /res ,accesing by @/
     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, …)
    android:xlargeScreens="true" android:largeScreens="true"
    android:normalScreens="true" android:smallScreens="true" />

    View Slide

  7. Includes / Reusing layouts

    View Slide

  8. Styles

    parent="@android:style/TextAppearance.Medium">
    match_parent
    wrap_content
    50dp
    @color/negro
    @color/gris_claro
    35sp


    <br/><item name="android:layout_width">match_parent</item><br/><item name="android:layout_height">wrap_content</item><br/><item name="android:textSize">20sp</item><br/><item<br/>name="android:drawableTop">@drawable/logo_empresa</item><br/>

    View Slide

  9. Styles
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/info_empresa"
    style="@style/CodeStyleTextView" />
    android:id="@+id/btnChangeImage"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/cambiar_imagen_fondo"
    style="@style/CodeStyleButton" />

    View Slide

  10. Action Bar Search View

    View Slide

  11. Action Bar Search View
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    mSearchView = (SearchView) searchItem.getActionView();
    mSearchView.setQueryHint("Search...");
    mSearchView.setOnQueryTextListener(this);
    return true;
    }
    android:showAsAction="always"
    android:title="@string/search"
    android:icon="@android:drawable/ic_menu_search"
    android:actionViewClass=
    "android.support.v7.widget.SearchView" />
    private SearchView mSearchView;

    View Slide

  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;
    }

    View Slide

  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

    View Slide

  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.

    View Slide

  15. Accessibility / TalkBack

    View Slide

  16. Accessibility
    http://developer.android.com/training/accessibility/index.html
    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
    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"/>

    View Slide

  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();
    android:name="android.permission.ACCESS_NETWORK_STATE"/>

    View Slide

  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);
    android:name="android.permission.CHANGE_WIFI_STATE"/>

    View Slide

  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;

    View Slide

  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.

    View Slide

  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{
    @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);

    View Slide

  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

    View Slide

  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

    View Slide

  24. Fragments
     Add a fragment to view
     by layout xml

    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal">
    class="com.proyecto.spaincomputing.fragment.UniversidadesFragment"
    android:id="@+id/FrgListado"
    android:layout_width="375dp"
    android:layout_height="match_parent"/>
    class="com.proyecto.spaincomputing.fragment.FragmentDetalle"
    android:id="@+id/FrgDetalle"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

    View Slide

  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();

    View Slide

  26. Fragments/ Master-detail
    PORTRAIT
    LANDSCAPE

    View Slide

  27. Fragments/ Master-detail
    PORTRAIT
    LANDSCAPE

    View Slide

  28. Fragments/ Master-detail
     2 layout
     layout\fragment_universidades_list.xml

    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    android:id="@+id/listView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >


    View Slide

  29. Fragments/ Master-detail
     2 layout
     layout-land\fragment_universidades_list.xml
    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" >
    android:id="@+id/listView"
    android:layout_width="0px"
    android:layout_height="wrap_content"
    android:layout_weight="1.5">

    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" />

    View Slide

  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);
    }

    View Slide

  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
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

    View Slide

  32. Navigation Drawer
     http://developer.android.com/training/implementing-navigation/nav-
    drawer.html

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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);
    android:parentActivityName=".ListadoActivity"

    android:value=".ListadoActivity" />

    View Slide

  37. Singleton
     Application class
    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();
    }}

    View Slide

  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
    listado=newArrayList();
    private ListView lstListado;
    lstListado=(ListView)getView().findViewById
    (R.id.LstListado);
    lstListado.setAdapter
    (new UniversidadAdapter(this,listado));

    View Slide

  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.

    View Slide

  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);
    }

    View Slide

  41. View Holder/View Container Pattern
     Debug

    View Slide

  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
    ));

    View Slide

  43. Obtain user moving
     LocationListener onLocationChanged()
     Activity Recognition API


    IntentFilter filter = new IntentFilter();
    filter.addAction("com.example.myactivityrecognition.ACTIVITY_RECOGNITION_
    DATA");
    registerReceiver(receiver, filter);
     Register broadcast receiver on activity

    View Slide

  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 "";
    } }

    View Slide

  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”
    }
    }

    View Slide

  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());
    }

    View Slide

  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);
    }}

    View Slide

  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

    View Slide

  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/

    View Slide

  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
    }


    View Slide

  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);
    }

    View Slide

  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

    View Slide

  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.

    View Slide

  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

    View Slide

  55. VOLLEY RESPONSE
    //Callback that is executed once the request has completed
    Response.Listener successListener =
    new Response.Listener() {
    @Override
    public void onResponse(JSONObject response) {
    }
    }
     JSON Response by volley.Response object
     More volley examples
    https://github.com/PareshMayani/Android-Volley-Example

    View Slide

  56. Images
     LRU
    Cache
     Other libraries
    https://github.com/nostra13/Android-Universal-Image-Loader
    • Universal Image Loader
    http://square.github.io/picasso/
    • Picasso

    View Slide

  57. Volley image loader
    public InstagramImageAdapter(Context context,
    ArrayList dataArray) {
    this.dataArray = dataArray;
    this.inflater = LayoutInflater.from(context);
    this.imageLoader = new
    ImageLoader(InstagramActivity.requestQueue,
    new BitmapLRUCache());
    }
    private InstagramImageAdapter adapter;
    private ArrayList imagArray;
    imagArray=new ArrayList();
    adapter=new InstagramImageAdapter(this,imagArray);
    Response.Listener successListener =
    new Response.Listener() {
    @Override
    public void onResponse(JSONObject response) {
    JSONArray data = response.getJSONArray("data");
    imagArray.addImage(data);
    }

    View Slide

  58. Developer libraries in google play

    View Slide

  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

    View Slide

  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/

    View Slide

  61. Fading Action Bar
     Used in Google play music
     https://github.com/ManuelPeinado/FadingActionBar
    +
     http://www.androidviews.net/  http://www.androidpatterns.com/

    View Slide

  62. Books

    View Slide

  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/

    View Slide