web-dev-qa-db-fra.com

POST with Android Retrofit

Je suis nouveau dans la programmation Android et je travaille avec Retrofit. J'ai fait un tas de recherches sur ce sujet, mais je n'ai pas pu trouver de solution spécifique à mes besoins. Je '' Je travaille avec notre API et j'essaie de faire une demande POST. J'ai réussi cela avec le code non-retrofit suivant:

    private class ProcessLogin extends AsyncTask<Void, String, JSONObject> {
    private ProgressDialog pDialog;
    String email,password;

    protected void onPreExecute() {
        super.onPreExecute();
        inputEmail = (EditText) findViewById(R.id.email);
        inputPassword = (EditText) findViewById(R.id.password);
        email = inputEmail.getText().toString();
        password = inputPassword.getText().toString();
        pDialog = new ProgressDialog(LoginActivity.this);
        pDialog.setTitle("Contacting Servers");
        pDialog.setMessage("Logging in ...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(true);
        pDialog.show();
    }

    protected JSONObject doInBackground(Void... params) {
        HttpURLConnection connection;
        OutputStreamWriter request = null;
        URL url = null;   
        String response = null;         
        String parameters = "username="+email+"&password="+password;  
        try
        {
            url = new URL("http://.../api/login");
            connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setRequestMethod("POST");    

            request = new OutputStreamWriter(connection.getOutputStream());
            request.write(parameters);
            request.flush();
            request.close();            
            String line = "";               
            InputStreamReader isr = new InputStreamReader(connection.getInputStream());
            BufferedReader reader = new BufferedReader(isr);
            StringBuilder sb = new StringBuilder();
            while ((line = reader.readLine()) != null)
            {
                sb.append(line + "\n");
            }
            // Response from server after login process will be stored in response variable.                
            response = sb.toString();
            // You can perform UI operations here
            isr.close();
            reader.close();
        }
        catch(IOException e)
        {
            // Error
        }
        System.out.println(response);
        JSONObject jObj = null;        
        // Try to parse the string to a JSON Object
        try {
            jObj = new JSONObject(response);
        } catch (JSONException e) {
            Log.e("JSON Parser", "Error parsing data " + e.toString());
        }

        // Return the JSONObject
        return jObj;
    }

    protected void onPostExecute(JSONObject json) {
        String status = (String) json.optJSONArray("users").optJSONObject(0).optJSONObject("user").optString("login");
        pDialog.dismiss();
        if (status.equals("Failed")) {
            loginMessage.setText("Login Failed");   
        }
        else if (status.equals("Success")) {
            loginMessage.setText("Success!");   
            startActivity(new Intent(getApplicationContext(), DActivity.class));
        }

    }
}

Maintenant, j'essaie d'obtenir les mêmes résultats en utilisant Retrofit, mais je ne sais pas comment récupérer le JSON de notre API à l'aide de rappels (je suppose que cet appel devrait se produire de manière asynchrone?):

J'ai fait une interface avec la méthode suivante:

    @FormUrlEncoded
@POST("/login")
public void login(@Field("username") String username, @Field("password") String password, Callback<JSONObject> callback);

Et instancié le RestAdapter, etc. dans la méthode onCreate de mon activité. Lorsque l'utilisateur appuie sur le bouton "connexion" (après avoir entré son nom d'utilisateur et son mot de passe), ce qui suit est appelé dans la méthode onClick du bouton:

    service.login(email, password, new Callback<JSONObject>() { 
            @Override
            public void failure(final RetrofitError error) {
                Android.util.Log.i("example", "Error, body: " + error.getBody().toString());
            }
            @Override
            public void success(JSONObject arg0, Response arg1) {

            }
        }
        );

Cependant, cela ne fonctionne pas comme prévu, et je ne pense vraiment pas que j'approche cela correctement. Je veux pouvoir faire un POST à notre serveur, qui renvoie un bloc de données au format JSON sur cet utilisateur. Si quelqu'un pouvait me diriger dans la bonne direction, ce serait vraiment apprécié . Merci d'avance

22
mike

L'un des avantages de Retrofit est de ne pas avoir à analyser le JSON vous-même. Vous devriez avoir quelque chose comme:

service.login(email, password, new Callback<User>() { 
        @Override
        public void failure(final RetrofitError error) {
            Android.util.Log.i("example", "Error, body: " + error.getBody().toString());
        }
        @Override
        public void success(User user, Response response) {
            // Do something with the User object returned
        }
    }
);

User est un POJO comme

public class User {
    private String name;
    private String email;
    // ... etc.
}

et le JSON renvoyé contient des champs qui correspondent à la classe User:

{
  "name": "Bob User",
  "email": "[email protected]",
  ...
}

Si vous avez besoin d'une analyse personnalisée, la place pour cela est lors de la configuration du convertisseur de l'adaptateur REST avec . SetConverter (Converter converter) :

Le convertisseur utilisé pour la sérialisation et la désérialisation des objets.

21
blahdiblah

Il semble que Retrofit ait un problème avec @POST et @FormUrlEncoded. Cela fonctionne bien si nous faisons synchrone mais a échoué si asynchrone.

Si le problème @mike est un objet de désérialisation, la classe utilisateur doit être

public class User {
     @SerializedName("name")
     String name;

     @SerializedName("email")
     String email;
}

Classe d'interface

@FormUrlEncoded
@POST("/login")
void login(@Field("username") String username, @Field("password") String password, Callback<User> callback);

Ou

@FormUrlEncoded
@POST("/login")
void login(@Field("username") String username, @Field("password") String password, Callback<UserResponse> callback);

public class UserResponse {

@SerializedName("email")
String email;

@SerializedName("name")
String name;

}
8
khaintt