我正在使用改装2+和gson库来从rest api获取数据。但每当我尝试运行我的应用程序时,它都会显示以下错误:
“预计BEGIN_ARRAY,但在第1行第1行路径为STRING”。
因此我尝试了很多来识别问题。这是我的json序列化器的代码。 Json就是这样给出的。在某些情况下,某些字段缺失,例如title
未包含在所有情况中。
Api数据:
[
{
"_id": "fhfh49879787989",
"dn": "CN=9879798789",
"whenChanged": "20170704065349.0Z",
"name": "Student",
"mail": "student@mail.com",
"updated_at": "2017-07-04T18:22:43.624Z"
},
{
"_id": "595bdcf32c67a3f9ee6c2a25",
"dn": "CN=dsfdsfsdfsf",
"givenName": "Accounting Office",
"whenChanged": "20170801114732.0Z",
"name": "Accounting",
"mail": "accounting@mail.com",
"updated_at": "2017-07-04T18:22:43.641Z"
},
{
"_id": "584ab3b4122d13e1b0d1578d",
"dn": "CN=sfdfsfsdfl",
"sn": "Abels",
"title": "Student",
"givenName": "Gardrut",
"whenChanged": "20170807150844.0Z",
"department": "PMO",
"company": "Multi Lmited",
"name": "Mike Lizz",
"mail": "mail@yahoo.com",
"mobile": "+1321646498",
"updated_at": "2016-12-09T13:37:56.175Z"
},
{
"_id": "584ab3b3122d13e1b0d15735",
"dn": "CN=xdfsdfsfsdf",
"sn": "Acsdff",
"title": "Software Engineer",
"givenName": "Olin",
"whenChanged": "20170810064841.0Z",
"department": "Head",
"company": "Private limited",
"name": "James Oliver",
"mail": "mail@gmail.com",
"mobile": "+41228",
"updated_at": "2016-12-09T13:37:55.813Z"
},
....
]
POJO:
public class ColleagueModel implements Serializable {
@Expose
private String _id;
@Expose
private String dn;
@Expose
private String givenName;
@Expose
private String whenChanged;
@Expose
private String name;
@Expose
private String mail;
@Expose
private String updatedAt;
@Expose
private String sn;
@Expose
private String title;
@Expose
private String department;
@Expose
private String company;
@Expose
private String mobile;
// getter and setter...
我的服务类:
public interface ColleagueApiService {
@GET("/api/users")
Call<List<ColleagueModel>> getAllColleagues();
}
休息maneger类:
public class ColleagueRestManager {
public ColleagueApiService mColleagueService;
public ColleagueApiService getColleagueService() {
if (mColleagueService == null) {
Gson gson = new GsonBuilder()
.setLenient()
.serializeNulls()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.HTTP.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
mColleagueService = retrofit.create(ColleagueApiService.class);
}
return mColleagueService;
}
}
适配器类:
public class MyColleaguesAdapter extends RecyclerView.Adapter<MyColleaguesAdapter.ColleagueHolder> {
public static String TAG = MyColleaguesAdapter.class.getSimpleName();
private List<ColleagueModel> mColleague;
public MyColleaguesAdapter() {
mColleague = new ArrayList<>();
}
private List<MyColleagueModel> myColleagueModels;
public interface ColleagueListListener {
}
public void addColleague(ColleagueModel colleague) {
Log.d(TAG,colleague.getName());
mColleague.add(colleague);
notifyDataSetChanged();
}
// create new views (invoked by the layout manager)
@Override
public ColleagueHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//inflate a new colleague view
View view = LayoutInflater
.from(parent.getContext())
.inflate(R.layout.colleage_row_layout,parent,false);
return new ColleagueHolder(view);
}
@Override
public void onBindViewHolder(ColleagueHolder holder, int position) {
ColleagueModel currentColleague = mColleague.get(position);
holder.colleagueName.setText(currentColleague.getName());
holder.companyName.setText(currentColleague.getCompany());
holder.jobTitle.setText(currentColleague.getTitle());
}
@Override
public int getItemCount() {
return mColleague.size();
}
public class ColleagueHolder extends RecyclerView.ViewHolder{
public CardView cardView;
public ImageView colleaguePicture;
public TextView colleagueName;
public TextView companyName;
public TextView jobTitle;
public ColleagueHolder(View itemView) {
super(itemView);
colleaguePicture = itemView.findViewById(R.id.colleague_picture);
colleagueName = itemView.findViewById(R.id.colleague_name);
companyName = itemView.findViewById(R.id.company_name);
jobTitle = itemView.findViewById(R.id.job_title);
cardView = itemView.findViewById(R.id.cardview_user);
}
}
最后是活动类:
public class MyColleaguesPage extends AppCompatActivity {
private RecyclerView recyclerView;
private MyColleaguesAdapter adapter;
private Controller mController;
private ColleagueRestManager mManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mycolleagues_layout);
// Showing and Enabling clicks on the Home/Up button
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
configViews();
mManager = new ColleagueRestManager();
Call<List<ColleagueModel>> colleagueList = mManager.getColleagueService().getAllColleagues();
colleagueList.enqueue(new Callback<List<ColleagueModel>>() {
@Override
public void onResponse(Call<List<ColleagueModel>> call, Response<List<ColleagueModel>> response) {
if(response.isSuccessful()) {
List<ColleagueModel> colleagueList = response.body();
for (int i = 0; i < colleagueList.size(); i++) {
ColleagueModel colleague = colleagueList.get(i);
adapter.addColleague(colleague);
}
} else {
int sc = response.code();
switch (sc){
case 400:
Log.e("Error 400", "Bad Request");
break;
case 404:
Log.e("Error 404", "Not Found");
break;
default:
Log.e("Error", "Generic Error");
}
}
}
@Override
public void onFailure(Call<List<ColleagueModel>> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
Log.d("Error Message:"+"",t.getMessage());
}
})
}
private void configViews() {
recyclerView = this.findViewById(R.id.colleagues_recycler);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(MyColleaguesPage.this));
recyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());
adapter = new MyColleaguesAdapter();
recyclerView.setAdapter(adapter);
}
}
获取api的重要级别:
public class Constants {
public static final class HTTP {
public static final String BASE_URL = "https://app.com"; //not given the real url
}
public static final class DATABASE {
}
}
已编辑的正文
08-20 07:51:02.334 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: --> GET https://app.blu-pa.com/api/users http/1.1
08-20 07:51:02.334 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: --> END GET
08-20 07:51:02.377 1346-1367/? W/audio_hw_generic: Not supplying enough data to HAL, expected position 860742 , only wrote 707760
08-20 07:51:02.383 1346-1366/? W/audio_hw_generic: Not supplying enough data to HAL, expected position 707956 , only wrote 707760
08-20 07:51:02.386 3421-3426/demo.app.com.bluapp_client_and I/art: Do partial code cache collection, code=59KB, data=59KB
08-20 07:51:02.387 3421-3426/demo.app.com.bluapp_client_and I/art: After code cache collection, code=50KB, data=54KB
08-20 07:51:02.387 3421-3426/demo.app.com.bluapp_client_and I/art: Increasing code cache capacity to 256KB
08-20 07:51:02.392 3421-3440/demo.app.com.bluapp_client_and D/EGL_emulation: eglMakeCurrent: 0xa494e540: ver 2 0 (tinfo 0xa494d430)
08-20 07:51:02.404 1581-1601/? I/ActivityManager: Displayed demo.app.com.bluapp_client_and/.activity.myColleague.MyColleaguesPage: +83ms
08-20 07:51:02.657 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: <-- 200 https://app.blu-pa.com/login?callback=%2F (322ms)
08-20 07:51:02.657 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: x-dns-prefetch-control: off
08-20 07:51:02.657 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: x-frame-options: SAMEORIGIN
08-20 07:51:02.657 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: strict-transport-security: max-age=15552000; includeSubDomains
08-20 07:51:02.658 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: x-download-options: noopen
08-20 07:51:02.658 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: x-content-type-options: nosniff
08-20 07:51:02.658 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: x-xss-protection: 1; mode=block
08-20 07:51:02.658 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: set-cookie: language=de-DE; Max-Age=86400; Path=/; Expires=Mon, 21 Aug 2017 07:51:05 GMT
08-20 07:51:02.658 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: set-cookie: connect.sid=s%3Ah-1Pju1IRtwJwNG5VU5Ja0t1OPujcaHz.Bd6gMWB8Q3DtgOpP%2BHnMuh6QY5VGHwcChbOqTRVVee0; Path=/; HttpOnly
08-20 07:51:02.658 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: content-type: text/html; charset=utf-8
08-20 07:51:02.658 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: etag: W/"8af-hp6ns0Ui95kDbe9rVovQHfKz5pA"
08-20 07:51:02.658 3421-5002/demo.app.com.bluapp_client_and D/OkHttp: vary: Accept-Encoding
答案 0 :(得分:0)
正如我在您的改造日志中所看到的,没有您期望的答案。您根据服务器实现发出请求whitout发送令牌或etag。通常,在编辑某些个人信息时会使用etag。
有一个重定向到登录页面:https://app.blu-pa.com/login?callback=%2F (322ms)
。
Retrofit正在检索登录页面(D/OkHttp: content-type: text/html; charset=utf-8
)的html(Retrofit返回html作为正文中的字符串),这就是为什么你得到"Expected BEGIN_ARRAY but was STRING at line 1 column 1 path $".
添加标题,您在users
请求中从登录中获得的令牌已准备就绪。
修改强>
您应该使用拦截器将令牌添加到每个请求
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", "YourTokenHere")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = new Retrofit.Builder().client(client).build();
现在,您可以自行决定如何存储和检索令牌。
您可以阅读更多关于incerceptor的here。