0

I'm very new to android development. Trying to connect some site and get data from it. I have this function called only from onCreate in the main activity. Every time I turn virtual Android phone left or right I see new "run()" strings in EditText and requests in Wireshark. How to stop that properly?

Tried call.cancel() and mClient.dispatcher().cancelAll() inside OnResponse

protected void Load(String url) {
    Request request = new Request.Builder()
            .url(url)
            .build();

    mClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            e.printStackTrace();
        }

        @Override
        public void onResponse(Call call, final Response response) throws IOException {
            if (response.isSuccessful()) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mEdit.setText(mEdit.getText() + "run()\n");
                    }
                });
            }
        }

    });
}
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Vadim
  • 93
  • 5
  • This happens because of reconfiguration. You activity gets recreated every time you turn your phone, hence your onCreate is called again and again which inturn will invoke you loadString method. – p.mathew13 Apr 02 '19 at 10:22
  • I've added traces at beginnings of onCreate and Load. After some turns "onCreate" and "Load" are printed only once and "run" are many https://imgur.com/dN0Inkr – Vadim Apr 02 '19 at 11:04

2 Answers2

0

retrofit supports enqueue canceling, and it works great. And i think if you will try to run this code - your client enqueues would be stoped

protected void Load(String url) {
    Request request = new Request.Builder()
            .url(url)
            .build();

    Call<Response> mCall = mClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
                if (call.isCanceled()) {
                    Log.e(TAG, "request was cancelled");
                }
                else {
                    Log.e(TAG, "other larger issue, i.e. no network connection?");
                }
        }

        @Override
        public void onResponse(Call call, final Response response) throws IOException {
            if (response.isSuccessful()) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mEdit.setText(mEdit.getText() + "run()\n");
                    }
                });
            }
        }

    });

    mCall.cancel();
}

I don't know you project structure and what kind of patterns you using(MVP, MVVM or else), but in simple, this code can be improved by returning Call

protected void Load(String url): Call<Response>

And then you can hadle you request status, and if it longer than 5 seconds for example, you call call.cancel() and request is stopping.

Scrobot
  • 1,911
  • 3
  • 19
  • 36
0

onCreate is called every time configuration changes (for example you rotate your phone/emulator). For more info: https://developer.android.com/guide/components/activities/activity-lifecycle

You can save your response to prevent new request on every onCreate. Something like this:

MainActivity {
  private Response savedResponse;

  onCreate() {
    if (savedResponse == null) {
      Load(url)
    }
  }
}

and in your onResponse save the response:

 @Override
    public void onResponse(Call call, final Response response) throws IOException {
        if (response.isSuccessful()) {
            savedResponse = response;    // <----
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mEdit.setText(mEdit.getText() + "run()\n");
                }
            });
        }
    }

However, correct way would be to separete network calls/requests from activity lifecycle and load data somewhere else (Service, WorkManager, ...)

Kubik
  • 610
  • 7
  • 15
  • I've thought about bool variable to stop Load call but this not helpes too. I've added mEdit.setText(mEdit.getText() + "Load()\n"); to the first line of Load function and it printed only once (and "onCreate" as well) – Vadim Apr 02 '19 at 10:53
  • OK, to keep your variables after onDestroy, you have to implement onSaveInstanceState. Check out this section: https://developer.android.com/guide/components/activities/activity-lifecycle#save-simple,-lightweight-ui-state-using-onsaveinstancestate – Kubik Apr 02 '19 at 11:03
  • But I might be consfused, I thought you want to call your Load function only once. So it should be correct to see only one log message from first line of Load function. – Kubik Apr 02 '19 at 11:05
  • Yes. I need only one Load() call and only one run(). Now I get something strange for me https://imgur.com/dN0Inkr - after four turns – Vadim Apr 02 '19 at 11:09
  • Well, it is strange. I suppose you don't have "run()" log anywhere else in your code. I don't see any reason to have multiple run logs from your posted code, if you have only one Load log. – Kubik Apr 02 '19 at 11:21