Nos permite entender la estuctura, funcionamiento y forma de ensamblaje de los módulos de nuestra app.
Módulos
Arquitecturas más comunes:
Cinco principios basados en la POO y el diseño de Software. Su intención es permitirnos crear aplicaciones fáciles de mantener y escalar a lo largo del tiempo.
Tendrémos 3 módulos principales:
Estructura de archivos
Flujo de datos
Modelo de capas
Estructura de archivos
Flujo de datos
Consejos
uses-permision vs uses-feature
Con uses-permission le notificas al usuario cuando va a instalar la aplicación que usarás ese permiso.
Con uses-feature le dices al SO que estas interesado en utilizar un feature específico del hardware, además sirve como filtro en Play Store si el dispositivo no tiene esa característica no aparece la app disponible para instalar.
Ejemplo accediendo a cámara(Permiso por AndroidManifest)
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature
android:name="android.hardware.camera2"
android:required="false"
/>
privatevoidtakePicture(){
Intent intentTakePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intentTakePicture.resolveActivity(getActivity().getPackageManager()) !=null){
startActivityForResult(intentTakePicture, REQUEST_CAMERA);
}
}
startActivityForResult(intentTakePicture, REQUEST_CAMERA);
privatestaticfinalint REQUEST_CAMERA = 1;
@Override
public void onActivityResult(int requestCode, int resultCode, Intentdata) {
if (requestCode == REQUEST_CAMERA && resultCode == getActivity().RESULT_OK){
Log.d("HomeFragent", "CameraOK!! :)");
Toast.makeText(this.getContext(), "CamaraOK!!", Toast.LENGTH_SHORT).show();
}
}
try{
...
}catch (Exception e) {
e.printStackTrace();
}
Ejemplo
static mapping = {
table'person'
columns {
name column:'name'
}
}
Archivos de Configuración
Estructura del proyecto
MyApp/ *Project*
|
+- build.gradle
|
+- settings.gradle
|
+- app/ *Module* (wear, tv, mobile, etc)
|
+- build.gradle
|
+- build/
|
+- libs/
|
+- src/
|
+- main/ *Sourceset*
|
+- java/
||
| +- com.example.myapp/
|
+-res/
||
| +- drawable/
||
| +- layout/
||
| +- ...
|
+- AndroidManifest.xml
Nivel superior
Nivel de módulo
¿Qué hacer?
public classPlatzigramApplicationextendsApplication{
<application
android:name=".PlatzigramApplication"
Toda la información sobre como implementar FirebaseAuth la puedes encontrar en la documentación de Firebase: https://firebase.google.com/docs/auth/android/start/
Las aplicaciones en Android se instalan en el directorio /data/data/[package]/ (Para ingresar de forma común a estos directorios debes ser un usuario Root). En este directorio se encontrará el almacenamiento interno de nuestra app.
Almacenamiento interno
Almacenamiento en red
La mayor recomendación es trabajar con ambos tipos de almacenamiento, Interno y en la red para proveer a nuestros usuarios de una mayor persistencia.
SharedPreferences
Almacena la información en una ubicación específica, en un archivo .xml, a la que se accesa a través de una Key-Valor.
Este tipo de almacenamiento es útil cuando se trata de datos sencillos. Puntajes, configuraciones, datos de entrada, etc.
Uso
SharedPreferences pref = getSharedPreferences("MisPreferencias",Context.MODE_PRIVATE);SharedPreferences.Editor editor = pref.edit();
editor.putString("email", "[email protected]");
editor.putString("nombre", "Carlos");
editor.commit();
Esto se almacena en:
/data/data/package/shared_prefs/MisPreferencias.xml
Para leer la información almacenada en SharedPreferences:
SharedPreferences pref = getSharedPreferences("MisPreferencias",Context.MODE_PRIVATE);pref.getString("email", "mensaje");pref.getString("nombre", "mensaje");
Internal Storage
Almacena la información en la memoria interna del dispositivo File I/O. Esto se hace con código basado completamente en Java.
Almacenamiento como Recursos (raw)
Los archivos también se pueden almacenar como recursos en nuestra carpeta de recursos raw. En este caso comúnmente son propiedades, por ejemplo, en un archivo de texto.
Para obtener los datos:
Resources miRecurso = getResources();InputStreammiarchivo = miRecurso.openRawResource(R.raw.miarchivo);
SQLite Database
Normalmente lo usamos cuando nuestra información tiene una estructura muy compleja y privada. Este es el gestor de base de datos oficial de Android y utiliza el lenguaje SQL.
Por defecto, una base de datos de tu aplicación será almacenada en el directorio:
/data/data/package/databases/miDB
Network Connection
Los datos se almacenan en la nube con la ayuda de web services como firebase o un servidor personalizado.
La forma mas comun de trabajar los menus en Android es mediante un archivo .xml en la carpeta menu dentro de la carpeta res.
Existen tres tipos de menús con mayor importancia
Opciones
De los más comunes, son los tres puntitos que puedes ver normalmente en la toolbar. Más usado para ajustes, configuración de la app.
Implementación
@overridepublicbooleanonCreateOptionsMenu(Menu menu){
getMenuInflater().inflate(R.menu.menu_opciones, menu);
returntrue;
}
@overridepublicbooleanonOptionsItemSelected(MenuItem item){
switch(item.getItemIde()){
}
}
Contexto
Este menú se ejecuta luego de un long-press sobre algún view, como una lista de opciones.
Implementación
TextView tvNombre = (TextView) findViewById(R.id.tvNombre);
registerForContextMenu(tvNombre);
@overridepublicbooleanonCreateContextMenu(ContextMenu menu, View v, Context...){
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.menu_contexto, menu);
}
@overridepublicbooleanonContextItemSelected(MenuItem item){
switch(item.getItemIde()){
}
}
Donde registerForContextMenu(miView); lo que hace es definir cuales views seran los que activarán el menú de contexto con el evento long-press.
Popup
Se disparan cuando se da click, tap en algún View (button, cardView, imagen, etc).
Implementación
En primer lugar, se debe asignar un evento onClick al view que ejeutarú el menú popup. En este caso, un onClickListener funciona perfectamente.
ImageView imagen = (ImageView) findViewById(R.id.imgImagen);PopupMenu popupMenu = new PopupMenu(this, imagen);popupMenu.getMenuInflater().inflate(R.menu.menu_popup, popupMenu.getMenu());
popupMenu.setOnMenuClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch(item.getItemId()){
...
}
}
}
Usa Google Cloud Storage. Los archivos se estructuran como un sistema de arbol donde el directorio padre es el proyecto, identificado con una URL que puedes encontrar en tu panel de firebase > storage, y cada subdirectorio puede ser llamado y almacenar como quieras.
Todo se manejará en base a referencias mediante la clase principal StorageReference ref; y esta siempre apunta por defecto a nuestro directorio padre (la URL) a partir de ahí puedes acceder a los archivos y nodos mediante .child(“carpeta1”).child(“img3.jpg”);.
Para subir un archivo usarémos UploadTask que funcionará con su Listener.
Logcat
Es un sistema de registro de Android que proporciona información sobre la salida del sistema en modo debug o depuración.
Estructura:
Ejemplo
Log.w(TAG, "Mensaje de Warning");
Firebase Crashlytics
Nos informa de errores muy precisos de la aplicación, desde que está siendo desarrollada hasta cuando está ya en producción.
Aprende como implementarlo en tu app siguiendo la documentación oficial.
Uso
Puedes desactivar la recopilación automática con una etiqueta meta-data en tu archivo AndroidManifest.xml:
<meta-data android:name="firebase_crashlytics_collection_enabled"android:value="false" />
Esto sirve, por ejemplo, para habilitar la recopilación para usuarios seleccionados mediante la inicialización de Crashlytics desde una de las actividades de tu app:
Fabric.with(this, new Crashlytics());
Manejarémos tres tipos de errores con Firebase Crashlytics:
Crashlytics.logException(e);
Crashlytics.log(msg);
Crashlytics.log(int priority, String tag, String msg);
Agregar claves personalizadas
Puedes asociar pares clave-valor arbitrarios con tus informes de fallos y verlos en Firebase console.
Personalizar mensajes de Firebase Crashlytics
Crashlytics.setString(key, value);
Crashlytics.setBool(Stringkey, boolean value);
Crashlytics.setDouble(Stringkey, double value);
Crashlytics.setFloat(Stringkey, float value);
Crashlytics.setInt(Stringkey, int value);
Ejemplo:
Crashlytics.setInt("current_level", 3);
Crashlytics.setString("last_UI_action", "logged_in");
Configurar ID de usuario
Para agregar los ID de usuario a tus informes, asigna a cada usuario un identificador único con el formato de un número de ID, un token o un valor con hash.
void Crashlytics.setUserIdentifier(String identifier);
Si necesitas borrar un identificador de usuario después de configurarlo, restablece el valor a una string en blanco.
Anahí dejó esta clase por escrita, así que sólo dejo el enlace.
Anahí dejó esta clase por escrita, así que sólo dejo el enlace.
Guía de estilo para diseñar y desarrollar una API
https://platzi.com/?state=active&code=75b4876b88aa
(Primero debes implementar retrofit de square)
Como buena práctica, en la carpeta de la API que debe estar en el Package deberíamos crear una clase de constantes que contendrá todas las Rutas. Constants
Crearemos una InterfazService que gestionará todos los Endpoints, todas las direcciones de peticiones.
Ej:
@GET(Constants.URL_GET_USER)
call<JsonObject> getDataUser();
//Donde URL_GET_USER contiene "/me"
También crearemos una clase que se encargará de gestionar la conexión a la API, normalmente llamada RestApiAdapter.
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
@OverridepublicResponse intercept(Interceptor.Chain chain)throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Authorization", "Bearer" + Constants.Bearer)
.build);
return chain.proceed(newRequest);
}
}).build();
//Esto de arriba se utiliza cuando necesitamos pasar Headers. Recuerda que el "Bearer" es algo propio de Medium, normalmente no hace falta mandar "Bearer" sino el token no mas.publicService getClientService(){
Retrofit retrofit = new Retrofit.Builder()
.baseURL(Constants.ROOT_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(Service.class);
}
Para ejecutar, dentro del Repository, en el método que ya definimos como getDataUser() agregamos:
RestApiAdapter restApiAdapter = new RestApiAdapter();
Service service = restApiAdapter.getClientService();
Call<JsonObject> call = service.getDataUser();
call.enqueue(new Callback<JsonObject>() {
@Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
JsonObject userJson = response.body().getAsJsonObject("data").toString();
User user = new User(
userJson.get("id").getAsString(),
userJson.get("name").getAsString(),
userJson.get("username").getAsString(),
userJson.get("url").getAsString(),
userJson.get("imageUrl").getAsString(),
);
userPresenter.showDataUser(user);
//Este método es el que, en la vista, le asignará a cada view el dato que le corresponde con
//objectView.setText(user.getName());
}
@Override
public void onFailure(Call<JsonObject> call, Throwable t) {
}
});
Normalmente tus api keys estarán almacenadas en el archivo strings.xml o en alguna clase de constantes, si las tienes ahí están vulnerables a ser descubiertas con ingeniería inversa, por ello es buena idea usar Gradle para mantener aislados estos datos del código fuente.
Esta clase es textual, el enlace recuerda que lo tienes aquí.
Esta capa de seguridad sigue siendo muy vulnerable, una mayor seguridad se puede obtener creando una clase que encripte y desencripte los Strings : http://iamvijayakumar.blogspot.com.co/2013/10/android-example-for-encrypt-and-decrypt.html
Android tiene esencialmente 3 formas de crear animaciones:
Toda la clase de @anncode está en este enlace.
La documentación es completamente intuitiva y la puedes encontrar en la misma consola de firebase.