227 votes

API Restful service

Je suis à la recherche d'un service que je peux utiliser pour faire des appels à un basé sur le web api rest. J'ai passé quelques jours à la recherche par le biais de stackoverflow.com, en lisant des livres et en regardant les articles tout en jouant avec un peu de code et je ne peux pas obtenir tout ce dont je suis très content.

Fondamentalement, je veux démarrer un service sur app init puis je veux être en mesure de demander ce service à la demande une url et renvoie les résultats. En attendant, je veux être capable d'afficher une fenêtre de progression ou quelque chose de similaire.

J'ai créé une fonction qui utilise IDL, j'ai lu quelque part que vous ne vraiment besoin de ceci pour la croix-app de communication, de sorte que ces besoins de décapage, mais ne savent pas comment faire les rappels sans elle. Aussi quand j'ai touché post(Config.getURL("login"), values) l'application semble pause pendant un certain temps (bizarre - pensée l'idée d'un service qu'il s'exécute sur un autre fil!)

Actuellement, j'ai un service à post et get http méthodes à l'intérieur, un couple de AIDL fichiers (pour la communication dans les deux sens), un ServiceManager qui traite avec le démarrage, l'arrêt, la reliure, etc pour le service et je suis de la création dynamique d'un Gestionnaire de code spécifique pour les rappels nécessaires.

Je ne veux pas quelqu'un pour me donner un code complet de la base de travailler sur le, mais quelques conseils seraient grandement appréciés; même si c'est pour dire que je suis en train de faire complètement faux. Je suis assez nouveau pour Android et Java dev donc si il y a quelque évidentes erreurs ici - s'il vous plaît ne pense pas que je suis une poubelle, développeur, je suis tout mouillé derrière les oreilles et apprécierait d'être dit où je vais mal.

De toute façon, le code dans (presque) complet (n'avais vraiment pas envie de mettre ce code ici, mais je ne sais pas où je vais mal - toutes mes excuses à l'avance):

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 couple de AIDL fichiers:

package com.something.android

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

et

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

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

et le gestionnaire de services:

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;
    }
}

Service init et lier:

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

le service appel de la fonction:

// 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);
        }

    }

};

284voto

Robby Pond Points 37875

Si votre service est de vous demande de vous rendre plus complexe que cela doit l'être. Puisque vous avez un cas d'utilisation simple d'obtenir des données à partir d'un Service Web RESTful, vous devriez regarder dans ResultReceiver et IntentService.

Ce Service + ResultReceiver modèle fonctionne en commençant ou en liaison avec startService() lorsque vous voulez faire une certaine action. Vous pouvez spécifier l'opération à effectuer et réussir dans votre ResultReceiver (l'activité) à travers les extras dans l'Intention.

Dans le service que vous mettre en œuvre onHandleIntent à l'opération qui est spécifié dans l'Intention. Lorsque l'opération est terminée, vous utilisez le passé dans ResultReceiver pour envoyer un message à l'Activité à laquelle onReceiveResult sera appelée.

Ainsi, par exemple, vous souhaitez tirer certaines données de votre Service Web.

  1. Vous créez l'intention et l'appel startService.
  2. L'opération dans le service commence et il envoie une activité un message disant qu'il a commencé
  3. L'activité traite le message et montre un progrès.
  4. Le service se termine le fonctionnement et l'envoie des données vers votre activité.
  5. Votre activité traite les données et les met dans une vue de liste
  6. Le service vous envoie un message en disant que c'est fait, et il se tue elle-même.
  7. L'activité est le message de fin et masque la boîte de dialogue de progression.

Je sais que vous avez mentionné vous ne voulez pas un code de base, mais l'open source de Google I/O 2010 application utilise un service de la même façon que je viens de décrire.

Mise à jour pour ajouter des exemples de code:

L'activité.

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;
    }
}

Le Service:

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 extension - édité en œuvre MyResultReceiver.Récepteur

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);
        }
    }
}

18voto

Terrance Points 5384

Développement Android RESTE des applications client a été une ressource impressionnante pour moi. Le haut-parleur n'affiche pas de code, il va juste sur des considérations de conception et les techniques à mettre sur pied un solide comme le roc Reste de l'Api android. Si votre un podcast un peu la personne ou pas, je vous recommande de donner ce un au moins à l'écoute, mais, personnellement, j'ai écouté 4 ou cinq fois jusqu'à présent et je vais probablement l'écouter de nouveau.

Développement Android RESTE des applications clientes
Auteur: Virgile Dobjanschi
Description:

Cette session présentera des considérations architecturales pour le développement d'applications Reposant sur la plate-forme Android. Il met l'accent sur les modèles de conception, la plate-forme d'intégration et de performance les questions spécifiques à la plate-forme Android.

Et il y a donc de nombreuses raisons, je n'avais vraiment pas fait dans la première version de mon api que j'ai eu à refactoriser

16voto

Soumya Simanta Points 2330

Aussi, quand j'ai frappé la poste(Config.getURL("login"), de valeurs), l'application semble pause pour un while (bizarre - pensée l'idée derrière un service est qu'il fonctionne sur une thread différent!)

Non, vous devez créer un thread vous-même, un Local de service s'exécute dans le thread de l'INTERFACE utilisateur par défaut.

11voto

panchicore Points 3288

Je sais que @Martyn ne veux pas le code complet, mais je pense que cette annotation son bon pour cette question:

10 Open Source Android Apps qui chaque développeur Android devez regarder dans

Foursquared pour Android est open-source, et une intéressante du modèle de code de l'interaction avec le foursquare API REST.

5voto

StlTenny Points 101

Je voulais juste pointer à vous tous dans le sens d'une classe autonome, j'ai roulé qui intègre toutes les fonctionnalités.

http://github.com/StlTenny/RestService

Il exécute la requête comme non-blocage, et renvoie les résultats dans un format facile à mettre en œuvre gestionnaire. Même est livré avec un exemple de mise en œuvre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X