我创建了从Android设备名称,手机号码和电子邮件中检索联系人的服务,并将其与联系人的自定义对象一起存储在数组列表中。我的设备中有20,000个联系人。我正在使用Gson将该数组列表转换为JSON数组。我正在将数据发送到服务器,但是请求失败。如果我发送少量数据,则API会成功响应。我想知道当存在JSON格式的大数据时为什么无法收到成功请求。 这是我将发送到服务器的示例格式数据
[
{
"Name": "FirstName Lastname",
"Phone": "[+123456789012]"
},
{
"Name": "FirstName Lastname",
"Phone": "[+123456789012, +123456789012, +123456789012]",
"Email": "abcd@gmail.com"
},
{
"Name": "FirstName Lastname",
"Phone": "[+123456789012]"
},
{
"Name": "FirstName Lastname",
"Phone": "[]"
}
]
这是我得到的打印堆栈跟踪
06-25 17:32:21.816 19421-20008 / D / OkHttp:<-HTTP失败:javax.net.ssl.SSLException:写入错误:ssl = 0x40d92618:系统调用期间I / O错误,管道损坏 06-25 17:32:21.826 19421-19421 / W / System.err:javax.net.ssl.SSLException:写入错误:ssl = 0x40d92618:系统调用期间I / O错误,管道损坏 06-25 17:32:21.856 19421-19421 / W / System.err:at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(本机方法) 在org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl $ SSLOutputStream.write(OpenSSLSocketImpl.java:719) 在okio.Okio $ 1.write(Okio.java:79) 在okio.AsyncTimeout $ 1.write(AsyncTimeout.java:180) 在okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:179) 在okio.RealBufferedSink.writeUtf8(RealBufferedSink.java:54) 在okhttp3.internal.http1.Http1Codec.writeRequest(Http1Codec.java:172) 在okhttp3.internal.http1.Http1Codec.writeRequestHeaders(Http1Codec.java:130) 在okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:50) 在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 在okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45) 在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
这是我完成所有工作的服务代码。
public class ContactService extends Service {
String strDate;
@Nullable
CompositeDisposable mDisposable = null;
private UploadContactsUseCase mUploadContactsUseCase;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Date date = Calendar.getInstance().getTime();
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
//to convert Date to String, use format method of SimpleDateFormat class.
strDate = dateFormat.format(date);
new GetContacts().execute();
stopSelf();
// I don't want this service to stay in memory, so I stop it
// immediately after doing what I wanted it to do.
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
if (mDisposable != null) {
mDisposable.dispose();
mDisposable = null;
}
// I want to restart this service again.
AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
alarm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1),
PendingIntent.getService(this, 0, new Intent(this, ContactService.class), 0));
}
private JSONArray displayContacts() {
int j = 1;
List<ContactUser> contactUserList = new ArrayList<ContactUser>();
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur != null && cur.getCount() > 0) {
while (cur.moveToNext()) {
Log.i("COUNT: ", String.valueOf(j++));
List<String> listPhones = new ArrayList<String>();
ContactUser contactUser = new ContactUser();
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
contactUser.setName(name);
if (Integer
.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)))
> 0) {
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[]{id}, null);
while (pCur != null && pCur.moveToNext()) {
String phoneNo = pCur
.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
// Toast.makeText(NativeContentProvider.this, "Name: " + name + ", Phone No: " + phoneNo, Toast.LENGTH_SHORT).show();
// Log.i("Contact", name + " " + ":" + " " + phoneNo);
listPhones.add(phoneNo);
// mStoreContacts.add(name + " " + ":" + " " + phoneNo);
}
if (pCur != null) {
pCur.close();
}
}
// get the user's email address
String email = null;
Cursor ce = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[]{id}, null);
if (ce != null && ce.moveToFirst()) {
email = ce.getString(ce.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
// mStoreContacts.add(name + " " + ":" + " " + email);
ce.close();
}
String[] array = listPhones.toArray(new String[0]);
contactUser.setPhone(Arrays.toString(array));
contactUser.setEmail(email);
contactUserList.add(contactUser);
}
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < contactUserList.size(); i++) {
jsonArray.put(contactUserList.get(i).getJSONObject());
}
if (cur != null) {
cur.close();
}
return jsonArray;
}
if (cur != null) {
cur.close();
}
return null;
}
class GetContacts extends AsyncTask<Void, Void, JSONArray> {
@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(ContactService.this, "Starting reading contacts", Toast.LENGTH_SHORT).show();
}
@Override
protected JSONArray doInBackground(Void... voids) {
JSONArray contacts = displayContacts();
return contacts;
}
@Override
protected void onPostExecute(final JSONArray contact) {
super.onPostExecute(contact);
// new JobTask(contact).execute();
try {
Log.i("Contacts:", contact.toString(2));
} catch (JSONException e) {
e.printStackTrace();
}
mDisposable = new CompositeDisposable();
mUploadContactsUseCase = new UploadContactsUseCaseImpl();
mDisposable.add(mUploadContactsUseCase
.execute(Preferences.getInstance().getUserEmail(), contact.toString())
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action() {
@Override
public void run() throws Exception {
// handle completion
Toast.makeText(ContactService.this, "Complete", Toast.LENGTH_SHORT).show();
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
throwable.printStackTrace();
// handle error
Toast.makeText(ContactService.this, throwable.getMessage(), Toast.LENGTH_SHORT)
.show();
}
}));
}
}
}
这是我的Retrofit网络管理员课程
public class NetworkManager {
/**
* The Constant CONNECTION_TIMEOUT_TIME.
*/
private static final long CONNECTION_TIMEOUT_TIME = 30;
private static final String CURRENT_LANG =
Locale.getDefault().getLanguage().toString() + "-" + Locale.getDefault().getCountry();
private static final String GZIP_DEFLATE = "gzip,deflate";
/**
* The Constant ACCEPT_ENCODING.
*/
private static final String ACCEPT_ENCODING = "Accept-Encoding";
/**
* The Constant CONTENT_TYPE.
*/
private static final String CONTENT_TYPE = "Content-Type";
/**
* The Constant APPLICATION_JSON.
*/
private static final String APPLICATION_JSON = "application/json";
private static final String BASE_URL = "https://mybaseurl.in";
private static SafecodeApiService sInstanceV2 = null;
private static SafecodeApiService sInstanceV2_1 = null;
public static SafecodeApiService getService() {
if (sInstanceV2 == null) {
OkHttpClient client = getHttpClient();
sInstanceV2 = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(GsonFactory.create())).client(client)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build()
.create(SafecodeApiService.class);
}
return sInstanceV2;
}
@NonNull
private static OkHttpClient getHttpClient() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return new OkHttpClient.Builder().followRedirects(true).followSslRedirects(true)
.retryOnConnectionFailure(true).connectTimeout(CONNECTION_TIMEOUT_TIME, TimeUnit.SECONDS)
.writeTimeout(CONNECTION_TIMEOUT_TIME, TimeUnit.SECONDS)
.readTimeout(CONNECTION_TIMEOUT_TIME, TimeUnit.SECONDS)
.readTimeout(CONNECTION_TIMEOUT_TIME, TimeUnit.SECONDS).cache(null)
.addInterceptor(loggingInterceptor).addInterceptor(new ResponseInterceptor()).build();
}
private static class ResponseInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
try {
Request original = chain.request();
Request request = original.newBuilder().addHeader(CONTENT_TYPE, APPLICATION_JSON)
.addHeader("Connection", "Keep-Alive").addHeader(ACCEPT_ENCODING, GZIP_DEFLATE)
.method(original.method(), original.body()).build();
Response response = chain.proceed(request);
String rawJson = response.body().string();
Log.i("RESPONSE: ", String.format("raw JSON response is: %s", rawJson));
switch (response.code()) {
case HttpURLConnection.HTTP_OK:
// Re-create the response before returning it because body can be read only once
return response.newBuilder()
.body(ResponseBody.create(response.body().contentType(), rawJson)).build();
case HttpURLConnection.HTTP_UNAVAILABLE:
throw new MaintenanceException("Service Unavailable.");
default:
break;
}
return response;
} catch (SocketTimeoutException exception) {
throw new SocketTimeoutException("timeout");
}
}
}
private static class MaintenanceException extends RuntimeException {
public MaintenanceException(String message) {
super(message);
}
}
}
答案 0 :(得分:0)
我一次最多可以向服务器发送50个联系人。我已经在设备上检查了一下。我无法同时发送所有20000个联系人。我更改了逻辑,从ContentResolver检索时,将一一发送到服务器。我认为这可能是唯一的方法,并且我认为问题出在服务器中,该服务器无法处理API的post方法中的最大字符。感谢所有真正帮助我解决此问题的成员。