«

»

dic 03 2012

Android Services (4/4) – Comunicación entre procesos con Messenger

Hola a todos, espero que hayáis disfrutado de estos post, los he hecho con todo el cariño que podía así que espero que lo disfrutéis con cariño igualmente :). En este último post de esta secuencia de posts relacionados con Services voy a hablar sobre la comunicación entre procesos a través de Messenger. Espero que lo useis :) Al final del post os escribo un pequeño cuento que espero que también os guste. :)

 

 

Comunicación entre procesos con Messenger

Ahora demostraremos cómo establecer una comunicación mediante una Activity y un Service usando la clase Messenger y Handler.

Creamos un nuevo proyecto llamado “es.androcode.android.ownservice.messenger” con una Activity llamada MainActivity por ejemplo.
Creamos el siguiente AndroidManifest.xml:
 

        <?xml version="1.0" encoding="utf-8"?>
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="es.androcode.android.ownservice.messenger"
         android:versionCode="1"
         android:versionName="1.0" >

        <uses-sdk android:minSdkVersion="15" />
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

        <application
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>

            <service android:name="DownloadServiceMessenger" >
            </service>
         </application>

        </manifest> 
        

 

A continuación creamos la clase DownloadServiceMessenger que extiende de Service:
 

     package es.androcode.android.ownservice.messenger;

     import java.io.File;
     import java.io.FileOutputStream; 
     import java.io.IOException;
     import java.io.InputStream;
     import java.io.InputStreamReader;
     import java.net.URL;

     import android.app.Activity;
     import android.app.Service;
     import android.content.Intent;
     import android.os.Bundle;
     import android.os.Environment;
     import android.os.Handler;
     import android.os.IBinder;
     import android.os.Message;
     import android.os.Messenger;
     import android.os.StrictMode;
     import android.util.Log;

     public class DownloadServiceMessenger extends Service {
       public static final String FILENAME = "fileName";
       public static final String URLPATH = "urlPath";
       public static final String RESULTPATH = "urlPath";
       private int result = Activity.RESULT_CANCELED;

  
       //Se usa para recibir los mensajes de la Activity
       final Messenger inMessenger = new Messenger(new IncomingHandler());
      //Se usa para enviar mensajes a la Activity
       private Messenger outMessenger;

       public DownloadServiceMessenger() {
         super();
       // NO HACER ESTO!
      // Conexión se ejecutará en el hilo principal
         StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
         .permitAll().build();
        StrictMode.setThreadPolicy(policy);
      }

       class IncomingHandler extends Handler {
          @Override
          public void handleMessage(Message msg) {
          Log.e("Mensaje", "Obtenemos Message");
          Bundle data = msg.getData();
          String urlPath = data.getString(DownloadServiceMessenger.URLPATH);
          String fileName = data.getString(DownloadServiceMessenger.FILENAME);
          String outputPath = download(urlPath, fileName);

          Message backMsg = Message.obtain();
          backMsg.arg1 = result;
          Bundle bundle = new Bundle();
          bundle.putString(RESULTPATH, outputPath);
          backMsg.setData(bundle);
          try {
             outMessenger.send(backMsg);
          } catch (android.os.RemoteException e1) {
             Log.w(getClass().getName(), "Excepción enviando mensaje", e1);
         }
       }
     }

     private String download(String urlPath, String fileName) {
        File output = new File(Environment.getExternalStorageDirectory(),fileName);
        if (output.exists()) {
           output.delete();
        }

        InputStream stream = null;
        FileOutputStream fos = null;
        try {
           URL url = new URL(urlPath);
           stream = url.openConnection().getInputStream();
           InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
           fos = new FileOutputStream(output.getPath());
           int next = -1;
           while ((next = reader.read()) != -1) {
             fos.write(next);
           }
           // Sucessful finished
           result = Activity.RESULT_OK;
        } catch (Exception e) {
           e.printStackTrace();
        } finally {
          if (stream != null) {
          try {
             stream.close();
           } catch (IOException e) {
             e.printStackTrace();
           }
        }
        if (fos != null) {
         try {
           fos.close();
         } catch (IOException e) {
           e.printStackTrace();
         }
       }
    }
     return output.getAbsolutePath();

    }

    @Override
    public IBinder onBind(Intent intent) {
     Bundle extras = intent.getExtras();
     // Get messager from the Activity
     if (extras != null) {
       outMessenger = (Messenger) extras.get("MESSENGER");
      }
     // Return our messenger to the Activity to get commands
        return inMessenger.getBinder();
    }
   } 
   

 
El layout será el siguiente
 

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical" >
      <Button
         android:id="@+id/button1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:onClick="onClick"
         android:text="Boton" />
    </LinearLayout> 
  

 

Ahora cambiamos el MainActivity al siguiente:
 

    package es.androcode.android.ownservice.messenger;

    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    import android.os.Messenger;
    import android.os.RemoteException;
    import android.view.View;
    import android.widget.Toast;

     public class MainActivity extends Activity {
        Messenger messenger = null;

       private Handler handler = new Handler() {
        public void handleMessage(Message message) {
             Bundle data = message.getData();
             if (message.arg1 == RESULT_OK && data != null) {
                 String text = data
                       .getString(DownloadServiceMessenger.RESULTPATH);
                 Toast.makeText(MainActivity.this, text, Toast.LENGTH_LONG).show();
              }
         }
       };

     @Override
     public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
      }

     private ServiceConnection conn = new ServiceConnection() {

       public void onServiceConnected(ComponentName className, IBinder binder) {
          messenger = new Messenger(binder);
        }

      public void onServiceDisconnected(ComponentName className) {
         messenger = null;
       }
     };

      protected void onResume() {
        super.onResume();
        Toast.makeText(this, "OnResume called", Toast.LENGTH_SHORT).show();
        Intent intent = null;
               intent = new Intent(this, DownloadServiceMessenger.class);
         //Creamos un nuevo Messenger para la comunicación    
        // Desde el Service al Activity
        Messenger messenger = new Messenger(handler);
        intent.putExtra("MESSENGER", messenger);

       bindService(intent, conn, Context.BIND_AUTO_CREATE);
      }

     @Override
     protected void onPause() {
       super.onPause();
       unbindService(conn);
     }

     public void onClick(View view) {
        Message msg = Message.obtain();

        try {
          Bundle bundle = new Bundle();
          bundle.putString(DownloadServiceMessenger.FILENAME, "index.html");
          bundle.putString(DownloadServiceMessenger.URLPATH,"http://www.androcode.es/index.html");
          msg.setData(bundle);
          messenger.send(msg);
        } catch (RemoteException e) {
          e.printStackTrace();
        }
     }
    } 
    

 
Cada cual que customize su propia url.

Con esto acabo la primera tirada de posts de este tutorial sobre Services. Espero que os hayan gustado los posts sobre services.
 
Os escribo ahora un pequeño cuento que ayer mismo mi tío me contó. Nos viene bien a los androides porque, a veces es bastante costoso que nos salga algo a la primera, y bueno, siempre hay que echarle ganas para conseguir el objetivo.
 
El cuento o mini-cuento se llama “El arquero y la luna” y dice…
“Un arquero quiso cazar la luna.
Noche tras noche, sin descansar, lanzó sus flechas hacia el astro.
Los vecinos comenzaron a burlarse de él.
Inmutable, siguió lanzando sus flechas.
Nunca cazó la luna, pero se convirtió en el mejor arquero del mundo.”

Pues nada, que sigamos intentando las cosas, aunque al principio sean difíciles a la vista de otros y de nosotros mismos.

 
Fuente | http://www.vogella.com

 

Espero que os haya gustado y si es así no lo dudéis y ¡¡compartid lo aprendido!!

 

Acerca del autor

InmaculadaAlcon

Me entusiasma aprender y desarrollar software de calidad. Crear aplicaciones para Android es lo que más me gusta y por lo que me muevo cada día. Soy muy flamenca, enamorada de Sevilla y con el sueño de trabajar algún día en Silicon Valley. Me encanta el fútbol y soy del Betis manque pierda.

  • Raul

    Muchas gracias por los tutoriales!!! Cada vez que tenga que utilizar algún Service, los miraré para aprovecharlos. Muy bonito el cuento….. jejeje

    • http://www.linkedin.com/in/inmaculadaalcon InmaculadaAlcon

      Muchas gracias a ti Raul por leerlos y poder haberte servido de ayuda es una satisfacción y me anima a seguir esta linea.
      El cuento está chulo! jejeje
      Un saludo y no dudes en preguntar cualquier cosa que se te ofrezca. :)

  • Alejandro

    Muchas gracias por la explicación. Ahora lo entiendo todo mejor!!

  • http://www.baviux.com Sergio Viudes

    Gracias por estos 4 tutoriales. Son muy útiles! :)

    Seguid así!

  • Robert

    Hola muchas gracias por el tutorial, una duda que tengo ¿el servicio cuando se para?

  • tomas

    hola muy buenos los tutoriales de los mejores explicados que he leído muchas gracias me sirve de ayuda ,pero no explicas como hacer un service sin un loyout es decir una aplicacion que se inicia y hace una tarea determinada pero que no necesita mostrar nada al usuario por ejemplo cuando hay una actualización de una app o simplemente un optimizador de algo…

  • Adrian

    Es muy bueno todo lo que escribes , tengo una duda como puedo hacer un servicio que consulte un webservices cada cierto tiempo

  • Ivan Aucancela

    saludos cordiales ,,,,, una consulta …. es posible enviar un sms cuando se realiza una determinada accion ……..a un numero determinado … u correo electronico

  • guillermo

    Hola, antes que nada muchas gracias por los tutoriales, son muy claros e interesantes.
    Soy nuevo en android y tengo un proyecto en el cual necesito usarlo.
    Basicamente necesito hacer una aplicación la cual se comunicará con un hardware externo a través de una interface serie asincrónica.
    La aplicación tendrá varias actividades, y sólo desde alguna de ellas necesito comunicarme con el dispositivo externo.
    En el momento que una actividad requiere de los datos que provienen del dispositivo externo, los debe recibir periodicamente.
    De acuerdo a lo que estuve leyendo tengo la impresión que la gestión de la comunicación con mi dispositivo externo podría realizarla desde una servicio que se ejecute en un hilo propio. La idéa sería que cuando la actividad requiera recibir los datos inicie el servicio. Una vez iniciado el servicio, este gestionaría la comunicación y cada vez que tenga datos disponibles debería informarle a la actividad para que esta los procese.
    Todavía entiendo bien como hacer para que el servicio le pase la información a la actividad.
    ¿Me podrías decir si te parece adecuada esta aproximación?.
    Cualquier comentario será bienvenido.
    Saludos y gracias