45 votes

Android utilise V8 sans WebView

Je fais du sport de l'exécution de javascript à partir de Java. Rhino fonctionne très bien pour cela sur le bureau, mais doit se replier à la (lente) en mode interprété sur Android (en raison de dalvik étant pas en mesure d'exécuter le bytecode Java le Rhino JIT compile).

Android a intégré dans le moteur javascript V8, qui est accessible en interne via JNI et devrait donner de bien meilleures performances que les Rhinocéros; toutefois, la seule façon que je peux trouver pour l'accès c'est par l'intermédiaire d'une WebView.

Malheureusement, WebView nécessite un Contexte, et des plantages avec des entrées en phase nationale avec une valeur null contexte, donc je suis incapable de même instancier un mannequin WebView simplement exécuter le code et de retourner le résultat. La nature de mon exercice n'a pas vraiment me permettre de fournir un Contexte pour la WebView, donc je suis en espérant que peut-être il y a quelque chose que je suis surplombant.

Plusieurs de ces V8Threads s'exécuter en parallèle, de sorte qu'il n'est pas vraiment possible (pour autant que je suis au courant) pour ajouter une WebView pour ma mise en page et de le cacher, car je ne crois pas un seul WebView peut exécuter des fonctions dans plusieurs threads.

private class V8Thread extends Thread
{
    private WebView webView;
    private String source;

    private double pi;
    private int i, j;

    public V8Thread(int i, int j)
    {
        pi = 0.0;
        this.i = i;
        this.j = j;

        source = "";

        try {
            InputStreamReader isReader = new InputStreamReader(assetManager.open("pi.js"));
            int blah = isReader.read();
            while (blah != -1)
            {
                source += (char)blah;
                blah = isReader.read();
            }

            webView = new WebView(null);
            webView.loadData(source, "text/html", "utf-8");
            webView.getSettings().setJavaScriptEnabled(true);
            webView.addJavascriptInterface(this, "V8Thread");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public double getResult()
    {
        return pi;
    }

    @Override
    public void run() 
    {
        webView.loadUrl("javascript:Androidpicalc("+i+","+j+")");
    }
}

Idéalement, il doit y avoir une prise en charge pour appeler V8 directement, ou au moins d'exécuter du javascript sans avoir besoin d'une réelle WebView, comme il semble que plutôt maladroit et alambiqué méthode à exécuter du code javascript.

Mise à JOUR

J'ai réarrangé mon code un peu, quoique invisible ici, c'est que maintenant, je suis à l'instanciation de la V8Threads sur le AsyncTasks de onPreExecute() tout en gardant tout le reste dans doInBackground(). Le code source est lu plus tôt dans le programme, il n'est donc pas de manière redondante re-lire pour chaque thread.

Parce que maintenant le V8Thread est instancié sur le Thread de l'INTERFACE utilisateur, je peux la passer à la vue actuelle du Contexte (je suis à l'aide de fragments, donc je ne peux pas juste passer "ce"), de sorte qu'il ne se bloque plus.

private class V8Thread extends Thread
{
    private WebView webView;

    private double pi;
    private int i, j;

    public V8Thread(int i, int j)
    {
        pi = 0.0;
        this.i = i;
        this.j = j;

        source = "";

        webView = new WebView(v.getContext());
    }

    @SuppressWarnings("unused")
    public void setResult(String in)
    {
        Log.d("Pi",in);
    }

    public double getResult()
    {
        return pi;
    }

    @Override
    public void run()
    {
        webView.getSettings().setJavaScriptEnabled(true);
        webView.addJavascriptInterface(this, "V8Thread");
        webView.loadData(source, "text/html", "utf-8");
        //webView.loadUrl("javascript:Androidpicalc("+i+","+j+")");
        webView.loadUrl("javascript:test()");
        Log.d("V8Thread","Here");
    }
}

Cependant, lors de l'exécution, logcat crache un par le fil de l'erreur "ne Peut pas obtenir la viewWidth après la première mise en page" et le code javascript ne s'exécute jamais. Je sais que le fil des feux complètement, parce que le "Ici" journal d'un message envoyé. Voici le test() de la fonction dans le code js.

function test()
{
V8Thread.setResult("blah");
}

Travail correctement, "blah" doit afficher jusqu'à quatre fois dans le logcat, mais il ne se présente jamais. Pourrait être mon code source est lu de manière incorrecte, mais j'en doute.

Scanner scan = new Scanner(assetManager.open("pi.js"));
while (scan.hasNextLine()) source += scan.nextLine();

La seule autre chose que je peux imaginer que, en raison de ces erreurs, la webView jamais réellement se déplace à l'exécution du javascript.

Je vais aussi ajouter que pi.js ne contient que javascript, HTML non que ce soit. Cependant, même quand je l'envelopper dans juste assez HTML pour la qualifie comme une page web, toujours pas de chance.

10voto

soulseekah Points 3527

Vous pouvez créer un nouveau V8 Contexte via son API et de l'utiliser pour exécuter votre code JavaScript, regarder dans les https://android.googlesource.com/platform/external/v8 include répertoire qui contient deux fichiers d'en-tête C++. Lien contre la libwebcore.donc (compilé à partir de https://android.googlesource.com/platform/external/webkit) de la bibliothèque via le NDK, rien de spécial.

v8::Persistent<v8::Context> context = v8::Persistent<v8::Context>::New(v8::Context::New());
context->Enter();

Reportez-vous à https://developers.google.com/v8/get_started qui va travailler sur Android. Juste assurez-vous que l'appareil est livré avec V8 (certains vieux appareils navire avec JSC [JavaScript de Base]).

1voto

nicholas.hauschild Points 21796

Pouvez-vous obtenir une prise de l' Context qui est votre Application? Il ya un couple de façons de le faire.

  1. Appel getApplication() de votre Activity (Application est un enfant de Context)
  2. Appel getApplicationContent() à partir d'un Context (Context de chance d'être votre Activity)

Mise à JOUR

Selon cette Android documentation, votre tenue Javascript code sera exécuté dans un processus distinct de toute façon, donc il ne devrait pas être nécessaire de le configurer selon ses propres Thread.

À partir du lien:

Remarque: L'objet qui est lié à votre JavaScript s'exécute dans un autre thread et pas dans le thread dans lequel il a été construit. (L '"objet" d'être mentionnée est la JavascriptInterface classe)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X