AsyncTask ProgressBar 更新中的多线程概念 wait() 和 notify()

Posted

技术标签:

【中文标题】AsyncTask ProgressBar 更新中的多线程概念 wait() 和 notify()【英文标题】:Multi threading concept wait() and notify() inside AsyncTask ProgressBar update 【发布时间】:2021-03-31 06:49:34 【问题描述】:

这里的后台方法需要根据列表的大小调用多个API请求。但我正在使用 while()。它不是等到请求 API 并得到响应。所以我在里面使用线程。如何同步。一旦API调用成功后,只需要调用下一个请求即可。

    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, "", "");
        
    

此线程正在使用但崩溃帮助我

    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();
                
                
                
        

【问题讨论】:

您没有发布“postRequest()”代码,所以运行“notify()”时不容易理解。也没有任何“WHILE”,那么你在哪里进行迭代?但是,您的解决方案似乎是错误的,因为“对话框”似乎是一个 UI 元素,不得直接从“doInBackground()”访问。请添加“postRequest()”代码 【参考方案1】:

你需要类似的东西:

/** 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);

只需调用“doAllRequests(...)”,提供适当的列表。 单个“OnPreExecute()”-like 将在第一次 API 调用时执行,单个“OnPostExecute()”-like 将在最后一次 APi 调用结束时执行。 在每次 API 调用(成功或失败)时,都会从 Main/UIThread 调用“case 111:”。

【讨论】:

感谢@emandt 的回复。我使用递归概念进行 API 请求调用。

以上是关于AsyncTask ProgressBar 更新中的多线程概念 wait() 和 notify()的主要内容,如果未能解决你的问题,请参考以下文章

AsyncTask ProgressBar 更新中的多线程概念 wait() 和 notify()

使用 CountDownTimer 更新 ProgressBar

第一次进入片段ListView时AsyncTask更新progressBar的进度失败,滚动ListView后就ok了

DialogFragment 和 ProgressBar 在任务更新时更新

Android中的动画ProgressBar更新

ProgressBar 未显示在 AsyncTask 中