Android Phonegap: Notify javascript when an AsyncTask is finished

后端 未结 3 806
礼貌的吻别
礼貌的吻别 2020-12-02 19:19

in my app, when user click on a button in webview, a phonegap plugin will be called to trigger an asynctask to download file from internet. Now i want to send a signal back

相关标签:
3条回答
  • 2020-12-02 19:36

    I also asked this question in Phonegap Google Group, here is response of Simon Mac Donald. It works perfectly for me:


    You can handle this situation by using the Plugin API quite easily. It is implemented in the core API items Connection and Battery. What you need to do is:

    1) In your execute() method of your plugin save the callbackId you get.

    2) Return a NO_RESULT plugin result and set keep callback id to true.

        PluginResult pluginResult = new  PluginResult(PluginResult.Status.NO_RESULT); 
        pluginResult.setKeepCallback(true); 
        return pluginResult; 
    

    3) When you async java method finishes return another plugin result like this:

        PluginResult result = new PluginResult(PluginResult.Status.OK, data); 
        result.setKeepCallback(false); 
        this.success(result, this.myCallbackId); 
    

    As I said, you can look at the code in GitHub to see how we are using this for Connection and Battery.


    0 讨论(0)
  • 2020-12-02 19:36

    Here is a detailed example:

    Lets create some interface that should be called when AsyncTask will finish the stuff, a.e when onPostExecute called.

    In my case we fetch some JSONArray data

    MyTaskListenerItf.java

    public interface GroupTaskListenerItf {
       public void onTaskDone(JSONArray groupArray);
    }
    

    The AsyncTask template of looks like:

    MyBuildTask.java

    public class MyBuildTask extends AsyncTask<Void, Void, SomeData>{
    
        private MyTaskListenerItf mTl = null;
    
        public MyBuildTask(Context context,  MyTaskListenerItf tl) {
            super();
            this.mContext = context;        
            this.mTl = tl;
        }
    
           @Override
           protected SomeData doInBackground(Void... params) {
              /* ... */
            }
    
        @Override
        protected void onPostExecute(WmTransferItem transferItem) {
           // ...
    
    
            if(this.mTl != null){           
                JSONArray data  = new JSONArray("");            
                this.mTl.onTaskDone(data);
            }      
    
           // ..
         }
    }
    

    So now our CordovaPlugin class should look like:

    MyCordovaPlugin.java

    public class MyCordovaPlugin extends CordovaPlugin implements GroupTaskListenerItf {
    
           // we need this callback when Task will finish
       private CallbackContext mMyCallbackContext = null; 
    
       @Override
       public boolean execute(String action, JSONArray args,CallbackContext callbackContext) throws JSONException {
              if("runMe".equals(action)){
                 final GroupTaskListenerItf gt = this;
    
                  mMyCallbackContext = callbackContext;
                 // pass our 'GroupTaskListenerItf' interface to async class    
                  MyBuildTask task = new MyBuildTask(cordova.getActivity(), gt);
                  task.execute();
    
            PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
            pluginResult.setKeepCallback(true);
            callbackContext.sendPluginResult(pluginResult); 
              }
              else{
                  this.cordova.getThreadPool().execute( new Runnable() {
                       public void run() {
                         // BTW, here you might run something else out of UI Thread
                        }
                 });
              }
       }
    
    /* ... */
    
     @Override
    public void onTaskDone(JSONArray data) {
    
    if (this.mGroupCallbackContext != null) {
            PluginResult result = new PluginResult(PluginResult.Status.OK, data);
            result.setKeepCallback(false);
            this.mMyCallbackContext.sendPluginResult(result);
          }     
    }
    

    That's all.

    Hope it will help to someone.

    0 讨论(0)
  • 2020-12-02 19:51

    This is how I solve problems like your.

    1) Create and associate a JavascriptInterface to your WebView. A JavascriptInterface is simply a class inside which you can declare some Java method you want to use from JS.

    public class JSInterface() {
        private final CountDownLatch latch = new CountDownLatch(1);
    
        public void waitForProceed() {
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public void canProceed() {
            latch.countDown();
        }
    }
    

    2) In your AsyncTask, at the end of onPostExecute() method, you have to call the canProceed() method to notify to JSInterface that it can exit from waitForProceed() method.

    public class MyAsyncTask extends AsyncTask<.......> {
        private JSInterface jsi;
        ... // other class property
    
        public MyAsyncTask(JSInterface jsi) {
            ...
            //do what you want with other class property
    
            this.jsi = jsi;
        }
    
        @Override
        public ... doInBackground(...) {
            ...
            //do something
        }
    
        @Override
        public void onPostExecute(...) {
            ...
            //do something
    
            jsi.canProceed();
        }
    }
    

    3) In your Activity you have to associate the JSInterface object to your WebView:

    WebView mWebView;
    
    ...
    
    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.addJavascriptInterface(new JSInterface(), "JSIface");
    

    4) Finally, in JS, you can call AsyncTask (I don't know how you call it, but I guess you use somthing like a JSInterface) and after call waitForProceed() method:

    startAsyncTask(); //somehow
    JSIface.waitForProceed();
    

    I hope it solves your problem ;)

    0 讨论(0)
提交回复
热议问题