guardar coordenadas en mysql usando retrofit 2

Hoy veremos como guardar las coordenadas en mysql usando la librería retrofit 2. Ya hace buen tiempo hicimos un tutorial de como guardar las coordenadas en mysql con la librería apache, también hicimos otros de como guardar las coordenadas en mysql usando la librería volley pero como sabrán la librería apache ya esta en desuso y aunque me duela decirlo volley no es tan popular como retrofit, entonces hoy decidimos actualizar este pequeño curso en android. Si eres nuevo con esta librería y tienes mas dudas o simplemente quieres dominarla te aconsejo que ingreses a este enlace: ejemplo básico de retrofit , donde veras un ejemplo básico de como utilizar la librería retrofit, sin mas que decir empezamos de una vez con el curso.

 

Guardar coordenadas en mysql usando retrofit 2

BASE DE DATOS

Empezamos creando una base de datos en mi caso le llamare gpsbd y luego crearemos una tabla llamada gps donde tendremos cuatro campos como se ven en el código que le estoy dejando lineas mas abajo:

CREATE TABLE `gps` (
  `id` int(11) NOT NULL,
  `direccion` varchar(100) NOT NULL,
  `lat` float NOT NULL,
  `lon` float NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `gps`
  ADD PRIMARY KEY (`id`);

ALTER TABLE `gps`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

 

WEBSERVICES

En este caso ya saben que siempre utilizo el modelo por capas, osea diferente parte de código dentro de carpetas diferentes para mejorar el orden de la programación, en este sentido creare tres carpetas y deben ser las siguientes como se muestra en la imagen:

web services

Carpeta datos En esta carpeta ingresaremos un archivo php llamado Conexión.clase.php que nos servirá para hacer la conexión entre nuestra base de datos y la webservices. Recuerda cambiar tus datos en la linea 6,7 y 8 con los de tu servidor o hosting. Conexion.clase.php

<?php
    class Conexion {
        protected $dblink;
                
        function __construct() {
            $servidor = "mysql:host=localhost;port=3306;dbname=gpsbd";
            $usuario = "root";
            $clave = "12345";          
            $this->dblink = new PDO($servidor, $usuario, $clave);
            $this->dblink->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->dblink->exec("SET NAMES utf8");
        }
        
}
?>

  carpeta negocios En esta carpeta ingresaremos nuestra clase php llamada Gps.clase.php que nos servirá para utilizar los atributos que emplearemos en este caso las coordenadas como se ve en las lineas 4,5,6,7 y también la función agregar en la linea 48 que nos permitirá agregar las coordenadas en nuestra tabla gps: Gps.clase.php

<?php
    require_once '../datos/Conexion.clase.php';
    class Gps extends Conexion{
        private $codigo;
        private $direccion;
        private $lat;
        private $lon;
        public function getCodigo()
        {
            return $this->codigo;
        }
        
        public function setCodigo($codigo)
        {
            $this->codigo = $codigo;
            return $this;
        }
  public function getDireccion()
  {
      return $this->direccion;
  }
  
  public function setDireccion($direccion)
  {
      $this->direccion = $direccion;
      return $this;
  }
  public function getLat()
  {
      return $this->lat;
  }
  
  public function setLat($lat)
  {
      $this->lat = $lat;
      return $this;
  }
  public function getLon()
  {
      return $this->lon;
  }
  
  public function setLon($lon)
  {
      $this->lon = $lon;
      return $this;
  }
  public function agregar() {
            $sql = "insert into gps( direccion, lat, lon) values(:dir, :lat, :lon);";
            
            $sentencia = $this->dblink->prepare($sql);
            $direccion = $this->getDireccion();
            $lat = $this->getLat();
            $lon = $this->getLon();
            $sentencia->bindParam(":dir",  $direccion);
            $sentencia->bindParam(":lat", $lat);
            $sentencia->bindParam(":lon", $lon );
            $resultado = $sentencia->execute();
            
            if ($resultado != 1){
                //ocurrio un error al insertar
                return FALSE;
            }
            
            //Insertó correctamente
            return TRUE;
            
        }
    }

  carpeta web-services En esta carpeta tendremos un archivo php llamado registrar-gps.php este archivo nos servirá para consumir nuestra api webservices y podremos registrar los datos que son enviados desde la app hacia la base de datos: registrar-gps.php

<?php
    if  (
            ( !isset(  $_POST["direccion"]        ) )     ||
            ( !isset(  $_POST["lat"]              ) )     ||
            ( !isset(  $_POST["lon"]              ) )      
        )
        {
            $respuesta = array(
                "estado"=>"error"
            );
            
            echo json_encode($respuesta);
            exit();
        }
        
        
        $direccion      = $_POST["direccion"];
        $lat       = $_POST["lat"];
        $lon          = $_POST["lon"];
        
        require_once '../negocio/Gps.clase.php';
        $objGps = new Gps();
        $objGps->setDireccion($direccion);
        $objGps->setLat($lat);
        $objGps->setLon($lon);
        
        if ($objGps->agregar()==TRUE){
            $respuesta = array(
                "estado"=>"exito"
            );
        }else{
            $respuesta = array(
                "estado"=>"error",
                "datos"=>""
            );
        }
        
        //echo json_encode($respuesta);
        echo json_encode($respuesta);
        
?>

 

CONSTRUYENDO LA APP

  Damos permiso en el AndroidManifest Aquí debemos dar permiso tanto para el gps como para el acceso del Internet, como se observa en las lineas 4,5,6. Quiero aclarar que damos permisos al Internet, porque luego de usar las coordenadas nuestra aplicación usara la clase Geocoder y esta necesita del Internet para poder transformarlas en direcciones de las calles. AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.androfast.server.appgpsbdvolley">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

  Agregando la librería retrofit Debemos agregar la librería retrofit dentro de nuestro archivo build.gradle, para ser mas exacto dentro de dependencies como se muestra a continuación en la linea 9 es la lubreria retrofit, pero también necesitamos parsear nuestro código entonces agregamos dos dependencias  en la linea 12 y 13 y por ultimo agregamos dos dependencias butterknife en las lineas 16,17, no es necesario estas dependencia para trabajar con retrofit, pues su función es mas bien para mejorar el código, en vez de escribir largas lineas de código estas te permite cortar dicho código:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    // Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.1.0'

    // JSON Parsing
    implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
    
    //Acortador de codigo
    implementation 'com.jakewharton:butterknife:8.4.0'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
}

  Agregando modo gráfico Para este ejemplo tan sencillo solo usaremos tres textview y un botón como se muestra en la siguiente imagen, esto sera agregado en nuestro activity_main que tenemos por defecto al momento de crear la app. activity_main

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/txtLatitud"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="52dp"
        android:text="Latitud"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/txtLongitud"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="28dp"
        android:text="Longitud"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/txtLatitud" />
    <TextView
        android:id="@+id/txtDireccion"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="40dp"
        android:text="Direccion"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/txtLongitud" />
    <Button
        android:id="@+id/btnGuardar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="64dp"
        android:text="GUARDAR"
        android:textSize="18sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/txtDireccion" />
</android.support.constraint.ConstraintLayout>

Agregando clases

Para este pequeño ejercicio quería comentarles que solo tendremos dos clases y una interface, lo haré de una forma tan sencilla que verán que armar un proyecto con retrofit2  no es nada del otro mundo.

Http

Empezaremos creando la clase Http, vamos aclarar algunas cosas en primer lugar, esta clase sirve para apuntar la dirección de nuestra webservices , como ves la dirección esta incompleta por el archivo PHP la llamaremos en nuestra interface Api, otro punto aclarar es que si haces las pruebas de forma local uses la ip de tu computador y si lo pruebas en un hosting uses el dominio y debes escribirlo de forma correcta respetando si es http// o https//.

public class Http {
    public static String BASE_URL = "http://192.168.8.170/gpsbd/web-services/";
}

 

Api

Si no estas acostumbrado a trabajar con retrofit tal vez te parezca raro los archivos de tipo interface, pero dejae contarte que este tiene una importante función y una arquitectura sencilla pues nos permite hacer de puente entre la web services y la app, en la linea 14 nos fijamos que estamos llamando al archivo PHP de nuestra web services que hace el guardado  mientras que en las lineas 15,16,17 estamos llamando a nuestros objetos de tipos Json que nos servirán para hacer el registro de los datos del Gps.

import org.json.JSONObject;

import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;

/**
 * Created by Androfast on 16/03/2019.
 */

public interface Api {
    @FormUrlEncoded
    @POST("registrar-gps.php")
    Call<JSONObject> coordenadas(@Field("direccion") String direccion,
                                 @Field("lat") String lat,
                                 @Field("lon") String lon);
}

 

MainActivity

En esta clase se obtiene las coordenadas y la dirección para luego ser asignadas a los textview y posteriormente guardarlos en mysql.

import android.Manifest;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;


import org.json.JSONObject;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.txtDireccion)
    TextView direccion;
    @BindView(R.id.txtLatitud)
    TextView latitud;
    @BindView(R.id.txtLongitud)
    TextView longitud;

    private ProgressDialog progress;

    @OnClick(R.id.btnGuardar) void datos() {
        // hacer un diálogo de progreso
        progress = new ProgressDialog(this);
        progress.setCancelable(false);
        progress.setMessage("Cargando ...");
        progress.show();

        // obtener datos de los textview
        String Sdireccion = direccion.getText().toString();
        String Slatitud = latitud.getText().toString();
        String Slongitud = longitud.getText().toString();



        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Http.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        Api api = retrofit.create(Api.class);
        Call<JSONObject> call = api.coordenadas(Sdireccion, Slatitud, Slongitud);
        call.enqueue(new Callback<JSONObject>() {
            @Override
            public void onResponse(Call<JSONObject> call, Response<JSONObject> response) {

                if(response!=null && response.isSuccessful()) {
                    progress.dismiss();
                    Toast.makeText(MainActivity.this, "coordenadas registradas", Toast.LENGTH_SHORT).show();
                }
            }
            @Override
            public void onFailure(Call<JSONObject> call, Throwable t) {
                t.printStackTrace();
                progress.dismiss();
                Toast.makeText(MainActivity.this, "Hubo un Error!", Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        locationStart();
    }


    private void locationStart() {
        LocationManager mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        Localizacion Local = new Localizacion();
        Local.setMainActivity(this);
        final boolean gpsEnabled = mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        if (!gpsEnabled) {
            Intent settingsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            startActivity(settingsIntent);
        }
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,}, 1000);
            return;
        }
        mlocManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, (LocationListener) Local);
        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, (LocationListener) Local);
        latitud.setText("Localización agregada");
        direccion.setText("");
    }
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == 1000) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                locationStart();
                return;
            }
        }
    }
    public void setLocation(Location loc) {
        //Obtener la direccion de la calle a partir de la latitud y la longitud
        if (loc.getLatitude() != 0.0 && loc.getLongitude() != 0.0) {
            try {
                Geocoder geocoder = new Geocoder(this, Locale.getDefault());
                List<Address> list = geocoder.getFromLocation(
                        loc.getLatitude(), loc.getLongitude(), 1);
                if (!list.isEmpty()) {
                    Address DirCalle = list.get(0);
                    direccion.setText(DirCalle.getAddressLine(0));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /* Aqui empieza la Clase Localizacion */
    public class Localizacion implements LocationListener {
        MainActivity mainActivity;
        public MainActivity getMainActivity() {
            return mainActivity;
        }
        public void setMainActivity(MainActivity mainActivity) {
            this.mainActivity = mainActivity;
        }
        @Override
        public void onLocationChanged(Location loc) {
            // Este metodo se ejecuta cada vez que el GPS recibe nuevas coordenadas
            // debido a la deteccion de un cambio de ubicacion
            loc.getLatitude();
            loc.getLongitude();
            String sLatitud = String.valueOf(loc.getLatitude());
            String sLongitud = String.valueOf(loc.getLongitude());
            latitud.setText(sLatitud);
            longitud.setText(sLongitud);
            this.mainActivity.setLocation(loc);
        }
        @Override
        public void onProviderDisabled(String provider) {
            // Este metodo se ejecuta cuando el GPS es desactivado
            latitud.setText("GPS Desactivado");
        }
        @Override
        public void onProviderEnabled(String provider) {
            // Este metodo se ejecuta cuando el GPS es activado
            latitud.setText("GPS Activado");
        }
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            switch (status) {
                case LocationProvider.AVAILABLE:
                    Log.d("debug", "LocationProvider.AVAILABLE");
                    break;
                case LocationProvider.OUT_OF_SERVICE:
                    Log.d("debug", "LocationProvider.OUT_OF_SERVICE");
                    break;
                case LocationProvider.TEMPORARILY_UNAVAILABLE:
                    Log.d("debug", "LocationProvider.TEMPORARILY_UNAVAILABLE");
                    break;
            }
        }
    }
}

  Espero te haya servido el tutorial a continuación te dejos los enlaces de descarga de la app.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

WhatsApp chat