Android Phonegap:AsyncTask 完成时通知 javascript

发布于 2024-12-09 11:51:07 字数 178 浏览 0 评论 0原文

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

活雷疯 2024-12-16 11:51:08

这就是我解决像你这样的问题的方法。

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) 在你的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)在您的 Activity 中,您必须将 JSInterface 对象关联到您的 WebView:

WebView mWebView;

...

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

4)最后,在 JS 中,您可以调用 AsyncTask (我不知道您如何调用它,但我猜您使用类似 JSInterface 之类的东西),然后调用 waitForProceed() 方法:

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

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

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

花海 2024-12-16 11:51:08

这是一个详细的示例:

让我们创建一些接口,当 AsyncTask 完成任务时,即当 onPostExecute 调用时,应调用该接口。

在我的例子中,我们获取一些 JSONArray 数据

MyTaskListenerItf.java

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

AsyncTask 模板如下所示:

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

       // ..
     }
}

所以现在我们的 CordovaPlugin 类应该如下所示:

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

就这样。

希望它会对某人有所帮助。

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.

深府石板幽径 2024-12-16 11:51:07

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


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

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

2) 返回 NO_RESULT 插件结果并将 keepcallback id 设置为 true。

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

3)当你的异步java方法完成时,返回另一个插件结果,如下所示:

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

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


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.


~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文