Etiqueta: SpotifyClient

GreenDao Paso2 – DBManager impl

Buenas!

En esta entrada vamos a ver cómo crear nuestro gestor para la base de datos y cómo usarlo. Y con esto daremos por terminada la primera versión de guardar los datos en una base de datos cifrada.

DBManager

Lo primero que hacemos es crearnos un nuevo paquete en nuestro proyecto para tenerlo todo bien separado y creamos una interfaz con los métodos que consideremos útiles. Nosotros hemos elegido estos:

public interface DBManager {

    void closeDbConnections();
    void dropDb();

    boolean insertToken(DBToken token);

    boolean updateToken(DBToken token);

    List<DBToken> listTokens();

    DBToken getToken(Long tokenid);

    boolean deleteToken();
}

Son los típicos métodos de CRUD.

A continuación nos crearemos una nueva clase que implemente esta interfaz.

Hemos planteado la clase para que funcione con Singleton, ya que no necesitamos más que una única instancia del gestor de la db.

En el siguiente fragmento de código, veremos cómo  inicializar el “Helper” de nuestra base de datos encriptada que permitirá abrir nuestra DB en modo lectura o escritura.

public DBManagerImpl(final Context context) {
    this.context = context;
    mHelper = new DaoMaster.EncryptedDevOpenHelper(this.context, "spotifyClientDB");
    completedOperations = new CopyOnWriteArrayList<>();
}

public static DBManagerImpl getInstance(Context context) {
    if (instance == null) {
        instance = new DBManagerImpl(context);
    }
    return instance;
}

De los métodos de nuestra interfaz tenemos closeDbConnections() y dropDb() que uno cierra/limpia e iguala a nulo todas las instancias de la base de datos, como podemos ver en el repositorio y dropDb que abre la db en modo escritura, borra todas las tablas, y las vuelve a crear vacías con todos sus elementos borrados:

@Override
public void dropDb() {
    try {
        openWritableDb();
        DaoMaster.dropAllTables(database, true); // drops all tables
        mHelper.onCreate(database);              // creates the tables
        asyncSession.deleteAll(DBToken.class);    // clear all elements from a table
    } catch (Exception e) {
        e.printStackTrace();
    }
}

InsertToken

En este método, insertamos el token a la DB después de validar que no venga nulo. Para ello abrimos la DB en modo escritura y con el DAO (Data Access Object) que nos devuelve la sesión de nuestra DB, insertamos el token en ella.

@Override
public boolean insertToken(DBToken token) {
    try{
        if(token != null){
            openWritableDb();
            DBTokenDao tokenDao = daoSession.getDBTokenDao();
            tokenDao.insert(token);
            daoSession.clear();
            database.close();
            return true;
        }
        return false;
    } catch (Exception e){
        e.printStackTrace();
    }
    return false;
}

GetToken – ListTokens

Para leer los tokens de la DB hemos creado 2 métodos, uno que funciona mandando un id a la db y te devuelve un token concreto y otro que te devuelve todos los tokens.

Esta funcionalidad es ahora mismo absurda, porque la idea de la aplicación es que solo tenga 1 token en todo momento, por lo que en un futuro será eliminada, era para probar.

Del código no hay mucho que explicar, funciona de manera similar al insertar, solo que se hace un “loadAll()” en el Dao para obtener todos los datos.

@Override
public List<DBToken> listTokens() {
    List<DBToken> tokens = null;
    try{
        openReadableDb();
        DBTokenDao tokenDao = daoSession.getDBTokenDao();
        tokens = tokenDao.loadAll();

        daoSession.clear();
        database.close();
    } catch (Exception e){
        e.printStackTrace();
    }

    if(tokens != null)
        return tokens;
    return null;
}

@Override
public DBToken getToken(Long tokenid) {
    ...
    token = tokenDao.load(tokenid);
    ...
    return token;
}

Update

Para actualizar un valor de la db, seguimos la misma idea y en el daoSession (no en el Dao de la tabla) haremos un update con el objeto directamente.

daoSession.update(token);

DeleteToken

Siguiendo la misma idea, hemos hecho el método deleteToken obteniendo el Dao y haciendo un:

tokenDao.deleteAll();

Para borrar todos los tokens de la db. Si quisiéramoas borrar un único token, usaríamos ”

deleteByKey(long tokenid)

OpenReadableDb / OpenWritableDb

Para abrir una conexión con la db en modo lectura o escritura, solo tenemos que indicarle la forma de la que queremos abrirla y la contraseña de la DB cifrada (ahora mismo está puesta tal cuál en la aplicación porque estamos en un entorno de prueba. Si fuera a publicarse, habría que encontrar la manera de obtener una clave del tipo SHA1 para cifrar la DB correctamente y guardar esa clave en algún entorno seguro).

public void openReadableDb() throws SQLiteException {
    database = mHelper.getReadableDatabase("contraseñahipersecreta");
    openDb();
}

public void openWritableDb() throws SQLiteException {
    database = mHelper.getWritableDatabase("contraseñahipersecreta");
    openDb();
}

private void openDb(){
    daoMaster = new DaoMaster(database);
    daoSession = daoMaster.newSession();
    asyncSession = daoSession.startAsyncSession();
    asyncSession.setListener(this);
}

El asyncSession del que no hemos hablado, es otra interfaz que implementa la clase para realizar las acciones de modo asíncrono.

¿Cómo usarlo?

Para usarlo, es tan fácil como obtener la instancia del gestor de la base de datos en una actividad:

databaseManager = DBManagerImpl.getInstance(this);

Y para insertar un dato, echando una mirada a la siguiente entrada ya que voy a insertar el token de mi usuario de Spotify, inicializamos la variable token de los modelos generador previamente con GreenDao y si el token no es nulo ni vacío, lo insertamos en la base de datos haciendo una llamada a “insertToken()” y ya está.

DBToken token = new DBToken();
boolean todoOk = false;
if(response.getAccessToken() != null && !response.getAccessToken().isEmpty()){
    databaseManager.deleteToken();
    token.setTokenvalue(response.getAccessToken());
    todoOk = databaseManager.insertToken(token);
}

Para leer el token que hemos insertado, simplemente tendríamos que usar el método get o listTokens que hemos hecho antes.

List<DBToken> dbtokens = databaseManager.listTokens();

 

Con esto podéis ver cómo hemos hecho una base de datos encriptada (con una contraseña horrible y que NO debéis usar ya que  incluir la contraseña en la propia app es inseguro) y hemos visto cómo usarla completamente y con facilidad gracias a la librería GreenDao que nos lo ha puesto bastante fácil para hacerlo. ¡Eh! ¡Y sin escribir nada de código SQL!

Recordad que todo el código está también en el repositorio de GitHub.

Un saludo 😉

GreenDao y GreenDaoGenerator

Tras revisar la WebApi y AndroidApi de Spotify, muchas de las peticiones necesitan la autenticación del usuario, por lo que necesitamos que para ellas el usuario tenga su sesión iniciada, sea por Spotify o Facebook, de eso ya se encarga Spotify.

Para ello utilizaremos la librería de Spotify Auth para Android que veremos en el siguiente post.

Esa librería, si se hace login correctamente, nos devolverá un token de usuario. Ese token, deberíamos guardarlo en algún lado para no perderlo. Y como es propio del usuario, estaría bien que estuviera cifrado.

GreenDao

He elegido GreenDao porque ya había trabajado con él en otros proyectos y porque sabía que tenía una opción de cifrado de la base de datos.

En esta web podemos encontrar información de la base de datos cifrada también para Android Nougat (v7) y las penalizaciones de tamaño que tiene contra una db SqLite.

GreenDao Generator Encryption

Vamos a usar el generador de GreenDao para olvidarnos de crear los DAOs de la app que queremos guardar en base de datos.

Para integrar GreenDao en nuestro proyecto, adaptaremos la información de esta entrada de Antonina Tkachuk a nuestro caso concreto.

Para ello crearemos un nuevo módulo en nuestro proyecto y seleccionaremos “Java Library

azboac4

Le ponemos el nombre que queramos (nosotros hemos elegido “greendao-gen“) y le ponemos también el nombre de la clase que queramos, como MainGenerator por ejemplo.

En el archivo Gradle añadimos la librería de GreenDao Generator Encryption para comenzar a usarla:

compile 'org.greenrobot:greendao-generator-encryption:2.2.0'

MainGenerator

Dentro de esta clase, pondremos la estructura de la base de datos que queremos usar.

Empezaremos creando 2 variables para obtener la ruta donde está el código de nuestra app.

private static final String PROJECT_DIR = System.getProperty("user.dir").replace("\\", "/");
private static final String OUT_DIR = PROJECT_DIR + "/app/src/main/java";

Y crearemos también un método “main” en el que crearemos nuestro Scheme de la base de datos indicándole por parámetro qué versión de nuestro esquema es y en qué ruta queremos que guarde los archivos generador.

Por último, usando DaoGenerator,  generamos todo el esquema en el directorio de salida que le hemos indicado antes.

Schema schema = new Schema(1, "com.afrasilv.spotifyclientapp.model");

addTables(schema);

new DaoGenerator().generateAll(schema, OUT_DIR);

Como realmente lo único que queremos guardar en la base de datos por ahora, va a quedar la estructura un poco absurda, pero será más fácil de ampliar por si en un futuro vemos que necesitamos crear nuevas tablas.

Dentro de addTables, haremos llamadas a los métodos que se encargan de añadir al Scheme las Entities de las que se va a componer la db.

private static void addTables(Schema schema){
    // Entities
    Entity token = addToken(schema);
}

private static Entity addToken(Schema schema){
    Entity token = schema.addEntity("DBToken");
    token.addIdProperty().primaryKey().autoincrement();
    token.addStringProperty("tokenvalue").notNull();

    return token;
}

En addToken le añadimos la Entity “DBToken” al esquema indicándole que tiene una PK es que ID y que se autoincrementa y que además tiene también una propiedad String que es “tokenvalue” que es la que más nos interesa.

Con lo que tenemos ya, solo tenemos que pulsar con el botón derecho en MainGenerator y seleccionar “Run MainGenerator.main()” y automáticamente se nos habrá creado dentro de nuestro proyecto en el módulo de la app, una carpeta “model” con los ficheros de la base de datos.

En la siguiente entrada veremos cómo crear un gestor para nuestra base de datos, aunque en esta ocasión será muy simple.

Todo el código de la app lo podréis ver en el repositorio de GitHub!!

Aplicación “Cliente Spotify” – Primeros pasos

La primera aplicación que vamos a ir haciendo en el tiempo libre y publicando en el blog es un cliente de Spotify. En un principio será un cliente con la Web Api  al que le añadiremos en un futuro la librería de Android para poder reproducir las canciones directamente desde ella, solo para usuarios premium.

Todo el código de la aplicación lo podremos encontrar en este repositorio de GitHub afrasilv – SpotifyClientApp.

¿Qué vamos a usar?

La aplicación la vamos a estructurar usando el patrón MVP, que básicamente consiste en separar la capa de presentación de la aplicación, de la lógica de la misma. Por lo que separaremos el cómo funciona y el cómo lo representamos. Lo que hará también las pruebas del código algo más sencillo. Podéis ampliar más la información en el blog de Antonio Leiva (@lime_cl) en inglés o español si lo preferís.

Como base también, en la medida de lo posible (aunque será muy mejorable) intentaremos tener presentes los principios SOLID y lo aprendido en el libro “Clean Code” de Uncle Bob.

Además usaremos Dagger (v2) de Google y Square para inyectar las dependiencias (Dependency Injection) que nos vaya haciendo falta para tener las clases lo más independientes posible y facilitar las pruebas. Aquí un pequeño tutorial de cómo usar Dagger2.

Para las peticiones REST usaremos Retrofit2, la cuál solo necesita crear una interfaz y añadir las anotaciones con los parámetros y listo ;).

Para la carga de las imágenes usaremos Glide, no por nada en especial, si no porque Picasso lo he usado ya en varios proyectos y quiero ver cómo se usa otra librería más.

También tenemos ButterKnife para simplificar el uso de las vistas dentro de las actividades/fragments.

EventBus para la información que comparten diferentes activides/fragments/hilos…

Y bueno, haremos también pruebas de código en el que usaremos Mockito del que tampoco hay mucho que decir ya.

¿Qué necesitamos?

Pues Android Studio y ciertos conocimientos de Java ya puestos. Ah y paciencia, porque lo iré haciendo en los ratos libres.

 

Y nada, ya estamos. Vamos a ello.