How to display loading message during the execution of my function?

Viewed 122

Some functions take a long time to execute. I want to make the user wait with a progress bar. Unfortunately, when I run this one, it runs but only at the end of my function and not when I would like. Let me explain, I launch my progress bar with the "sendloading()" method but during my tests this bar is only displayed after the processing of the other functions "copyAssets" or "createOnClicBtnInsert()". Can someone explain to me why?

Here is my code :

 @Override
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    view.findViewById(R.id.btnInsertDataset2).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(!hasPermissions(getContext(),Permissions)){
                lay_dataset2 = view.findViewById(R.id.lay_dataset2); 
                messagePerm();
            }else {
                sendLoading(); //MY PROGRESS BAR
                btnInsert = view.findViewById(R.id.btnInsertDataset2);
                /** if perm ok -> insert*/
                copyAssets();
                createOnClicBtnInsert();
                view.findViewById(R.id.btnDeleteDataset2).setEnabled(true);
                Toast.makeText(getContext(), "Insert Success", Toast.LENGTH_SHORT).show();
            }


        }
    });
}

Here is my code for the progress bar :

    public void sendLoading() {
    int llPadding = 30;
    LinearLayout ll = new LinearLayout(getContext());
    ll.setOrientation(LinearLayout.HORIZONTAL);
    ll.setPadding(llPadding, llPadding, llPadding, llPadding);
    ll.setGravity(Gravity.CENTER);
    LinearLayout.LayoutParams llParam = new LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT);
    llParam.gravity = Gravity.CENTER;
    ll.setLayoutParams(llParam);

    ProgressBar progressBar = new ProgressBar(getContext());
    progressBar.setIndeterminate(true);
    progressBar.setPadding(0, 0, llPadding, 0);
    progressBar.setLayoutParams(llParam);

    llParam = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT);
    llParam.gravity = Gravity.CENTER;
    TextView tvText = new TextView(getContext());
    tvText.setText("Loading ...");
    tvText.setTextColor(Color.parseColor("#000000"));
    tvText.setTextSize(20);
    tvText.setLayoutParams(llParam);

    ll.addView(progressBar);
    ll.addView(tvText);

    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    builder.setCancelable(true);
    builder.setView(ll);

    AlertDialog dialog = builder.create();
    dialog.show();
    Window window = dialog.getWindow();
    if (window != null) {
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        layoutParams.copyFrom(dialog.getWindow().getAttributes());
        layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT;
        layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT;
        dialog.getWindow().setAttributes(layoutParams);
    }

}
2 Answers

Android is an event driven OS that runs on a single main thread. Drawing is an event. That means in order to draw the main thread needs to return to the event loop. Your code does not return to the event loop until after you do all your processing. Thus it won't draw until after the processing is done.

The way to solve this is to use either a Thread or a Kotlin coroutine to do the processing, and allow the main thread to return to the event loop. BTW, if you have long lasting processing you should not be doing it on the main thread anyway- it freezes your UI and makes your app appear non responsive, for the same reason. The main thread should do short quick calculations and respond to OS events only.

You should use an AsyncTask to execute your task in a separated Thread and update the progressbar in the UI thread. Here below a short example of it:

private class VeryLongTask extends AsyncTask<String, Integer, String> {
    
    private final Context context;
   
    public VeryLongTask(Context context) {
        this.context = context;
    }

    @Override
    protected String doInBackground(String... sUrl) {
        for (int i = 0; i < 255; i++) {
            // do your long task;
            // in this simple example is made by 255 iteraction
            if (anErrorOccured()) return "ERROR";
            publishProgress(i);
        }
        return "OK";
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // Initialize your progressbar to zero
        yourSetProgressMethod(0);
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        yourSetProgressMethod(progress[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        if (getActivity() != null) {
            if (result != null)
                Toast.makeText(context, result, Toast.LENGTH_LONG).show();
            }
        }
    }
}
Related