I have a method call first thing inside a setOnClickListener block that gets some value from an API which I use to start a live stream, it's critical for that method call, to finish before anything else is done inside the block in order to get the correct result because everything else after that first line method call is dependent on that.

Code snippet:

myButton.setOnClickListener {

            // Everything depends on check stream call
            currentViewModel.checkStream()

            if (!PlaybackService.isServiceStarted) {
                if (isStreaming!!) {
                    onPlayerStart()
                    sliding_player.panelState = SlidingUpPanelLayout.PanelState.COLLAPSED
                } else
                    Snackbar.make(appbar, R.string.stream_fail, Snackbar.LENGTH_LONG).show()
            }
        }

I need for the myButton.setOnClickListener block to wait on
currentViewModel.checkStream() in order for the following lines to work correctly (give the correct result).

Is it possible to do that? Using some sort of callback method? Should I consider doing that with Retrofit2?

4 Answers

0
Community On

Try to first call api then get response to call your method like this way..

Call<UploadObject> fileUpload = uploadImage.uploadFile(fileToUpload, filename);
        fileUpload.enqueue(new Callback<UploadObject>() {
            @Override
            public void onResponse(Call<UploadObject> call, Response<UploadObject> response) {
                Toast.makeText(MainActivity1.this, "Success " + response.message(), Toast.LENGTH_LONG).show();
                Toast.makeText(MainActivity1.this, "Success " + response.body().toString(), Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFailure(Call<UploadObject> call, Throwable t) {
                Log.d(TAG, "Error " + t.getMessage());
            }
        });
0
Rahul On

make your network call inside asycn class and use as below mentioned code

myButton.setOnClickListener {
    //start asycn call from here
    // new Async().execute();
        }

class Async extends Async{
    onPreExecute(){}

    doInBackground(){
        // below method call should be synchronised
        currentViewModel.checkStream()
    }

    onPostExecute(){
        if (!PlaybackService.isServiceStarted) {
                if (isStreaming!!) {
                    onPlayerStart()
                    sliding_player.panelState = SlidingUpPanelLayout.PanelState.COLLAPSED
                } else
                    Snackbar.make(appbar, R.string.stream_fail, Snackbar.LENGTH_LONG).show()
            }
    }

}
0
Ajay - Rlogical On

It can be possible if you call your API in on main thread but it will stuck your UI. So the best way is to call your API in Asynchronous way and execute you further code once API return success.

Check below AsyncTask call.

public class AsyncUploadStream extends AsyncTask<String, Integer, Object> {

    private ProgressDialog dialog;

    public AsyncUploadStream() {   
        dialog = new ProgressDialog(context);
        dialog.setMessage("Please Wait...");
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        dialog.show();
    }

    @Override
    public Object doInBackground(String... params) {
        return currentViewModel.checkStream();
    }

    @Override
    public void onPostExecute(Object result) {
        super.onPostExecute(result);

        if (dialog != null && dialog.isShowing())
            dialog.dismiss();

        try {

            if (!PlaybackService.isServiceStarted) {
                if (isStreaming !!){
                    onPlayerStart()
                    sliding_player.panelState = SlidingUpPanelLayout.PanelState.COLLAPSED
                } else{
                    Snackbar.make(appbar, R.string.stream_fail, Snackbar.LENGTH_LONG).show()
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
1
tynn On

You should never wait on the main thread and onClick() is called on the main thread.

You could consider an asynchronous framework to handle your use-case. These frameworks would include RxJava, AsyncTask or even plain Handler implementations. To be nearer to your actual implementation, Kotlin Coroutines might be most suitable, as switching back to the main thread is very clear. It also integrates well with Retrofit.

myButton.setOnClickListener {
    coroutineScope.launch(Dispatchers.IO) {
        // make sure checkStream() is a suspending function
        // to wait for it execution to finish
        currentViewModel.checkStream()

        if (!PlaybackService.isServiceStarted) {
            launch(Dispatchers.Main) {
                if (isStreaming!!) {
                    onPlayerStart()
                    sliding_player.panelState = COLLAPSED
                } else {
                    Snackbar.make(appbar, R.string.stream_fail, LENGTH_LONG).show()
                }
            }
        }
    }
}

The coroutineScope you'd have to attach to the lifecycle to not leak the activity or fragment.