#OnClick(R.id.btnCheckStockId) void callCheck() {
MyDatabaseHelper dbHelper = new MyDatabaseHelper(ScanBarcodeActivity.this);
final SQLiteDatabase sql = dbHelper.getWritableDatabase();
String query = "SELECT barcode FROM stockopname where lokasi_item = ?";
cursor = sql.rawQuery(query, new String[]{lokasiItem});
try {
while (cursor.moveToNext()) {
final String stockId = cursor.getString(cursor.getColumnIndex("barcode"));
//API RETROFIT
ApiService api_check = ApiClient.getClient().create(ApiService.class);
Call<String> call = api_check.check_barcode(stockId);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
//get result
String sync_result = response.body();
String set_sync = "";
if (sync_result == "true") {
set_sync = "true";
} else {
set_sync = "false";
}
//update data on sqlite
ContentValues updatecolumn = new ContentValues();
updatecolumn.put("is_sync", set_sync);
sql.update("stockopname", updatecolumn, "barcode = ?", new String[]{stockId});
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
So the logic is, get a list from stock_id from the local database then check the server with API, if true the stock_id already exists on the server, if false the stock_id data does not yet exist. and the results of the responses need to be updated back to the local database with the column is_sync = true/false
when debugging, the pointer does not enter into onResponse but enters the next loop
I want to ask and need advice on how to get a response from the server immediately before the next loop in the cursor (using sqlite database), is there a solution?
Update, My Solution after reconstruct the code :
#OnClick(R.id.btnCheckStockId) void callCheck() {
MyDatabaseHelper dbHelper = new MyDatabaseHelper(ScanBarcodeActivity.this);
SQLiteDatabase sql = dbHelper.getWritableDatabase();
String query = "SELECT barcode FROM stockopname where lokasi_item = ?";
cursor_checksync = sql.rawQuery(query, new String[]{lokasiItem});
if (cursor_checksync != null) {
//more to the first row
cursor_checksync.moveToFirst();
//iterate over rows
for (int i = 0; i < cursor_checksync.getCount(); i++) {
callCheckSync(cursor_checksync);
cursor_checksync.moveToNext();
}
//close the cursor
cursor.close();
}
}
public void callCheckSync(Cursor csr_checksync)
{
final String stockId = csr_checksync.getString(csr_checksync.getColumnIndex("barcode"));
//API RETROFIT
ApiService api_check = ApiClient.getClient().create(ApiService.class);
Call<String> call = api_check.check_barcode(stockId);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
//get result
if(response.isSuccessful())
{
String sync_result = response.body();
String set_sync = "";
if (sync_result == "true") {
set_sync = "true";
} else {
set_sync = "false";
}
//update data on sqlite
update(stockId, set_sync);
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
public void update(String Barcode, String value)
{
MyDatabaseHelper dbHelper = new MyDatabaseHelper(ScanBarcodeActivity.this);
SQLiteDatabase sql = dbHelper.getWritableDatabase();
ContentValues updatecolumn = new ContentValues();
updatecolumn.put("is_sync", value);
sql.update("stockopname", updatecolumn, "barcode = ?", new String[]{Barcode});
}
I don't know if this is the best approach, but it solves my problem.
Call this method on onClick after defining initial cursor. Sorry for syntax I dont have IDE.
public void callMethod(Cursor cursor){
if (cursor.moveToNext()) {
//Retrofit
onResponse: () -> {
callMethod(cursor);
}
}else {
cursor.close();
}
}
Related
I have my own rest api for application so when I create post request to api I want to wait for the response and then do something. how I can wait for the call response.
insert TicketList
public long insertApi(TicketListTable ticketListTable) throws IOException {
Call<TicketListTable> ticketListTableCall = dataService.createTicketList(ticketListTable);
ticketListTableCall.enqueue(new Callback<TicketListTable>() {
#Override
public void onResponse(Call<TicketListTable> call, Response<TicketListTable> response) {
}
#Override
public void onFailure(Call<TicketListTable> call, Throwable t) {
}
});
// want to wait for the call to complete then return the value
//ticketListTableCall.execute();
Log.d("CODE", "insertApi: "+ ticketListTableCall.isExecuted());
return repo.insert(ticketListTable);
}
this method is called when button is clicked
public void saveListToDb(String[] split, String regexData){
String newListName = listName.getText().toString();
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
TicketListTable newTicketListTable = new TicketListTable();
newTicketListTable.setTicketListName(newListName);
newTicketListTable.setTicketListCreated(sd.format(Calendar.getInstance().getTime()));
newTicketListTable.setTicketListUpdated(sd.format(Calendar.getInstance().getTime()));
long ticketTableListId = 0;
try {
ticketTableListId = ticketTableVm.insert(newTicketListTable);
} catch (IOException e) {
e.printStackTrace();
}
if(ticketTableListId<=0){
throw new ArithmeticException();
}
for (String s : split) {
String[] values = s.split(regexData);
String number = values[0].replace("\n", "").replace("\r", "");
String info = values[1];
String warningNote = values[2];
String warning = values[3];
String customer = values[4];
int useable = Integer.parseInt(values[5].replaceAll("\\s+", "").replace("\n", "").replace("\r", ""));
TicketTable ticketTable = new TicketTable(number, customer, info, warningNote, useable, ticketTableListId,warning);
ticketTableVm.insert(ticketTable);
}
}
insert Ticket api call, before calling this I want to verify that the previous call has been successfully executed
public void insert(TicketTable ticketTable) throws IOException {
Call<TicketTable> ticketCall = dataService.createTicket(ticketTable);
//Response resp = ticketCall.execute();
ticketCall.enqueue(new Callback<TicketTable>() {
#Override
public void onResponse(Call<TicketTable> call, Response<TicketTable> response) {
repo.insert(ticketTable);
}
#Override
public void onFailure(Call<TicketTable> call, Throwable t) {
}
});
Hi in the below first name is not passing correctly to another activity.Can any one help me.
I am comparing my username with user_name if both are equal then I am sending my first name to another activity.
Support my username is admin and user_name is admin then I am able to pass the first name from the api. If it is second list item it is not working.
private void fetchUserJSON(final String sessionId, final String username){
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Write code for your refresh logic
// progressDialog = new ProgressDialog(getActivity());
// progressDialog.setIndeterminate(true);
// progressDialog.setMessage("Loading...");
// progressDialog.setCanceledOnTouchOutside(false);
// progressDialog.setCancelable(false);
// progressDialog.show();
// sessionId = getIntent().getStringExtra("sessionId");
//username = getIntent().getStringExtra("username");
String operation = "query";
String query = "select * from Users";
final GetNoticeDataService service = RetrofitInstance.getRetrofitInstance().create(GetNoticeDataService.class);
/** Call the method with parameter in the interface to get the notice data*/
Call<UserModule> call = service.UserRecordDetails(operation, sessionId, query);
/**Log the URL called*/
Log.i("URL Called", call.request().url() + "");
call.enqueue(new Callback<UserModule>() {
#Override
public void onResponse(Call<UserModule> call, Response<UserModule> response) {
Log.e("response", new Gson().toJson(response.body()));
if (response.isSuccessful()) {
Log.e("response", new Gson().toJson(response.body()));
UserModule userModule = response.body();
String success = userModule.getSuccess();
if (success.equals("true")) {
Results_Users results = userModule.getResult();
records = results.getRecords();
for (Records records1 : records) {
String user_name = records1.getUser_name();
String id = records1.getId();
Log.d("id",id);
String first_name = records1.getFirst_name();
String last_name = records1.getLast_name();
String email1=records1.getEmail1();
String title=records1.getTitle();
Records records=new Records(user_name,title,first_name,last_name,email1,id);
recordsList.add(records);
}
if(username.equals(recordsList.get(0).getUser_name()))
i = new Intent(LoginActivity.this, MainActivity.class);
i.putExtra("first_name", recordsList.get(2).getFirst_name());
startActivity(i);
finish();
}
}
}
#Override
public void onFailure(Call<UserModule> call, Throwable t) {
}
// progressDialog.dismiss();
});
}
}, 0);
return ;
}
Remove final from for loop
for (Records records1 : records) {
I don't know the logic of your whole code. But you can edit your loop like this:
String first_name = null;
for (Records records1 : records) {
if (username.equals(records1.getUser_name())) {
first_name = records1.getFirst_name();
break;
}
}
i = new Intent(LoginActivity.this, MainActivity.class);
i.putExtra("first_name", first_name);
startActivity(i);
finish();
Hello My app is freezes ui for some seconds while it is fetching data from network and stores it in db and then shows it in recyclerview. For fetching data from network I am using retrofit and for storing it and fetching form db Room library. Both with the help of MVVM pattern. Is there a way to remoove the UI freeze?
Here is my code:
In the Mainactivity when clicking download btn
downloadBtn.setOnClickListener(v ->
eventsViewModel.insertEvents(this));
Viewmodel class:
public void insertEvents(Context context){
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
String token = preferences.getString("token", "");
final Map<String,String> queryData = new HashMap<>();
queryData.put("token", token);
Call<EventsResponse> call = RetrofitClient.getmInstance().getApi().getEvents(queryData);
call.enqueue(new Callback<EventsResponse>() {
#Override
public void onResponse(Call<EventsResponse> call, Response<EventsResponse> response) {
if (response.code() == 401){
String email = preferences.getString("email", "");
String password = preferences.getString("password", "");
Call<LoginResponse> call1 = RetrofitClient.getmInstance().getApi().loginuser(email, password);
call1.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if (response.code() == 200){
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context); // 0 - for private mode
SharedPreferences.Editor editor = pref.edit();
editor.putString("token", response.body().getToken());
editor.apply();
insertEvents(context);
}
else {
}
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
}
if (response.code() == 200){
eventList = response.body().getData();
EventsTable eventsTable = new EventsTable();
TicketDatesTable ticketDatesTable = new TicketDatesTable();
for (int i = 0; i < eventList.size(); i++) {
eventsTable.setEvent_id(eventList.get(i).getId());
eventsTable.setTitle_tk(eventList.get(i).getTitle_tk());
eventsTable.setTitle_ru(eventList.get(i).getTitle_ru());
eventsTable.setImageURL("https://bilettm.com/" + eventList.get(i).getImage_url());
eventsTable.setStart_date(eventList.get(i).getStart_date());
eventsTable.setEnd_date(eventList.get(i).getEnd_date());
eventsTable.setSales_volume(eventList.get(i).getEnd_date());
eventsTable.setOrganiser_fees_volume(eventList.get(i).getOrganiser_fees_volume());
eventsTable.setViews(eventList.get(i).getViews());
eventsTable.setSales_volume(eventList.get(i).getSales_volume());
eventsTable.setIs_live(eventList.get(i).getIs_live());
if (!eventList.get(i).getTicket_dates().isEmpty()) {
showTimeList = eventList.get(i).getTicket_dates();
int b = 0;
while (b < showTimeList.size()) {
ticketDatesTable.setEvent_id(showTimeList.get(b).getEvent_id());
ticketDatesTable.setTicket_date(showTimeList.get(b).getTicket_date());
insertTicketDates(ticketDatesTable);
try {
Thread.sleep(150);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
b++;
}
}
insert(eventsTable);
try {
Thread.sleep(150);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
#Override
public void onFailure(Call<EventsResponse> call, Throwable t) {
}
});
}
public void insert(EventsTable data){
repository.insertEvents(data);
}
public void insertTicketDates(TicketDatesTable ticketDatesTable){
repository.insertTicketDates(ticketDatesTable);
Here is my repository :
public void insertEvents(EventsTable data){
new EventInsertion(eventsDAO).execute(data);
}
private static class EventInsertion extends AsyncTask<EventsTable, Void, Void> {
private EventsDAO eventsDAO;
private EventInsertion(EventsDAO eventsDAO) {
this.eventsDAO = eventsDAO;
}
#Override
protected Void doInBackground(EventsTable... eventsTables) {
eventsDAO.insertEvents(eventsTables[0]);
return null;
}
}
public void insertTicketDates(TicketDatesTable data){
new TicketDatesInsertion(eventsDAO).execute(data);
}
private static class TicketDatesInsertion extends AsyncTask<TicketDatesTable, Void, Void> {
private EventsDAO eventsDAO;
private TicketDatesInsertion(EventsDAO eventsDAO) {
this.eventsDAO = eventsDAO;
}
#Override
protected Void doInBackground(TicketDatesTable... ticketDatesTables) {
eventsDAO.insertTicketDates(ticketDatesTables[0]);
return null;
}
}
Here is my DAO:
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insertEvents(EventsTable data);
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insertTicketDates(TicketDatesTable datesTable);
I think it freezes when it is storing it into sqlite db
I found my problem. It was initializing entity before starting for loop:
BEFORE:
EventsTable eventsTable = new EventsTable();
for (int i = 0; i < eventList.size(); i++) {
INSERT();
}
AFTER:
for (int i = 0; i < eventList.size(); i++) {
EventsTable eventsTable = new EventsTable();
INSERT();
}
A better solution would be to collect all your required objects in an ArrayList and then pass it on to the AsyncTask and from there to DAO for bulk insertion.
And remove all Thread.sleep(150) statements as they serve no purpose.
why you are using this Thread.sleep(150);Call is already a background task in retrofit
I had created service that retrieves contacts from android device name, mobile number and email and stores in array list with custom object of contacts. I am having 20,000 contacts in my device. I am converting that array list to JSON Array using Gson. And I am sending data to server but request fails. If I am sending small amount of data then API gives successful response. I want to know why I am not able to have success request when there is large data in JSON format.
This is sample format data that i will send to server
[
{
"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": "[]"
}
]
This is print stack trace that I am getting
06-25 17:32:21.816 19421-20008/ D/OkHttp: <-- HTTP FAILED: javax.net.ssl.SSLException: Write error: ssl=0x40d92618: I/O error during system call, Broken pipe
06-25 17:32:21.826 19421-19421/ W/System.err: javax.net.ssl.SSLException: Write error: ssl=0x40d92618: I/O error during system call, Broken pipe
06-25 17:32:21.856 19421-19421/ W/System.err: at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(Native Method)
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:719)
at okio.Okio$1.write(Okio.java:79)
at okio.AsyncTimeout$1.write(AsyncTimeout.java:180)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:179)
at okio.RealBufferedSink.writeUtf8(RealBufferedSink.java:54)
at okhttp3.internal.http1.Http1Codec.writeRequest(Http1Codec.java:172)
at okhttp3.internal.http1.Http1Codec.writeRequestHeaders(Http1Codec.java:130)
at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:50)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
Here is my service code that does all stuffs.
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();
}
}));
}
}
}
This is my network manager class of 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);
}
}
}
I am able to send max 50 contacts to server at a time. I had checked this practically on device. I am not able to send all 20000 contacts at same time. I changed my logic I will send one by one contact to server as and when retrieved from ContentResolver. I think this could be the only way and I think problem is with server that is not able to handle max character in post method of API. Thanks to all members who really helped me to resolve this issue.
I'm very new to RxJava and although I have seen multiple questions related to the one I am asking, I can't seem to piece them out altogether.
I have a PostPatrol object containing the following data:
public class PostPatrol {
String checkpoint_name;
String status;
int user;
String detail;
List<String> photos;
public PostPatrol(int cpId, String checkpoint_name, String detail, List<String> photos, String detail) {
this.cpId = cpId;
this.checkpoint_name = checkpoint_name;
this.detail = detail;
this.photos = photos;
this.status = status;
}
//getters and setters
}
What I'm trying to do now is to save a local list of photos into this PostPatrol record, but before that I have to upload the photos one by one with retrofit, get back a url and save that to a list which I then set as the photos for the PostPatrol record.
Once I save all the needed details for a certain PostPatrol record, I then send that again through retrofit.
Currently, I am doing it this way:
I pass the photos to a function to upload the image one by one
The function is like this:
private void uploadImage(List<String> photos, String folder, long requestId) {
final int size = photos.size();
final long reqId = requestId;
for (String path : photos) {
File file = new File(path);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestBody);
RequestBody folderName = RequestBody.create(MediaType.parse("text/plain"), folder);
ApiEndpointInterface apiEndpointInterface = RetrofitManager.getApiInterface();
Call<FileInfo> call4File = apiEndpointInterface.postFile(body, folderName);
call4File.enqueue(new ApiCallback<FileInfo>() {
#Override
protected void do4Failure(Throwable t) {
Log.d(TAG, t.toString());
snackbar = Snackbar.make(viewPendingRequestLayout, R.string.sb_image_upload_error, Snackbar.LENGTH_SHORT);
snackbar.show();
position++;
}
#Override
protected void do4PositiveResponse(Response<FileInfo> response) {
Log.d(TAG, "Uploaded Image");
FileInfo fileDetails = response.body();
listUrls.add(fileDetails.getImage());
position++;
if (position == size) {
postRequest(reqId);
position = 0;
}
}
#Override
protected void do4NegativeResponse(Response<FileInfo> response) {
String bodyMsg = "";
try {
bodyMsg = new String(response.errorBody().bytes());
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, bodyMsg);
snackbar = Snackbar.make(viewPendingRequestLayout, R.string.sb_image_upload_error, Snackbar.LENGTH_SHORT);
snackbar.show();
position++;
}
});
}
}
In do4PositiveResponse I use local variables to keep track whether I have uploaded all the photos before sending them to a function where the list is saved to the PostPatrol record. Sometimes though, I get problems where the photos aren't uploaded at all since it fires too late or too early.
This is my code onpostRequest()
private void postRequest(long requestId) {
if(mapIdPatrol.containsKey(requestId)){
PostPatrol postPatrol = mapIdPatrol.get(requestId);
postPatrol.setPhotos(listUrls);
postPatrolRequest(postPatrol, requestId);
}
listUrls = new ArrayList<>();
}
And finally my code on postPatrolRequest()
private void postPatrolRequest(final PostPatrol postPatrol, final long requestId){
ApiEndpointInterface apiEndpointInterface = RetrofitManager.getApiInterface();
Call<ResponseId> call4Handle = apiEndpointInterface.handleCheckpoint(postPatrol);
call4Handle.enqueue(new ApiCallback<ResponseId>() {
#Override
protected void do4Failure(Throwable t) {
finishUploading();
Log.d(TAG, t.toString());
}
#Override
protected void do4PositiveResponse(Response<ResponseId> response) {
RequestsDataSource.removeRequest(getApplication(),requestId);
finishUploading();
}
#Override
protected void do4NegativeResponse(Response<ResponseId> response) {
finishUploading();
String bodyMsg = "";
try {
bodyMsg = new String(response.errorBody().bytes());
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, bodyMsg);
snackbar = Snackbar.make(viewPendingRequestLayout, getResources().getText(R.string.sb_negative_response), Snackbar.LENGTH_SHORT);
snackbar.show();
}
});
}
I know this is very inefficient and so I would like your help so I can try to find a way around it with the use of RxJava. Thank you.
Is the operation atomic? i.e. if saving some of the photos via Retrofit fails, do you still have to proceed?
Anyway, roughly the solution will be something like that (pseudocode):
Observable<String> urls = Observable.from(listOfPhotoFilePaths)
.flatMapDelayError(path -> { return retrofit.save(readFile(path))})
.toList()
Observable<PostPatrol> pp = urls
.map(list -> { return new PostPatrol(list)})