0

Actually i'm trying to post a text file to my server and i would be able to handle the error when i've sent the file but i didn't get the response (In case the file has been sent the network is gone down so the server received the file but the device don't know it)

Because for now i'm getting an issue because if i don't get the response when the device return online it send again the same file and i would prevent it.

Seems it's hidely retry to send the file on connection fail or something like that.

Here is my method which i use onClick to send the file:

 public void sendPost() {
        @SuppressLint({"SdCardPath", "DefaultLocale"}) final File file = new File("/data/data/com.example.igardini.visualposmobile/files/"+String.format("%03d", Integer.valueOf(nTerminalino))+"_"+nTavoli.getText().toString()+".txt");

        final MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);

        final RequestBody fbody = RequestBody.create(MediaType.parse("text/*"), file);
        builder.addFormDataPart(String.format("%03d", Integer.valueOf(nTerminalino))+"_"+nTavoli.getText().toString(), file.getName(),fbody);

        final MultipartBody requestBody = builder.build();

        final APIService apiService = ApiUtils.getAPIService(ipCASSA);

        final Call<Void> calls = apiService.savePost(requestBody);



        calls.enqueue(new Callback<Void>() {
            @Override
            public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) {
                if (response.isSuccessful()) {
                    Log.i("RESPONSE: ", response.toString());


                    Print();
                    dialogLoading.dismiss();
                    Runtime.getRuntime().gc();


//                    checkFile task = new checkFile();
//                    task.execute();

                }else {
                    Toast.makeText(pterm.this,"ERRORE",Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
                    if(t instanceof IOException) {
                        Log.e("TAG", t.toString());
                        MediaPlayer mpFound = MediaPlayer.create(pterm.this, R.raw.errorsound);
                        mpFound.start();
                        Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                        if (v.hasVibrator()) {
                            v.vibrate(6000);
                        }
                        new GlideToast.makeToast(pterm.this, "CONNESSIONE FALLITA!", GlideToast.LENGTHLONG, GlideToast.FAILTOAST).show();
                        dialogLoading.dismiss();
                    }

            }
        });
    }

While here are my other useful classes:

class ApiUtils {

    private ApiUtils() {}



    static APIService getAPIService(String ipCASSA) {

        String BASE_URL = "http://"+ipCASSA+"/web/";

        final OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10000, TimeUnit.MILLISECONDS)
                .writeTimeout(10000, TimeUnit.MILLISECONDS)
                .readTimeout(10000, TimeUnit.MILLISECONDS)
                .retryOnConnectionFailure(false)
                .build();


        return RetrofitClient.getClient(BASE_URL,okHttpClient).create(APIService.class);
    }
}

public interface APIService {

    @POST("CART=PTERM")
    Call<Void> savePost(@Body RequestBody text);

}

class RetrofitClient {

    private static Retrofit retrofit = null;


    static Retrofit getClient(String baseUrl, OkHttpClient okHttpClient) {
        if (retrofit==null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .client(okHttpClient)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}
NiceToMytyuk
  • 3,644
  • 3
  • 39
  • 100

1 Answers1

1

In that case I would add to file some sort of device generated random ID, and send it along with request.

On server side I would change logic to first try to locate file in DB using this ID, if there is none, store it and return status OK along with maybe server side id (might come handy later).

If there is file with ID provided on request, just return server side ID with status 200 - that way you will not store it twice.

You can even go further - if you have not stable connection (it seems like it from description) you could even make seperate REST call to check if file is on server side by generated id or checksum, and if not then start to send it - it will safe bandwitch.

It does not have to be generated ID - it can be checksum of a file for example. Whatever is easier for you.

For generating ID you could use Android's UUID https://developer.android.com/reference/java/util/UUID

For checksum check this answer: How to generate an MD5 checksum for a file in Android?

BTW - I would not do 10 seconds timeout limit - it is way too much, and user experience will be terrible

Lukas Novicky
  • 921
  • 1
  • 19
  • 44
  • Actually the problem is that i'm not saving any file to the DB to check if the file exist yet or not. It's an app for waiter and i just send a .txt file with the receipt then when the POS got it and printed the file is just deleted – NiceToMytyuk Dec 18 '18 at 14:01
  • you could store UUID in POS DB or maybe even in memory, and clean it 20 seconds after receiving to give time to print it – Lukas Novicky Dec 18 '18 at 14:02
  • But the problem would be that the POS printed yet the receipt, the network gone down on the device and i'm still forcing the waiter to resend it... – NiceToMytyuk Dec 18 '18 at 14:02
  • The problem is still that i'm not developing the POS so i have to find a solution on the mobile side.. – NiceToMytyuk Dec 18 '18 at 14:03
  • 1
    so there is none I am afraid - for REST we can only have response as a confirmation of sending – Lukas Novicky Dec 18 '18 at 14:19
  • The point i can't understand is why the connection is not closed if i don't get a response but it still retrying to send the file.. if i would be able to abort onFail in someway the call that would be great – NiceToMytyuk Dec 18 '18 at 14:24
  • you gave it 10 seconds of timeout - connection looses coverage, receipt is printed but connection did not get response, device gets in coverage again and tries to resend. make timeout lower and it should work. – Lukas Novicky Dec 18 '18 at 14:28
  • Actually with timeout 3s it's working better but still if the device is disconnected instantly i'm getting the same issue.. is there a way to disable that retries when the device gets out of coverage? – NiceToMytyuk Dec 18 '18 at 14:30
  • 1
    You must understand how REST works - until there is timeout, or response connection is alive. you should play with timeouts, connection times and readtimeouts to find something that suits you. I would start with default values - for that just delete those lines and see how it works. – Lukas Novicky Dec 18 '18 at 14:34
  • So it's a normal behaviour of all Http clients and even if i will use something else instead of Retrofit and OkHttp i will get the same issue? – NiceToMytyuk Dec 18 '18 at 14:38
  • 1
    no. by what you described in comments I can tell you that prolly implementation on POS is faulty, but you also said that you cannot do anything about it. So yes - on every HTTP client you will have same issues. Play with those timeouts - start with default and see if this is OK. I believe it should be fine – Lukas Novicky Dec 18 '18 at 14:41
  • On normal devices after playing with timeouts i doesn't have anymore that problem but it still remain when i'm using Radio Frequency instead of Wi-Fi, i'll try to contact the manufacturer to get some support. Thank you – NiceToMytyuk Dec 18 '18 at 14:43
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/185425/discussion-between-johnkarry-and-lukas-novicky). – NiceToMytyuk Dec 18 '18 at 14:56