Página Principal

miércoles, 27 de abril de 2016

SGC: Mi primer Proyecto - Parte I

Aquí le presento la primera parte de mi primer App  para android que la tome con seriedad.

Se llama Sistema de Gestión Comercial: Kiosquin. Es un proyecto que desarrolle para la habilitación profesional de mi carrera.
Este vídeo fue el comienzo funcional de mi app, ABM de productos(utilizando tabs fragments y la cam para leer código de barra), Base de datos (SQLite3)

Nota: véanlo desde una PC, porque el vídeo contiene notas, que desde un móvil no se ven.
Aclaración: La app se ve lenta, pero es la grabación


En breve subiré la siguiente parte, donde ya funciona la parte de ventas, con filtros de búsqueda por nombre o código de barra, popups, y con algo de temas y estilo para que visualmente sea mas agradable

un Saludo

lunes, 25 de abril de 2016

Backup de una BD(SQLite) en Android

Aquí mostrare un ejemplo de como generar o restaurar un Backup de una Base de Dato en android.

En principio hay que aclarar algunas cuestiones. Una vez creada la base de datos, tenemos que saber donde se aloja la misma...

/data/data/com.example.app/databases/example.db

Para un ejemplo generico, la BD asi se guardara en nuestra memoria interna.

public class GestionBackup {

    private Context contexto;

    public static final String PACKAGE_NAME = "app.com.kiosquin_v43";
    public static final String DATABASE_NAME = DBhelper.DB_NAME;
    public static final String APP_PATH = "/Kiosquin-v4.3/backup/";

    public static final String RUTA_BACKUP = Environment.getExternalStorageDirectory().
            getAbsolutePath() + APP_PATH;

    /** Contains: /data/data/com.example.app/databases/example.db **/
    private static final String DIR_DB_INTERNA =
                    "/data/" + PACKAGE_NAME +
                    "/databases/" + DATABASE_NAME;

    private static final String DIR_DB_BACKUP =
                    APP_PATH + "myDB.db";

    public GestionBackup(Context c){
        File file = new File(RUTA_BACKUP);
        //creo el directorio donde ira puesto el backup (Sin esto no lo puede generar)
        file.mkdirs();
        contexto=c;
    }

    public void importDB() {
        try {
            File sd = Environment.getExternalStorageDirectory();
            File data = Environment.getDataDirectory();
            if (sd.canWrite()) {

                File backupDB = new File(data, DIR_DB_INTERNA);
                File currentDB = new File(sd, DIR_DB_BACKUP);

                FileChannel src = new FileInputStream(currentDB).getChannel();
                FileChannel dst = new FileOutputStream(backupDB).getChannel();
                dst.transferFrom(src, 0, src.size());
                src.close();
                dst.close();
                Mensaje.ver("Import Exitoso!",contexto);

            }
        } catch (Exception e) {

            Mensaje.ver("Import Erroneo!", contexto);

        }
    }

    public void exportDB() {
        try {
            File sd = Environment.getExternalStorageDirectory();
            File data = Environment.getDataDirectory();

            if (sd.canWrite()) {

                File currentDB = new File(data, DIR_DB_INTERNA);
                File backupDB = new File(sd, DIR_DB_BACKUP);

                FileChannel src = new FileInputStream(currentDB).getChannel();
                FileChannel dst = new FileOutputStream(backupDB).getChannel();
                dst.transferFrom(src, 0, src.size());
                src.close();
                dst.close();
                Mensaje.ver( "Backup Exitoso!",contexto);

            }
        } catch (Exception e) {

            Mensaje.ver("Backup Erroneo!", contexto);

        }
    }
}

La clase Mensaje para los que les interese, ahí estará mas detallada.

Creo que el ejemplo esta bastante claro de seguir,

* PACKAGE_NAME:
                                  Nombre o dirección del paquete de nuestra app;
* DATABASE_NAME:
                                  Nombre de nuestra Base de Dato;          

* APP_PATH:
                     Direccion donde se alojara nuestra Backup

* RUTA_BACKUP:
     //Se obtiene la direccion completa, No la utilizo. porque al crear el file uso otro constructor
     Environment.getExternalStorageDirectory(). getAbsolutePath() + APP_PATH

* DIR_DB_INTERNA = 
                                 "/data/" + PACKAGE_NAME + "/databases/" + DATABASE_NAME;

* DIR_DB_BACKUP = 
                                 APP_PATH + "myDB.db";

Por ultimo aclarar que lo que hacen estas funciones son copiar y pegar el archivo de la base de dato en el destino que elegimos con el nombre que nosotros definimos al archivo.
Hay otras formas de hacer el backup "Mas Segura" pero esta me parece la mas sencilla y anda bien

Un saludo

La Clase Estatica Mensaje

Bueno esta clase es útil para mantener prolijidad y claridad en nuestro código. Evitar copiar y pegar un código, haciéndolo repetitivo

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.view.Gravity;
import android.widget.Toast;

import app.com.kiosquin_v43.inicio.LoginActividad;
import app.com.kiosquin_v43.ventas.VendedorActividad;

public class Mensaje {
 
 public static void ver(String mensaje, Context context){
  Toast toast = Toast.makeText(context,
       mensaje, Toast.LENGTH_SHORT);
      toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
      toast.show();
 }

 public static void salir(final Context context){

  new AlertDialog.Builder(context)
    .setIcon(android.R.drawable.ic_dialog_alert)
    .setTitle("Volver al login")
    .setMessage("Estas seguro?")
    .setNegativeButton("No", null)//sin listener
    .setPositiveButton("Si",
      new DialogInterface.OnClickListener() {
       //un listener que al pulsar, cierre la aplicacion
       @Override
       public void onClick(DialogInterface dialog, int which){

        Intent main = new Intent(context, Clase_login_inicial.class)
          .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        context.startActivity(main);
       }
      }).show();
 }
}
 

La primer función estática ver tiene dos parámetros, el primero un String que sera el mensaje a mostrar, y el segundo el contexto a donde se quiere mostrar. Lo que hace es muy simple, genera un mensaje Toast bien centrado y lo muestra. Ejemplo:

                                               Mensaje.ver("Muestro mensaje", this);

La segunda función estática salir, básicamente sirve preguntar si quiere salir de una actividad al apretar el botón Back (tienen que configurarlo). Crea un AlertDialog.Builder, con un titulo, un msj y 2 botones. Luego lo muestra

@Override //se agrega en la actividad donde quiere incorporar el cartel
public void onBackPressed() { //Implemento menu para salir al login

            Mensaje.salir(this)
}

domingo, 24 de abril de 2016

Clase Estatica Fecha en Android

Hola gente! Voy a mostrar una clase estática Fecha que les puede ser de utilidad. Importante al momento de tener que trabajar con la clase Date y necesiten guardarlo en una Base de Datos o viceversa.

Para el que desconoce como darle formato a la fecha, debería ver SimpleDateFormat.

los 2 formatos mas utilizado por mi, en un Date completo, es:

SimpleDateFormat("dd/MM/yyyy HH:mm:ss")

donde la HH, en mayúscula, hace referencia a el formato de 24h, el otro formato es:

SimpleDateFormat("dd/MM/yyyy hh:mm:ss a")

donde hh, en minuscula, nos muestra el formato de 12h, y la a, se refiere cambio pm y am.



public class Fecha {

    public static String actual(){
        SimpleDateFormat formateador = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        //SimpleDateFormat formateador = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss a");
        return formateador.format(new Date());
    }
    public static Date getDia(String fecha){
        //SimpleDateFormat formateador = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss a");
        SimpleDateFormat formateador = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        try {
            return formateador.parse(fecha);
        } catch (ParseException e) {
            return null;
        }
    }
    public static String getDia(Date fecha){
        SimpleDateFormat formateador = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        //SimpleDateFormat formateador = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss a");
        if ( fecha != null )
        {
            return formateador.format(fecha);
        } else {
            return "";
        }
    }

    public static String getDiaSinHora(Date fecha){
        SimpleDateFormat formateador = new SimpleDateFormat("dd/MM/yyyy");
        if ( fecha != null )
        {
            return formateador.format(fecha);
        } else {
            return "";
        }
    }
    public static String getDiaSinHora(String fecha){
        SimpleDateFormat formateador = new SimpleDateFormat("dd/MM/yyyy");
        try {
            return formateador.format(formateador.parse(fecha));
        } catch (ParseException e) {
            return "";
        }
    }
}

No es muy difícil de leer, básicamente funciona como la clase Integer cuando queremos convertir un string a int, solo que dependiendo el formato que busquemos en Date sera la función.

Aquí un ejemplo:

...
editTextFecha.setText("Fecha: "+Fecha.getDia(new Date()));
...

sábado, 23 de abril de 2016

Capturar evento de botón con setOnClickListener

Hola, En esta entrada mostrare algo simple pero útil, que le dará claridad y prolijidad a sus códigos, tanto para ustedes como para el que lo intente seguir, para un posible mantenimiento o lo que sea.

Esto esta apuntado a gente que se esta iniciando en el mundo de programación en android.

Cuando nos enseñaban android por primera vez, nos muestran que para capturar eventos debemos implementar OnClickListener, luego hacer la funcion onClick(View v) y dentro de ella hacer lo que se haga con el botón.. pero ¿que pasa si tenes mas de un botón? hay que degenerar el código con tantos if como botones tenga. O un Switch si son muchísimos.

Esta practica que les pasare a explicar hay que hacerlo para cada botón que vinculemos con el layout.

Así es como nos enseñan por primera vez




public class LoginActividad extends Activity implements OnClickListener{
 
 TextView tvUsuarioRegistro;
 EditText etNombre, etPass;
 Button bEntrar;
 Usuario usuario;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.ini_login);
  
  tvUsuarioRegistro = (TextView) findViewById(R.id.tvUsuarioRegistroClic);
  etNombre = (EditText) findViewById(R.id.etUsuarioNombre);
  etPass = (EditText) findViewById(R.id.etUsuarioPass);
  bEntrar = (Button) findViewById(R.id.btUsuarioEntrar);

  bEntrar.setOnClickListener(this);
  tvUsuarioRegistro.setOnClickListener(this);
  
  
 
  @Override
  public void onClick(View v) {
    if(v.getId()==findViewById(R.id.btUsuarioEntrar).getId()){
     
     //Aqui va lo que el boton debe hacer, una vez presionado  
    }
    if(v.getId()==findViewById(R.id.tvUsuarioRegistroClic).getId()){
     
     Intent actividad = new Intent(LoginActividad.this, RegistroActividad.class);
    startActivity(actividad);  
    }
           
  }  
 }
}
 

Y así es deberia;



public class LoginActividad extends Activity {
 
 TextView tvUsuarioRegistro;
 EditText etNombre, etPass;
 Button bEntrar;
 Usuario usuario;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.ini_login);
  
  tvUsuarioRegistro = (TextView) findViewById(R.id.tvUsuarioRegistroClic);
  etNombre = (EditText) findViewById(R.id.etUsuarioNombre);
  etPass = (EditText) findViewById(R.id.etUsuarioPass);
  bEntrar = (Button) findViewById(R.id.btUsuarioEntrar);

  bEntrar.setOnClickListener(new OnClickListener() {
 
   @Override
   public void onClick(View v) {
    
    //Aqui va lo que el boton debe hacer, una vez presionado       
   }  
  }); 
  tvUsuarioRegistro.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    Intent actividad = new Intent(LoginActividad.this, RegistroActividad.class);
    startActivity(actividad); 
   }  
  });
 }
}

No es que sea mas sencillo, ni nos ahorraremos de escribir, pero la claridad y prolijidad suma a la hora de mantener un código

Espero que les sirva o no, dependerá de como se sienta mas cómodo cada uno.
Un saludo