Как отправить Большие Данные JSON на сервер с помощью Retrofit? - PullRequest
0 голосов
/ 25 июня 2018

Я создал сервис, который извлекает контакты из имени устройства Android, номера мобильного телефона и электронной почты и сохраняет их в списке массивов с пользовательским объектом контактов.У меня 20 000 контактов в моем устройстве.Я конвертирую этот список массивов в массив JSON, используя Gson.И я отправляю данные на сервер, но запрос не выполняется.Если я отправляю небольшое количество данных, то 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 FAILED: javax.net.ssl.SSLException: Ошибка записи: ssl = 0x40d92618: ошибка ввода-вывода во время системного вызова, сломанный канал 06-25 17: 32: 21.826 19421-19421 / W / System.err:javax.net.ssl.SSLException: Ошибка записи: ssl = 0x40d92618: ошибка ввода-вывода во время системного вызова, сломанный канал 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.java:79) в okio.AsyncTimeout $ 1.write (AsyncTimeout.java:180) в okio.RealBufferedSink.emitCompleteSegments (RealBufferedSink.java:179) в okio.RealBufferedSink.writeUtf8 (RealBufferedSink.jtthp.phttp..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.kh.intercept (ConnectInterceptor.java:45) в okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:147) </p>

Вот мой сервисный код, который выполняет все действия.

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 голосов
/ 26 июня 2018

Я могу отправить максимум 50 контактов на сервер одновременно.Я проверил это практически на устройстве.Я не могу отправить все 20000 контактов одновременно.Я изменил свою логику, я буду отправлять один за другим контакт на сервер, как и при получении из ContentResolver.Я думаю, что это может быть единственным способом, и я думаю, что проблема с сервером, который не может обработать максимальное количество символов в методе post API.Спасибо всем участникам, которые действительно помогли мне решить эту проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...