gpt4 book ai didi

java - 使用 Retrofit 库的 NullPointerException - Android

转载 作者:行者123 更新时间:2023-11-30 08:48:42 24 4
gpt4 key购买 nike

(在问题末尾滚动以查看最终解决方案)

尝试使用 Retrofit Android 库。我正在尝试将 POST 请求推送到 Web 服务器,该服务器应该在通过 POST 成功调用“/login”方法后返回 3 个字段。信息:

  1. 终点:http://example.us.es:3456
  2. 执行登录的服务器端方法:/login
  3. 服务器端方法的必需参数:“用户”和“密码”
  4. 服务器管理员允许的 HTTP 方法:POST

无论应用程序客户端输入什么值的“用户”和“密码”,Web 服务器都应该发送一个包含三个字段的 JSONObject:

  1. ok:值为“true”或“false”的字符串(false 表示凭据无效)。
  2. msg:如果出现错误(例如,无效凭据或数据库错误),将携带一条字符串消息
  3. data:此方法中包含一个名称/值对的另一个 JSONObject,id_session(包含 session 标识符的字符串)。其他方法包含多个名称/值对; login 方法不是这种情况。

根据这些信息,我做的第一件事是创建一个如下所示的 POJO Java 方法:

POJO 方法(LoginInfo_POJO.java)

package com.example.joselopez.prueba1;

import java.util.List;

public class LoginInfo_POJO {
public String _ok;
public String _msg;
public Dataset _dataset;

class Dataset {
String _idsession;
}
}

我接下来要做的是创建一个包含登录方法的接口(interface)(我会在成功登录后在此处添加其他方法):

接口(interface)中的 API 方法 (IApiMethods.java)

package com.example.joselopez.prueba1;

import retrofit.http.POST;
import retrofit.http.Query;

public interface IApiMethods {

// Log-in method
@FormUrlEncoded
@POST("/login")
LoginInfo_POJO logIn(@Query("user") String user,
@Query("password") String password);
}

快到了。现在我创建一个从 AsyncTask 扩展的类,它将在单独的线程中执行网络操作。此类位于“MainActivity.java”文件中。

主 Activity (MainActivity.java)

...
...


private class BackgroundTask_LogIn extends AsyncTask<Void, Void, LoginInfo_POJO> {
RestAdapter restAdapter;

@Override
protected LoginInfo_POJO doInBackground(Void... params) {
IApiMethods methods = restAdapter.create(IApiMethods.class);
LoginInfo_POJO loginInfo = methods.logIn(mUser, mPassword);
return loginInfo;
}

@Override
protected void onPreExecute() {
restAdapter = new RestAdapter.Builder()
.setEndpoint("http://example.us.es:3456")
.build();
}

@Override
protected void onPostExecute(LoginInfo_POJO loginInfo_pojo) {
tv.setText("onPostExecute()");
tv.setText(loginInfo_pojo._ok + "\n\n");
tv.setText(tv.getText() + loginInfo_pojo._msg + "\n\n");
tv.setText(tv.getText() + loginInfo_pojo.data.id_sesion);
}
}
}

MainActivity 布局包含一个 TextView(位于 RelativeLayout 内),其 id 为“textView”,并在代码中实例化为“tv”,您将在接下来看到。 MainActivity 的完整代码为:

主 Activity (MainActivity.java)

package com.example.joselopez.prueba1;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;
import retrofit.RestAdapter;

public class MainActivity extends AppCompatActivity {

TextView tv;
String mUser, mPassword;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.textView);
mUser = "test_user";
mPassword = "test_password";

BackgroundTask_LogIn tryLogin = new BackgroundTask_LogIn();
tryLogin.execute();
}

private class BackgroundTask_LogIn extends AsyncTask<Void, Void, LoginInfo_POJO> { ... }

一切正常。但事实并非如此,经过一些调试后我发现 BackgroundTask_LogIn 类中的 onPostExecute() 方法在一行中停止:

for (LoginInfo_POJO.Dataset dataset : loginInfo_pojo._dataset) {

抛出的错误是:

com.example.joselopez.prueba1 E/AndroidRuntime﹕ FATAL EXCEPTION: main java.lang.NullPointerException

所以我在这一行设置了一个断点,你猜怎么着?我的 LoginInfo_POJO 实例为其内部变量保存这些值:

  • _ok = null
  • _msg = null
  • _dataset = null

这意味着我的变量不是从服务器响应中填充的,但是连接似乎是成功的,因为 doInBackground 方法完全运行并且正在调用 onPostExecute。

那你怎么看?也许我没有以正确的方式执行 POST 请求?


更新

正如@Gaëtan 所说,我在 POJO 类中犯了一个大错误;那里的局部变量名称必须与结果 JSON 中的名称相同。我说过我期待来自 JSON 的字段“ok”、“msg”、“data”和“id_session”,但 LoginInfo_POJO 中的局部变量名称为“_ok”、“_msg”、“_dataset”、“_idsession” (注意前导下划线)。从 Retrofit 的角度来看,这是一个巨大的错误,因此重写 POJO 方法解决这个问题最终将解决问题。

最佳答案

一些关于如何使用 Retrofit 的信息:

  1. POJO 中字段的名称必须与 JSON 响应中的第一个匹配。在这里,您的字段被命名为 _ok , _msg_dataset而 JSON 响应包含 ok , msgdata .您在这里有两个选择:重命名字段以匹配 JSON 响应,或使用 @SerializedName每个字段上的注释以给出 JSON 字段的名称。
public class LoginInfo_POJO {
// If you rename the fields
public String ok;
public String msg;
public List<Dataset> data;

// If you use annotation
@SerializedName("ok")
public String _ok;
@SerializedName("msg")
public String _msg;
@SerializedName("data")
public String _dataset;
}
  1. Retrofit 提供了一种不使用 AsyncTask 的方法.不要为您的 API 方法使用返回类型(此处为 LoginInfo_POJO logIn(String, String ),而是使用类型为 Callback<LoginInfo_POJO> 的最后一个参数.请求将通过改造在后台线程上执行,当请求完成时(或如果出现问题失败)将在主线程上调用回调。

参见 documentation有关详细信息,请参阅 SYNCHRONOUS VS。异步 VS。 OBSERVABLE 部分。

关于java - 使用 Retrofit 库的 NullPointerException - Android,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31774966/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com