221 votos

Servicio API RESTful

Estoy mirando para hacer un servicio que puedo usar para hacer llamadas a una web basada en la api de rest. He pasado un par de días mirando a través de stackoverflow.com, lectura de libros y mirando a los artículos, mientras que jugar un poco con algo de código y no puedo conseguir nada de lo que estoy contento con el.

Básicamente quiero iniciar un servicio en aplicación de init, a continuación, quiero ser capaz de hacer que el servicio a petición de una url y devolver los resultados. En el mientras tanto, quiero ser capaz de mostrar una ventana de progreso o algo similar.

He creado un servicio que actualmente utiliza IDL, he leído en algún lugar que sólo necesitas este para la cruz de la aplicación de la comunicación, por lo que creo que estas necesidades excluyendo pero no está seguro de cómo hacer las devoluciones de llamada sin ella. También cuando me golpeó el post(Config.getURL("login"), values) la aplicación parece pausa por un tiempo (parece raro - pensó que la idea detrás del servicio que se ejecuta en un subproceso diferente!)

Actualmente tengo un servicio de post y get http métodos en el interior, un par de AIDL de archivos (para la comunicación de dos vías), un ServiceManager que trata de iniciar, detener, encuadernación, etc. para el servicio y estoy crear dinámicamente un Controlador con código específico para las devoluciones de llamada según sea necesario.

No quiero que nadie me dé una completa base de código para trabajar, pero algunos punteros sería muy apreciada; incluso si es para decir que estoy haciendo es completamente equivocado. Soy bastante nuevo en Android y Java dev así que si hay algún cegadoramente obvio errores aquí - por favor, no piensen que soy una basura desarrollador, estoy húmeda detrás de las orejas y agradecería que se le dijo a donde voy mal.

De todos modos, el código (en su mayoría) full (no quería poner este código en aquí, pero no sé a donde voy mal - disculpas de antemano):

public class RestfulAPIService extends Service  {

final RemoteCallbackList<IRemoteServiceCallback> mCallbacks = new RemoteCallbackList<IRemoteServiceCallback>();

public void onStart(Intent intent, int startId) {
    super.onStart(intent, startId);
}
public IBinder onBind(Intent intent) {
    return binder;
}
public void onCreate() {
    super.onCreate();
}
public void onDestroy() {
    super.onDestroy();
    mCallbacks.kill();
}
private final IRestfulService.Stub binder = new IRestfulService.Stub() {
    public void doLogin(String username, String password) {

        Message msg = new Message();
        Bundle data = new Bundle();
        HashMap<String, String> values = new HashMap<String, String>();
        values.put("username", username);
        values.put("password", password);
        String result = post(Config.getURL("login"), values);
        data.putString("response", result);
        msg.setData(data);
        msg.what = Config.ACTION_LOGIN;
        mHandler.sendMessage(msg);
    }

    public void registerCallback(IRemoteServiceCallback cb) {
        if (cb != null)
            mCallbacks.register(cb);
    }
};

private final Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {

        // Broadcast to all clients the new value.
        final int N = mCallbacks.beginBroadcast();
        for (int i = 0; i < N; i++) {
            try {
                switch (msg.what) {
                case Config.ACTION_LOGIN:
                    mCallbacks.getBroadcastItem(i).userLogIn( msg.getData().getString("response"));
                    break;
                default:
                    super.handleMessage(msg);
                    return;

                }
            } catch (RemoteException e) {
            }
        }
        mCallbacks.finishBroadcast();
    }
    public String post(String url, HashMap<String, String> namePairs) {...}
    public String get(String url) {...}
};

Un par de AIDL archivos:

package com.something.android

oneway interface IRemoteServiceCallback {
    void userLogIn(String result);
}

y

package com.something.android
import com.something.android.IRemoteServiceCallback;

interface IRestfulService {
    void doLogin(in String username, in String password);
    void registerCallback(IRemoteServiceCallback cb);
}

y el administrador de servicios:

public class ServiceManager {

    final RemoteCallbackList<IRemoteServiceCallback> mCallbacks = new RemoteCallbackList<IRemoteServiceCallback>();
    public IRestfulService restfulService;
    private RestfulServiceConnection conn;
    private boolean started = false;
    private Context context;

    public ServiceManager(Context context) {
        this.context = context;
    }

    public void startService() {
        if (started) {
            Toast.makeText(context, "Service already started", Toast.LENGTH_SHORT).show();
        } else {
            Intent i = new Intent();
            i.setClassName("com.something.android", "com.something.android.RestfulAPIService");
            context.startService(i);
            started = true;
        }
    }

    public void stopService() {
        if (!started) {
            Toast.makeText(context, "Service not yet started", Toast.LENGTH_SHORT).show();
        } else {
            Intent i = new Intent();
            i.setClassName("com.something.android", "com.something.android.RestfulAPIService");
            context.stopService(i);
            started = false;
        }
    }

    public void bindService() {
        if (conn == null) {
            conn = new RestfulServiceConnection();
            Intent i = new Intent();
            i.setClassName("com.something.android", "com.something.android.RestfulAPIService");
            context.bindService(i, conn, Context.BIND_AUTO_CREATE);
        } else {
            Toast.makeText(context, "Cannot bind - service already bound", Toast.LENGTH_SHORT).show();
        }
    }

    protected void destroy() {
        releaseService();
    }

    private void releaseService() {
        if (conn != null) {
            context.unbindService(conn);
            conn = null;
            Log.d(LOG_TAG, "unbindService()");
        } else {
            Toast.makeText(context, "Cannot unbind - service not bound", Toast.LENGTH_SHORT).show();
        }
    }

    class RestfulServiceConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName className, IBinder boundService) {
            restfulService = IRestfulService.Stub.asInterface((IBinder) boundService);
            try {
            restfulService.registerCallback(mCallback);
            } catch (RemoteException e) {}
        }

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

    private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
        public void userLogIn(String result) throws RemoteException {
            mHandler.sendMessage(mHandler.obtainMessage(Config.ACTION_LOGIN, result));

        }
    };

    private Handler mHandler;

    public void setHandler(Handler handler) {
        mHandler = handler;
    }
}

Servicio de init y se unen:

// this I'm calling on app onCreate
servicemanager = new ServiceManager(this);
servicemanager.startService();
servicemanager.bindService();
application = (ApplicationState)this.getApplication();
application.setServiceManager(servicemanager);

servicio de llamada a la función:

// this lot i'm calling as required - in this example for login
progressDialog = new ProgressDialog(Login.this);
progressDialog.setMessage("Logging you in...");
progressDialog.show();

application = (ApplicationState) getApplication();
servicemanager = application.getServiceManager();
servicemanager.setHandler(mHandler);

try {
    servicemanager.restfulService.doLogin(args[0], args[1]);
} catch (RemoteException e) {
    e.printStackTrace();
}

...later in the same file...

Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {

        switch (msg.what) {
        case Config.ACTION_LOGIN:

            if (progressDialog.isShowing()) {
                progressDialog.dismiss();
            }

            try {
                ...process login results...
                }
            } catch (JSONException e) {
                Log.e("JSON", "There was an error parsing the JSON", e);
            }
            break;
        default:
            super.handleMessage(msg);
        }

    }

};

282voto

Robby Pond Puntos 37875

Si el servicio va a ser parte de la aplicación, a continuación, usted está haciendo, es mucho más complejo de lo que debe ser. Puesto que usted tiene un caso de uso sencillo de conseguir algunos datos de un Servicio Web RESTful, usted debe mirar en ResultReceiver y IntentService.

Este Servicio + ResultReceiver patrón de obras por partida o de unión para el servicio con startService() cuando se quiere hacer alguna acción. Puede especificar la operación a realizar y aprobar en su ResultReceiver (de la actividad) a través de los extras en el Intento.

En el servicio de implementar onHandleIntent hacer la operación de que se especifica en el Intento. Cuando la operación haya terminado de utilizar el pasado en ResultReceiver para enviar un mensaje de vuelta a la Actividad en la que el punto de onReceiveResult será llamado.

Así, por ejemplo, quieres extraer algunos datos de su Servicio Web.

  1. Crear la intención y la llamada startService.
  2. La operación en el servicio se inicia y se envía a la actividad de un mensaje que dice que se empezó a
  3. La actividad procesa el mensaje y muestra el progreso.
  4. El servicio finaliza la operación y envía algunos datos de su actividad.
  5. Su actividad procesa los datos y los pone en una lista ver
  6. El servicio envía un mensaje diciendo que se hace, y se mata a sí mismo.
  7. La actividad recibe el mensaje de finalización y oculta el cuadro de diálogo de progreso.

Yo sé que usted ha mencionado usted no quiere una base de código, pero el código abierto de Google I/O 2010 aplicación utiliza un servicio en este camino que estoy describiendo.

Actualizado para añadir código de ejemplo:

La actividad.

public class HomeActivity extends Activity implements MyResultReceiver.Receiver {

    public MyResultReceiver mReceiver;

    public void onCreate(Bundle savedInstanceState) {
        mReceiver = new MyResultReceiver(new Handler());
        mReceiver.setReceiver(this);
        ...
        final Intent intent = new Intent(Intent.ACTION_SYNC, null, this, QueryService.class);
        intent.putExtra("receiver", mReceiver);
        intent.putExtra("command", "query");
        startService(intent);
    }

    public void onPause() {
        mReceiver.setReceiver(null); // clear receiver so no leaks.
    }

    public void onReceiveResult(int resultCode, Bundle resultData) {
        switch (resultCode) {
        case RUNNING:
            //show progress
            break;
        case FINISHED:
            List results = resultData.getParcelableList("results");
            // do something interesting
            // hide progress
            break;
        case ERROR:
            // handle the error;
            break;
    }
}

El Servicio De:

public class QueryService extends IntentService {
    protected void onHandleIntent(Intent intent) {
        final ResultReceiver receiver = intent.getParcelableExtra("receiver");
        String command = intent.getStringExtra("command");
        Bundle b = new Bundle();
        if(command.equals("query") {
            receiver.send(STATUS_RUNNING, Bundle.EMPTY);
            try {
                // get some data or something           
                b.putParcelableArrayList("results", results);
                receiver.send(STATUS_FINISHED, b)
            } catch(Exception e) {
                b.putString(Intent.EXTRA_TEXT, e.toString());
                receiver.send(STATUS_ERROR, b);
            }    
        }
    }
}

ResultReceiver extensión - editado por implementar MyResultReceiver.Receiver

public MyResultReceiver extends ResultReceiver {
    private Receiver mReceiver;

    public MyResultReceiver(Handler handler) {
        super(handler);
    }

    public void setReceiver(Receiver receiver) {
        mReceiver = receiver;
    }

    public interface Receiver {
        public void onReceiveResult(int resultCode, Bundle resultData);
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {
        if (mReceiver != null) {
            mReceiver.onReceiveResult(resultCode, resultData);
        }
    }
}

17voto

Terrance Puntos 5384

El desarrollo de Android RESTO de aplicaciones de cliente ha sido un recurso increíble para mí. El altavoz no muestra ningún código, sólo va por encima de las consideraciones de diseño y técnicas en la creación de una sólida roca de la Api de Rest en android. Si un podcast un poco de la persona o no, me gustaría recomendar esta dando al menos una escucha, pero, personalmente, he escuchado como 4 o cinco veces hasta ahora y que probablemente voy a escuchar de nuevo.

El desarrollo de Android RESTO de aplicaciones de cliente
Autor: Virgilio Dobjanschi
Descripción:


En esta sesión se presentarán consideraciones de arquitectura para el desarrollo de Descanso de las aplicaciones de la plataforma Android. Se centra en los patrones de diseño, integración de la plataforma y los problemas de rendimiento específicos para la plataforma Android.

Y hay muchas consideraciones que yo realmente no había hecho en la primera versión de mi api que he tenido que refactorizar

16voto

Soumya Simanta Puntos 2330

También cuando le di el post(Config.getURL("login"), los valores de) la aplicación parece hacer una pausa por un tiempo (parece raro - pensó la idea detrás de un servicio era que se ejecuta en un subproceso diferente!)

No tienes que crear un hilo, un servicio Local se ejecuta en el subproceso de la interfaz de usuario por defecto.

11voto

panchicore Puntos 3288

Sé @Martyn no quiere código completo, pero creo que esta anotación es bueno para esta pregunta:

10 open Source Android Apps que deben investigar todos los desarrolladores de Android

Foursquared para Android es código abiertoy tiene un patrón de código interesante interactuando con la API REST de foursquare.

5voto

StlTenny Puntos 101

Sólo quería apuntar en la dirección de un standalone clase que rodé incorpora todas las funciones.

http://github.com/StlTenny/RestService

Se ejecuta la solicitud como no-bloqueo y devuelve los resultados de una forma fácil de implementar controlador. Incluso viene con un ejemplo de implementación.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X