Android Phonegap:当 AsyncTask 完成时通知 javascript

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7751522/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 01:10:48  来源:igfitidea点击:

Android Phonegap: Notify javascript when an AsyncTask is finished

javascriptandroidcordovaandroid-asynctask

提问by Peacemoon

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 to javascript part when the asynctask is finished. But i don't know how to do it, because my plugin had already send something back before the asynctask is finished. Does anyone know how i can notify my javascript part without plugin in Phonegap?

在我的应用程序中,当用户单击 webview 中的按钮时,将调用 phonegap 插件以触发 asynctask 从 Internet 下载文件。现在我想在异步任务完成时将信号发送回 javascript 部分。但我不知道该怎么做,因为我的插件在异步任务完成之前已经发回了一些东西。有谁知道我如何在没有 Phonegap 插件的情况下通知我的 javascript 部分?

回答by Peacemoon

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

我也在 Phonegap Google Group 中问过这个问题,这是 Simon Mac Donald 的回应。它非常适合我:



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:

您可以通过使用插件 API 轻松处理这种情况。它在核心 API 项 Connection 和 Battery 中实现。你需要做的是:

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

1) 在您的插件的 execute() 方法中保存您获得的 callbackId。

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

2) 返回一个 NO_RESULT 插件结果并将保持回调 id 设置为 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:

3)当你异步java方法完成返回另一个插件结果是这样的:

    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.

正如我所说,您可以查看 GitHub 中的代码,了解我们如何将其用于连接和电池。



回答by Vito Gentile

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.

1) 创建一个 JavascriptInterface 并将其关联到您的 WebView。JavascriptInterface 只是一个类,您可以在其中声明一些要从 JS 使用的 Java 方法。

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.

2)在你的AsyncTask中,在onPostExecute()方法结束时,你必须调用该canProceed()方法来通知JSInterface它可以退出waitForProceed()方法。

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:

3) 在您的 Activity 中,您必须将 JSInterface 对象与您的 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:

4)最后,在JS中,你可以调用AsyncTask(我不知道你是怎么调用的,但我猜你使用了像JSInterface这样的东西)和after callwaitForProceed()方法:

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

I hope it solves your problem ;)

我希望它能解决你的问题;)

回答by Maxim Shoustin

Here is a detailed example:

下面是一个详细的例子:

Lets create some interface that should be called when AsyncTaskwill finish the stuff, a.e when onPostExecutecalled.

让我们创建一些应该在AsyncTask完成这些东西时onPostExecute调用的接口,即在调用时调用。

In my case we fetch some JSONArraydata

就我而言,我们获取一些JSONArray数据

MyTaskListenerItf.java

MyTaskListenerItf.java

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


The AsyncTasktemplate of looks like:

AsyncTask模板看起来像:

MyBuildTask.java

我的构建任务.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 CordovaPluginclass should look like:

所以现在我们的CordovaPlugin类应该是这样的:

MyCordovaPlugin.java

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.

希望它会帮助某人。