Mono for Androidでjava/util/concurrent/CountDownLatchを使えるようにしてみた

モーダルダイアログを実現したくて見つけたJavaのコードサンプルで使っているCountDownLatch。
Mono for Android v1.9ではまだ実装されていなかったので自前で実装してみた。

using System;
using Android;
using Android.Runtime;

namespace Utilty
{
    public class CountDownLatch : Java.Lang.Object, IJavaObject
    {
        internal static IntPtr class_ref = JNIEnv.FindClass ("java/util/concurrent/CountDownLatch");
        private static Delegate cb_await;
        private static Delegate cb_coutnDown;
        private static IntPtr id_ctor;
        private static IntPtr id_await;
        private static IntPtr id_coutnDown;

        [Register(".ctro","(I)V", "")]
        public CountDownLatch (int count) : base(IntPtr.Zero)
        {
            if (base.Handle == IntPtr.Zero) {
                if (base.GetType () != typeof(CountDownLatch)) {
                    IntPtr kls = JNIEnv.FindClass (base.GetType ());
                    IntPtr jmethod = JNIEnv.GetMethodID (kls, "<init>", "(I)V");
                    JValue[] parms = new JValue[] {new JValue(count)};
                    base.SetHandle (JNIEnv.NewObject (kls, jmethod, parms), true);
                    JNIEnv.DeleteGlobalRef (kls);
                } else {
                    if (id_ctor == IntPtr.Zero) {
                        id_ctor = JNIEnv.GetMethodID (class_ref, "<init>", "(I)V");
                    }
                    JValue[] parms = new JValue[] {new JValue(count)};
                    base.SetHandle (JNIEnv.NewObject (class_ref, id_ctor, parms), true);
                }
            }
        }

        public CountDownLatch (IntPtr doNotUse) : base (doNotUse)
        {
        }

        [Register("await", "()V", "GetAwaitHandler")]
        public void Await ()
        {
            if (id_await == IntPtr.Zero) {
                id_await = JNIEnv.GetMethodID (class_ref, "await", "()V");
            }
            if (base.GetType () == this.ThresholdType) {
                JNIEnv.CallVoidMethod (base.Handle, id_await);
            } else {
                JNIEnv.CallNonvirtualVoidMethod (base.Handle, this.ThresholdClass, id_await);
            }
        }

        private static Delegate GetAwaitHandler ()
        {
            if (cb_await == null)
                cb_await = JNINativeWrapper.CreateDelegate (new Action<IntPtr, IntPtr> (CountDownLatch.n_Await));
            return cb_await;

        }

        private static void n_Await (IntPtr jnienv, IntPtr native__this)
        {
            Java.Lang.Object.GetObject<CountDownLatch> (native__this, false).Await ();
        }

        [Register("countDown", "()V", "GetCountDownHandler")]
        public void CountDown ()
        {
            if (id_coutnDown == IntPtr.Zero) {
                id_coutnDown = JNIEnv.GetMethodID (class_ref, "countDown", "()V");
            }
            if (base.GetType () == this.ThresholdType) {
                JNIEnv.CallVoidMethod (base.Handle, id_coutnDown);
            } else {
                JNIEnv.CallNonvirtualVoidMethod (base.Handle, this.ThresholdClass, id_coutnDown);
            }
        }

        private static Delegate GetCountDownHandler ()
        {
            if (cb_coutnDown == null)
                cb_coutnDown = JNINativeWrapper.CreateDelegate (new Action<IntPtr, IntPtr> (CountDownLatch.n_CountDown));
            return cb_coutnDown;

        }

        private static void n_CountDown (IntPtr jnienv, IntPtr native__this)
        {
            Java.Lang.Object.GetObject<CountDownLatch> (native__this, false).CountDown ();
        }

        protected override IntPtr ThresholdClass {
            get {
                return class_ref;
            }
        }

        protected override Type ThresholdType {
            get {
                return typeof(CountDownLatch);
            }
        }
    }
}
  • namespaceをJava.Util.Concurrentとするとビルドしてパッケージ化するときにエラーがおきるので断念。
  • class定義に[Register("java/util/concurrent/CountDownLatch")]をつけるとこれまたビルドしてパッケージ化するときにエラーがおきるのでつけなかった。

ご利用はくれぐれも自己責任で。