如何使用翻新将大型JSON数据发送到服务器?

时间:2018-06-25 03:04:14

标签: android retrofit2

我创建了从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);
    }
  }
}

1 个答案:

答案 0 :(得分:0)

我一次最多可以向服务器发送50个联系人。我已经在设备上检查了一下。我无法同时发送所有20000个联系人。我更改了逻辑,从ContentResolver检索时,将一一发送到服务器。我认为这可能是唯一的方法,并且我认为问题出在服务器中,该服务器无法处理API的post方法中的最大字符。感谢所有真正帮助我解决此问题的成员。