En este tutorial crearemos una sencilla aplicación para android que nos permitirá subir una imagen a un servidor web. La imagen que subiremos sera una foto que tomemos con nuestra cámara, pero aquí lo importante no subiremos archivos grandes sino archivos que no excedan los 1MB de peso esto porque para subir archivos pesados se utiliza otra forma que veremos en post futuros.
Necesitamos
Nivel: Intermedio
Tiempo: 15 minutos
Tutorial
El APIREST
Antes de desarrollar la aplicación android, nos detendremos un momento para ver lo que sera nuestro API REST, no construiremos nada complicado sino por el contrario nuestra API consistirá en un solo archivo PHP el cual estará a la espera de un objeto JSON con la siguiente forma:
{ "encodedImage": "\/9j\/4AAQSkZJRgABAQAAAQABAAD\.." }
Como vemos nuestro JSON contiene un solo parámetro que es «encodeImage» que contiene en una cadena la imagen codificada en Base64, mientras mas grande sea la imagen a enviar, más grande sera la cadena que se forme y podremos tener algunos problemas, es por eso que las imagen que usemos no deben exceder los 1000×1000 pixeles a lo mucho.
Nuestro apirest.php tendrá el siguiente codigo
<?php $data = file_get_contents("php://input"); $datares = array( 'Result'=>"200" ); saveJSON($data); print ( json_encode( $datares ) ); function saveJSON($data) { $file = 'photo.txt'; $success = file_put_contents($file, $data); } ?>
Como se ve, nuestra sencilla API, espera un JSON el cual guarda en un archivo de texto «photo.txt«, esto para que veas como es que se envía la imagen codificada. Nuestra api debe responder cuando le llega la petición POST y responde un JSON con una variable «Result» con valor de 200, esto para informar de que se recibió la imagen correctamente, por la sencillez de nuestra aplicación no nos detendremos en más detalles como control de errores o cosas por el estilo, suponemos que nos llega un JSON con la forma indicada más arriba y listo 🙂
Cuando subamos una imagen, más o menos esto es lo que veras en tu navegador:
Para terminar el trabajo en el servidor web, creamos un nuevo archivo php con el nombre de «photo.php«, este archivo tiene la tarea de leer el archivo «photo.txt» creado cuando se sube una imagen al servidor, y decodificar su contenido para transformar y mostrar en pantalla la imagen restaurada. El codigo es el siguiente:
<?php if (file_exists('photo.txt')) { header("Content-type: image/gif"); $json = file_get_contents('photo.txt'); $obj = json_decode($json); echo base64_decode( $obj->{'encodedImage'} ); } else { echo 'No se cargo ninguna fotografia'; } ?>
Una vez creados los archivos y subidos al servidor, podemos comenzar a crear la aplicación android.
1. El proyecto
Crea un nuevo proyecto android en eclipse con el nombre de «UploadImageToServer«, deja el MainActivity que se crea por defecto y añade un par de clases como se ve en la imagen de abajo:
2. Interfaz
Abre el archivo «Strings.xml» y cambia el contenido por:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Upload Image to Server</string> <string name="action_settings">Settings</string> <string name="strUpload">Subir al servidor</string> </resources>
A continuación, abre el archivo «activity_main.xml» que esta en la carpeta Layout y reemplaza el contenido por:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <ImageView android:id="@+id/photo" android:layout_width="180dp" android:layout_height="180dp" android:layout_gravity="center" android:src="@drawable/ic_launcher" /> <Button android:id="@+id/btnUpload" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="26dp" android:text="@string/strUpload" /> </LinearLayout>
En la vista diseño podremos ver algo como esto
Abre el archivo AndroidManifest.xml y agrega el permiso para internet
<uses-permission android:name="android.permission.INTERNET" />
3. APIREST
En nuestra clase «ApiRest.java» declaramos el método uploadPhoto(…) para subir la imagen codificada en Base64 al servidor mediante POST y JSON, el código es el siguiente:
package com.bolivia.uploadimage; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicHeader; import org.apache.http.protocol.HTTP; import org.json.JSONException; import org.json.JSONObject; public class ApiRest { private final String HTTP_EVENT="http://tuweb.net/api/apirest.php"; /** * Envia la imagen codificada al servidor * @param String encodedImage Imagen codificada con Base64 * @throws IOException * @throws ClientProtocolException * @throws JSONException * */ public Boolean uploadPhoto(String encodedImage) throws ClientProtocolException, IOException, JSONException { HttpClient httpclient = new DefaultHttpClient(); //url y tipo de contenido HttpPost httppost = new HttpPost(HTTP_EVENT); httppost.addHeader("Content-Type", "application/json"); //forma el JSON y tipo de contenido JSONObject jsonObject = new JSONObject(); jsonObject.put("encodedImage", encodedImage ); // StringEntity stringEntity = new StringEntity( jsonObject.toString()); stringEntity.setContentType( (Header) new BasicHeader(HTTP.CONTENT_TYPE, "application/json")); httppost.setEntity(stringEntity); //ejecuta HttpResponse response = httpclient.execute(httppost); //obtiene la respuesta y transorma a objeto JSON String jsonResult = inputStreamToString(response.getEntity().getContent()).toString(); JSONObject object = new JSONObject(jsonResult); if( object.getString("Result").equals("200")) { return true; } return false; } /** * Transforma el InputStream en un String * @return StringBuilder * */ private StringBuilder inputStreamToString(InputStream is) { String line = ""; StringBuilder stringBuilder = new StringBuilder(); BufferedReader rd = new BufferedReader( new InputStreamReader(is) ); try { while( (line = rd.readLine()) != null ) { stringBuilder.append(line); } } catch( IOException e) { e.printStackTrace(); } return stringBuilder; } }//end:ApiRest
4. Tarea en segundo plano
Como ya se vio en post anteriores, android no nos permite ejecutar tareas que puedan colgar la aplicación en el hilo principal por tal motivo debemos hacer uso dela clase AsyncTask que nos permite ejecutar en un nuevo hilo el método para subir el archivo al servidor.
package com.bolivia.uploadimage; import java.io.IOException; import org.apache.http.client.ClientProtocolException; import org.json.JSONException; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.os.AsyncTask; public class MyAsyncTask extends AsyncTask<String,Void,Boolean>{ private ProgressDialog progressDialog; AlertDialog.Builder builder; private Context context; /**Constructor de clase */ public MyAsyncTask(Context context) { this.context = context; builder = new AlertDialog.Builder(context); } /** * Antes de comenzar la tarea muestra el progressDialog * */ @Override protected void onPreExecute() { super.onPreExecute(); progressDialog = ProgressDialog.show(context, "Por favor espere", "Subiendo..."); } /** * @param * */ @Override protected Boolean doInBackground(String... params) { Boolean r = false; ApiRest apiRest = new ApiRest(); try { r = apiRest.uploadPhoto(params[0]); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } return r; } /** * Cuando se termina de ejecutar, cierra el progressDialog y avisa * **/ @Override protected void onPostExecute(Boolean resul) { progressDialog.dismiss(); if( resul ) { builder.setMessage("Imagen subida al servidor") .setTitle("JC le informa") .setNeutralButton("Aceptar", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog,int which) { dialog.cancel(); } }).create().show(); } else { builder.setMessage("No se pudo subir la imagen") .setTitle("JC le informa") .setNeutralButton("Aceptar", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog,int which) { dialog.cancel(); } }).create().show(); } } }
5. Unimos todo
Ya para terminar abre el MainActivity y reemplaza el código por:
package com.bolivia.uploadimage; import java.io.ByteArrayOutputStream; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Base64; import android.view.Menu; import android.view.View; import android.widget.Button; import android.widget.ImageView; public class MainActivity extends Activity { ImageView photo; Button button; Bitmap photobmp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Controles button = (Button)findViewById(R.id.btnUpload); photo = (ImageView)findViewById(R.id.photo); //evento click para cargar fotografia a la aplicación photo.setOnClickListener( new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intent, "Complete la acción usando..."), 1); }}); //evento click para comenzar a subir la imagen al servidor button.setOnClickListener( new View.OnClickListener() { public void onClick(View view) { //Codifica la imagen con Base64 ByteArrayOutputStream baos = new ByteArrayOutputStream(); photobmp.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] imageBytes = baos.toByteArray(); String encodedImage = Base64.encodeToString(imageBytes, Base64.DEFAULT); //Se ejecuta en segundo plano para no colgar la aplicacion new MyAsyncTask(MainActivity.this).execute(encodedImage); }}); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 1 && resultCode == RESULT_OK) { Uri selectedImageUri = data.getData(); String aaa = getRealPathFromURI(selectedImageUri); photobmp = BitmapFactory.decodeFile(aaa); photo.setImageBitmap(photobmp); } } /** * Obtiene la ruta del archivo de imagen en el dispositivo * @param Uri * @return String * */ public String getRealPathFromURI(Uri contentUri) { Cursor cursor = null; try { String[] proj = { MediaStore.Images.Media.DATA }; cursor = getApplicationContext().getContentResolver().query(contentUri, proj, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); } finally { if (cursor != null) { cursor.close(); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
Ejecuta la aplicación, carga una imagen presionando en la imagen con el logo de android y luego presiona el boton «Subir»
Después de unos segundos si todo salio bien, te aparecerá una ventana de dialogo avisando de que la imagen se subio con exito, en tu navegador ejecuta el photo.php y podrás ver la imagen que subiste, ejecuta también el photo.txt para ver la imagen codificada
¿Que es y para que sirve una imagen forense? Una imagen forense es un «clon» (copia bit a bit) de algún dispositivo como[...]
HeidiSQL es un software libre y de código abierto que permite conectarse a servidores MySQL, MariaDB, Percona Server, Mi[...]
En este post te hablaremos sobre una interesante herramienta para le lectura y edición de metadatos que no te debe de fa[...]
Hace tiempo me pidieron el código fuente de un juego de Puzzle de Neon Genesis Evangelión, este juego es completo, tiene[...]
AssertJ Swing es una biblioteca para Java que proporciona una interfaz fluida para la realización automatizada de prueba[...]
TikTok es una plataforma de microvideos muy popular entre los jóvenes el cual cuenta ya con millones de videos cortps de[...]