2012-08-29 5 views
4

J'ai créé une activité assez simple Mono pour le projet Android:Comment appeler Mono pour Android dans l'application Android?

[Activity(Label = "AndroidApplication1", MainLauncher = true, Icon = "@drawable/icon")] 
public class Activity1 : Activity 
{ 
    private string value = "intitial"; 

    [Export] 
    public string GetString() 
    { 
     return value; 
    } 

    [Export] 
    public void SetString(string newValue) 
    { 
     value = newValue; 
    } 
} 

L'activité ne doit servir de preuve de concept, d'où sa simplicité. Maintenant, j'aimerais pouvoir appeler la méthode GetString() à partir de l'application Android «normale» basée sur Java.

En Xamarin's docs, j'ai lu à propos de Java to Managed interop, qui semble être exactement ce que je recherche. Si je comprends bien, lorsque l'application Mono pour Android compile, elle génère des classes Java appelées Android Callable Wrappers (ACW). Je devrais alors être en mesure d'appeler des méthodes sur ces ACW à partir de l'application Android basée sur Java. La question est: comment puis-je faire référence à Mono compilé pour l'application Android (le fichier apk) à partir de l'application Android basée sur Java?

C'est où je suis maintenant bloqué et n'a pas pu trouver des exemples concrets. Il y a des questions similaires ici sur SO (this one et this one) et quelques blogposts, mais ils se résument simplement à "utiliser des ACW". Mais comment exactement? Peut-être qu'il me manque quelque chose d'évident ici, n'étant aucun type Android.

Ce que j'ai essayé est de charger dynamiquement le fichier dex que je tirai de mon Mono pour Android apk. Je l'ai simplement mis sur la carte de stockage, puis j'ai essayé d'utiliser DexClassLoader de l'application Android basée sur Java pour le charger (j'ai suivi ce blog post). La classe ACW a été trouvé, mais quand j'essayé de créer son exemple, j'obtenu l'erreur suivante:

No implementation found for native Lmno/android/Runtime;.register (Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)

Je suppose que je dois inclure une certaine façon Mono pour l'exécution Android à l'application Java, mais je aucune idée comment.

EDIT: Ceci est le code que je suis en train de charger le dex avec:

DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(), 
    optimizedDexOutputPath.getAbsolutePath(), 
    null, 
    getClassLoader()); 

try { 
    Class<?> classActivity1 = cl.loadClass("androidapplication1.Activity1"); 

    // the following line throws the exception 
    Object a = classActivity1.newInstance(); 

    Method getStringMethod = classActivity1.getMethod("GetString"); 
    Object result = getStringMethod.invoke(angel); 

    result = null; 
} catch (Exception e) { 
    e.printStackTrace(); 
} 

EDIT2: Je lis maintenant here qu'il devrait être possible de démarrer directement les activités écrit en Mono pour Android à partir de Java. Il n'est toujours pas clair pour moi comment référencer le Mono pour Android à partir de Java et Google ne donne aucun résultat pertinent. Vraiment perplexe maintenant.

Répondre

4

Si je comprends bien ce que vous essayez de faire, ce n'est pas vraiment possible. Comme l'indique le message d'erreur que vous avez reçu, une activité au sein d'une application Mono pour Android repose sur le moteur d'exécution Mono afin de fonctionner correctement. L'encapsulable n'est pas utile seul dans ce cas, car il s'agit juste d'une classe wrapper Java fine qui appelle l'exécution Mono. Vous pouvez voir vous-même les enveloppes appelables générées si vous regardez dans le dossier obj/Debug/android/src après avoir construit votre projet. Par exemple:

package androidapplication9; 


public class Activity1 
    extends android.app.Activity 
    implements 
     mono.android.IGCUserPeer 
{ 
    static final String __md_methods; 
    static { 
     __md_methods = 
      "n_onCreate:(Landroid/os/Bundle;)V:GetOnCreate_Landroid_os_Bundle_Handler\n" + 
      ""; 
     mono.android.Runtime.register ("AndroidApplication9.Activity1, AndroidApplication9, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", Activity1.class, __md_methods); 
    } 


    public Activity1() 
    { 
     super(); 
     if (getClass() == Activity1.class) 
      mono.android.TypeManager.Activate ("AndroidApplication9.Activity1, AndroidApplication9, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "", this, new java.lang.Object[] { }); 
    } 


    public void onCreate (android.os.Bundle p0) 
    { 
     n_onCreate (p0); 
    } 

    private native void n_onCreate (android.os.Bundle p0); 

    java.util.ArrayList refList; 
    public void monodroidAddReference (java.lang.Object obj) 
    { 
     if (refList == null) 
      refList = new java.util.ArrayList(); 
     refList.add (obj); 
    } 

    public void monodroidClearReferences() 
    { 
     if (refList != null) 
      refList.clear(); 
    } 
} 

Cela dit, en raison de la façon dont fonctionne Android, vous pourriez avoir une application Java démarrer une activité qui est définie dans un Mono pour l'application Android de la même manière que vous démarrer une activité Java externe . Cela dépend des deux applications installées, bien sûr, mais il en résulterait que l'application Mono pour Android et Mono Runtime démarrent réellement pour exécuter cette activité.

Modifier

Mise à jour pour répondre aux questions que vous avez posées dans votre commentaire. Le ExportAttribute vous donne simplement un peu plus de contrôle sur la façon dont l'ACW est générée, ce qui vous permet de spécifier qu'une méthode ou un champ particulier doit être présent dans l'ACW et quel nom il devrait avoir. Cela peut être utile lorsque vous voulez utiliser des choses comme un attribut android: onClick dans une mise en page, par exemple, où par défaut l'ACW ne contient pas la méthode que vous voulez référencer.

Vous ne pouvez pas obtenir beaucoup d'utilisation d'un ACW en dehors du contexte d'une application Mono pour Android, car le moteur d'exécution Mono ne serait pas présent. Le code écrit en C# est exécuté au dessus du runtime Mono, et non traduit en Java dans les coulisses pendant la compilation ou quelque chose comme ça. Au moment de l'exécution, il y a deux temps d'exécution côte à côte, Dalvik (runtime d'Android) et Mono, et les wrappers appelables sont là pour permettre aux deux de communiquer d'avant en arrière. Pour cette raison, même une bibliothèque de classes Mono pour Android dépendrait toujours du moteur d'exécution Mono, donc vous ne pouvez pas l'utiliser indépendamment de cette exécution.

Ce diagramme montre ce que l'architecture ressemble, et comment les runtimes se rapportent les uns aux autres:

Mono for Android architecture

Hope this helps clarifier les choses!

+0

Merci beaucoup pour votre réponse, enfin quelque chose à travailler avec! Qu'est-ce que vous dites a beaucoup de sens, mais quel est le but de ces documents Xamarin liés dans ma question? Quand est-ce que j'utiliserais l'ACW et l'attribut 'Export'? Et peut-être le plus important, est-ce qu'il y a une façon de faire de l'application Java "parler" à Mono pour Android sans avoir à installer deux applications séparées, par exemple avoir une bibliothèque Mono pour Android et simplement le référencer depuis l'application Java? Je serais vraiment reconnaissant si vous pouviez clarifier cela un peu pour moi. –