POST 与 Android 改造

Posted

技术标签:

【中文标题】POST 与 Android 改造【英文标题】:POST with Android Retrofit 【发布时间】:2013-11-16 18:06:46 【问题描述】:

我是 android 编程和 Retrofit 的新手。我已经对此主题进行了大量研究,但无法找到适合我需求的解决方案。我正在使用我们的 API 并尝试发出 POST 请求。我使用以下非改造代码成功实现了这一点:

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

    

现在,我正在尝试使用 Retrofit 获得相同的结果,但我不确定如何使用回调从我们的 API 中获取 JSON(我假设此调用应该异步发生?):

我用下面的方法做了一个接口:

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

并在我的 Activity 的 onCreate 方法中实例化了 RestAdapter 等。当用户按下“登录”按钮(输入用户名和密码后)时,在按钮的 onClick 方法中调用以下内容:

    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) 

            
        
        );

然而,这并没有按预期工作,我真的认为我没有正确处理这个问题。我希望能够对我们的服务器进行 POST,该服务器会发回有关该用户的 JSON 格式数据块。如果有人能指出我正确的方向,那将不胜感激。提前谢谢你

【问题讨论】:

您在哪个 android API 中工作? @BlueGreen 我正在使用我公司自己的 API,所以我正在尝试使用 Retrofit 进行 GET/POST 调用 我现在正在用 Retrofit 测试我的 REST,和你做同样的事情,但我还没有准备好给你一个完整的答案。对于初学者,请尝试使用 Callback - 这应该会给你一个原始数据。您的代码总体上看起来是正确的 我目前面临同样的问题。你设法让它工作了吗? 你让它工作了吗?我正在做同样的事情,并且在尝试使用 FormUrlEncoded 的回调执行异步 POST 时遇到了 IllegalArgumentException - ***.com/questions/22572301/… 【参考方案1】:

Retrofit 的一个好处是不必自己解析 JSON。你应该有类似的东西:

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 是类似 POJO 的地方

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

并且返回的 JSON 具有与 User 类匹配的字段:


  "name": "Bob User",
  "email": "bob@example.com",
  ...

如果您需要自定义解析,则可以在使用.setConverter(Converter converter) 设置 REST 适配器的转换器时进行:

用于对象序列化和反序列化的转换器。

【讨论】:

很好的例子,方程的所有“部分”都清楚地展示了。不错。 如果我们得到 json 数组 '[' 而不是 Objects '' 呢? [ "name": "Bob 用户", "email": "bob@example.com", ... ] 对于数组,您可以使用 List @LOG_TAG 发回去,那不是 JSON。【参考方案2】:

似乎 Retrofit 对 @POST@FormUrlEncoded 有问题。如果我们进行同步,它工作得很好,但如果异步失败。

如果@mike问题是反序列化对象,用户类应该是

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

     @SerializedName("email")
     String email;

接口类

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

或者

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


【讨论】:

以上是关于POST 与 Android 改造的主要内容,如果未能解决你的问题,请参考以下文章

NullPointerException 使用改造库 - Android

kotlin android中的改造请求@Part和@Query

如何从android改造上传图像到服务器

如何在body参数改造android中发送数组请求

如何通过 android 中的改造从 php 中检索“字符串响应”?

如何在 Android 的改造请求中传递 JSON 对象并检索 JSON 对象?