Android best practices
-
Upload
jose-manuel-candel -
Category
Software
-
view
246 -
download
0
description
Transcript of Android best practices
![Page 1: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/1.jpg)
Android Best
Practices
José Manuel Ortega
DroidCon July 2014
![Page 2: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/2.jpg)
https://techfest.uc3m.es/programa/android-in-practice/
![Page 3: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/3.jpg)
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
![Page 4: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/4.jpg)
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
![Page 5: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/5.jpg)
Android Asset Studio
Generate icons and graphic elements for each resolution http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html
![Page 6: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/6.jpg)
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" />
![Page 7: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/7.jpg)
Includes / Reusing layouts
![Page 8: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/8.jpg)
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>
![Page 9: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/9.jpg)
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" />
![Page 10: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/10.jpg)
Action Bar Search View
![Page 11: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/11.jpg)
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;
![Page 12: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/12.jpg)
Action Bar Search View
Implement interface OnQueryTextListener
Override methods onQueryTextSubmit, onQueryTextChange
@Override public boolean onQueryTextSubmit(String query) { UniversityListFragment fragmentList = (UniversityListFragment)getSupportFragmentManager().findFragmentByTag("list_fragment"); fragmentList.searchData(query); return true; } @Override public boolean onQueryTextChange(String query) { return true; }
![Page 13: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/13.jpg)
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
![Page 14: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/14.jpg)
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.
![Page 15: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/15.jpg)
Accessibility / TalkBack
![Page 16: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/16.jpg)
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"/>
![Page 17: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/17.jpg)
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"/>
![Page 18: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/18.jpg)
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"/>
![Page 19: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/19.jpg)
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;
![Page 20: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/20.jpg)
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.
![Page 21: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/21.jpg)
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);
![Page 22: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/22.jpg)
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
![Page 23: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/23.jpg)
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
![Page 24: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/24.jpg)
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>
![Page 25: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/25.jpg)
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();
![Page 26: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/26.jpg)
Fragments/ Master-detail
PORTRAIT LANDSCAPE
![Page 27: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/27.jpg)
Fragments/ Master-detail
PORTRAIT
LANDSCAPE
![Page 28: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/28.jpg)
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>
![Page 29: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/29.jpg)
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>
![Page 30: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/30.jpg)
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); }
![Page 31: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/31.jpg)
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"/>
![Page 32: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/32.jpg)
Navigation Drawer http://developer.android.com/training/implementing-navigation/nav-
drawer.html
![Page 33: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/33.jpg)
View Pager
http://developer.android.com/intl/es/training/animation/screen-slide.html
![Page 34: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/34.jpg)
Tabs navigation in Action bar
http://developer.android.com/intl/es/guide/topics/ui/actionbar.html#Tabs
![Page 35: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/35.jpg)
Drop-down navigation in Action bar
http://developer.android.com/intl/es/guide/topics/ui/actionbar.html#Dropdown
![Page 36: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/36.jpg)
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>
![Page 37: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/37.jpg)
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(); }}
![Page 38: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/38.jpg)
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));
![Page 39: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/39.jpg)
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.
![Page 40: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/40.jpg)
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);
}
![Page 41: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/41.jpg)
View Holder/View Container Pattern
Debug
![Page 42: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/42.jpg)
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));
![Page 43: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/43.jpg)
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
![Page 44: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/44.jpg)
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 ""; } }
![Page 45: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/45.jpg)
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” } }
![Page 46: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/46.jpg)
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()); }
![Page 47: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/47.jpg)
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); }}
![Page 48: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/48.jpg)
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
![Page 49: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/49.jpg)
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/
![Page 50: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/50.jpg)
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"/>
![Page 51: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/51.jpg)
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); }
![Page 52: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/52.jpg)
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
![Page 53: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/53.jpg)
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.
![Page 54: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/54.jpg)
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
![Page 55: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/55.jpg)
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
![Page 56: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/56.jpg)
Images
LRU Cache
Other libraries
https://github.com/nostra13/Android-Universal-Image-Loader
• Universal Image Loader
http://square.github.io/picasso/
• Picasso
![Page 57: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/57.jpg)
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); }
![Page 58: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/58.jpg)
Developer libraries in google play
![Page 59: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/59.jpg)
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
![Page 60: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/60.jpg)
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/
![Page 61: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/61.jpg)
Fading Action Bar
Used in Google play music https://github.com/ManuelPeinado/FadingActionBar
+
http://www.androidviews.net/ http://www.androidpatterns.com/
![Page 62: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/62.jpg)
Books
![Page 63: Android best practices](https://reader033.fdocuments.net/reader033/viewer/2022051209/547c2102b47959ac508b45d1/html5/thumbnails/63.jpg)
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/