Multi threading concept wait() and notify() inside AsyncTask ProgressBar update

47 views Asked by At

Here inside background method need to call multiple API request based on the size of the list. But i'm using while(). It is not wait un till request API and get response. So am using thread inside. How to synchronized. Once the API call get success after only need to call next request.

    private class AsyncPost extends AsyncTask<String, Void, Void> {
        String strResult = "";

        @Override
        protected Void doInBackground(String... params) {

            try {

                GlobalVariables.rqCount=0;
                mHandler=null;
                mHandler = new Handler(Looper.getMainLooper()) {
                    @Override
                    public void handleMessage(android.os.Message message) {
                        onProgressUpdate(message.getData().getString("MessageString"));     
                    }
                };
                strResult = "ENSURE NOT EMPTY";
                strResult=getRequestResult(Listactivity.this,50, mHandler);

            }
            catch (Exception e)
            {   
            dialog.dismiss();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void resultGetlogin) {


            try {
                dialog.dismiss();

                if(strResult.equals("Success")){
                    CustomDiallog.showAlertDialog(Listactivity.this, "Successfully!!");
                }else{
                    CustomDiallog.showAlertDialog(Listactivity.this, "FAIL!!");
                }

            } catch (Exception e) {
                dialog.dismiss();

            }

        }

        protected void onProgressUpdate(String... values) {
            dialog.setMessage(""+values[0]);
        }

        protected void onPreExecute() {

            dialog = ProgressDialog.show(Sync_Bulk.this, "", "");
        }
    }

This thread am using but getting crash help me

    private class getRequestResult(Context context, int allSyncLimit,Handler handler2){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        inalContext.wait();

                        if (res_result.equals("Success")) {
                            result[0] = "Success";
                        } else {
                            result[0] = "fail";
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }).start();


                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        synchronized (finalContext) {
                            postRequest((Activity) finalContext, list);   // This is Api method and notify() is called
                        }
                    }
                }).start();
                
                }
                
        }
1

There are 1 answers

1
emandt On

You need something similar to:

/** Class for Synchronize two Threads */
private static class SyncObj<T> {
    @Nullable
    private T mValue = null;
    public SyncObj(@Nullable final T initValue) { this.mValue = initValue; }
    public void set(@Nullable final T value) { this.mValue = value; }
    @Nullable
    public T get() { return this.mValue; }
}

/** A Thread is used instead of {@link AsyncPost} */
private class AsyncPost extends Thread {
    private Handler mAsyncPostHandler;
    private final Handler mMainThreadHandler;
    private boolean mOnPreExecuted = false;
    public AsyncPost() {
        mMainThreadHandler = new Handler(Looper.getMainLooper()) {
            @UiThread @MainThread
            @Override
            public void handleMessage(@NonNull final Message message) {
                switch (message.what) {
                    case 111: {
                        @Nullable
                        final String cRequestText = (String)message.obj;
                        if (cRequestText == null) break;
                        dialog.setMessage(cRequestText);
                        break;
                    }
                    default: { }    //all Runnables sent to "mMainThreadHandler" are executed "here"
                }
            }
        };
    }
    @WorkerThread
    @Override
    public void run() {
        Looper.prepare();
        mAsyncPostHandler = new Handler(Looper.myLooper()) {
            @Override
            public void handleMessage(@NonNull final Message message) {
                switch (message.what) {
                    case -1: {
                        final Looper cMyLooper = Looper.myLooper();
                        if (cMyLooper != null) cMyLooper.quit();
                        break;
                    }
                    case 555: {
                        if (!mOnPreExecuted) {
                                //esecuted on Main/UIThread at first API Request...
                            OnMainThreadRun(new Runnable() {    //SAME AS "onPreExecute()"
                                @Override
                                public void run() { dialog = ProgressDialog.show(Sync_Bulk.this, "", ""); }
                            });
                            mOnPreExecuted = true;
                        }
                        final List<?> cList = (List<?>)message.obj;
                        if (cList == null) break;
                        final SyncObj<String> cSyncObj = new SyncObj<>(null);
                            //loop through the List
                        @Nullable
                        String cRequesteResult;
                        for (final Object cItem : cList) {
                                //call API Request for each item in the List...
                            postRequest(cSyncObj, cItem);
                            try {
                                    //...wait until "notify()" is called
                                synchronized (cSyncObj) {
                                        //loop until "SyncObj.set()" was called with a valid Value
                                    while ((cRequesteResult = cSyncObj.get()) == null) cSyncObj.wait();
                                        //check SyncObj result
                                    if (cRequesteResult.equals("OK")) {
                                        Log.i("MainActivity", "Request successfully");
                                    } else {
                                        Log.w("MainActivity", "Request failed: " + cRequesteResult);
                                    }
                                        //update the Dialog on Main/UIThread
                                    OnProgressUpdate(cRequesteResult);
                                }
                            } catch (Exception e) {
                                Log.e("MainActivity", "Stopping all Request due to Exception: " + e.getMessage());
                            }
                        }
                            //terminate this Thread
                        postToAsyncThread_Quit();
                        break;
                    }
                }
            }
        };
        Looper.loop();
        this.OnMainThreadRun(new Runnable() {   //SAME AS "OnPostExecute()"
            @Override
            public void run() {
                ..executed on Main/UIThread at the end of all..
            }
        });
    }
    /** Execute a {@link Runnable} on MainThread/UiThread */
    @WorkerThread
    private void OnMainThreadRun(@Nullable final Runnable runnable) {
        if (runnable == null) return;
        mMainThreadHandler.post(runnable);
    }
    @AnyThread
    private void OnProgressUpdate(@Nullable final String text) { mMainThreadHandler.sendMessage(Message.obtain(mMainThreadHandler, 111, text)); }
    /** Execute a {@link Runnable} on {@link AsyncPost} Thread */
    @AnyThread
    private void postToAsyncThread_DoRequests(@Nullable final List<?> list) { mAsyncPostHandler.sendMessage(Message.obtain(mAsyncPostHandler, 555, list)); }
    /** Terminate {@link AsyncPost} Thread */
    @AnyThread
    private void postToAsyncThread_Quit() { mAsyncPostHandler.sendEmptyMessage(-1); }
}

private void postRequest(final SyncObj<String> syncObj, @NonNull final Object listItem) {
        //execute API Request which will trigger one of Listener methods
    doAsyncRequest(listItem, new ResponseListener() {
        @Override
        void onSuccess() {
            synchronized (syncObj) {
                syncObj.set("OK");
                syncObj.notify();
            }
        }
        @Override
        void onFailed() {
            synchronized (syncObj) {
                syncObj.set("ERROR");
                syncObj.notify();
            }
        }
    });
}

private void doAllRequests(@Nullable final List<?> list) {
    final AsyncPost cAsyncPost = new AsyncPost();
    cAsyncPost.start();
    cAsyncPost.postToAsyncThread_DoRequests(list);
}

Just call "doAllRequests(...)" providing the appropriate List. A single "OnPreExecute()"-like will be executed at first API call and a single "OnPostExecute()"-like will be executed at the end of last APi call. At each API Call (success or fail) "case 111:" will be called from the Main/UIThread.