Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在Xamarin.Android中安全地从不同线程写入GUI_C#_Multithreading_Visual Studio 2010_.net 4.0_Xamarin - Fatal编程技术网

C# 如何在Xamarin.Android中安全地从不同线程写入GUI

C# 如何在Xamarin.Android中安全地从不同线程写入GUI,c#,multithreading,visual-studio-2010,.net-4.0,xamarin,C#,Multithreading,Visual Studio 2010,.net 4.0,Xamarin,我已经下载了Xamarin的试用版,目前正在使用它(在VisualStudio2010中) 我想做的一个测试是看看如何通过BackgroundWorker线程在GUI上更新控件,具体来说,我想看看Mono语法与常规Windows窗体(C#)语法相比有多大的不同 为了验证这一点,我创建了一个Android应用程序(同样是在VS2010中),目标是API级别17(Android 4.2)。应用程序的常规功能将从_DoWork()BackgroundWorker事件处理程序中更改EditText控件的

我已经下载了Xamarin的试用版,目前正在使用它(在VisualStudio2010中)

我想做的一个测试是看看如何通过BackgroundWorker线程在GUI上更新控件,具体来说,我想看看Mono语法与常规Windows窗体(C#)语法相比有多大的不同

为了验证这一点,我创建了一个Android应用程序(同样是在VS2010中),目标是API级别17(Android 4.2)。应用程序的常规功能将从_DoWork()BackgroundWorker事件处理程序中更改EditText控件的文本值

这是密码

//Xamarin.Android app
[Activity(Label = "Cross-thread Test", MainLauncher = true)]
public class Activity1 : Activity
{
    EditText labelDisplay;
    BackgroundWorker bgWorker;
    int counter = 0;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        this.bgWorker = new BackgroundWorker();
        this.bgWorker.WorkerSupportsCancellation = true;
        this.bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);

        Button buttonStart = FindViewById<Button>(Resource.Id.buttonStart);
        buttonStart.Click += new EventHandler(buttonStart_Click);

        Button buttonStop = FindViewById<Button>(Resource.Id.buttonStop);
        buttonStop.Click += new EventHandler(buttonStop_Click);

        labelDisplay = FindViewById<EditText>(Resource.Id.labelDisplay);
        labelDisplay.Text = "Click Start";
    }

    void bgWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        while (true)
        {
            if (this.bgWorker.CancellationPending)
            {
                RunOnUiThread(() => labelDisplay.Text = "Click Start");
                break;
            }
            else
            {
                counter++;

                            // This causes GREF to increase to 2001
                RunOnUiThread(() => labelDisplay.Text = counter.ToString());
            }
        }
    }

    private void buttonStart_Click(object sender, EventArgs e)
    {
        if (this.bgWorker != null && !this.bgWorker.IsBusy)
            this.bgWorker.RunWorkerAsync();
    }

    private void buttonStop_Click(object sender, EventArgs e)
    {
        if (this.bgWorker != null && this.bgWorker.IsBusy)
            this.bgWorker.CancelAsync();
    }
}
Android应用程序将在调试输出显示以下错误时崩溃(我只提供了值得注意的信息)

09-2818:09:39.231 D/dalvikvm(731):GREF增加到1701
09-28 18:09:39.461 D/dalvikvm(731):格雷夫增加到1801
09-28 18:09:40.192 D/dalvikvm(731):格雷夫增加到1901
09-28 18:09:40.271 D/dalvikvm(731):GC_并发释放305K,7%释放6175K/6599K,暂停3ms+5ms
09-28 18:09:40.531 D/dalvikvm(731):格雷夫已增至2001年
09-28 18:09:40.531 W/dalvikvm(731):JNI全局参考表(0x475fd0)转储:
09-28 18:09:40.531 W/dalvikvm(731):最后10个条目(2001年起):
09-28 18:09:40.531 W/dalvikvm(731):2000:0x40fa4e90 java.lang.NoClassDefFoundError
09-28 18:09:40.541 W/dalvikvm(731):1999:0x40fb2e78 mono.java.lang.RunnableImplementor
.
.
.
09-28 18:09:40.581 E/dalvikvm(731):过度的JNI全局引用(2001)//糟糕!
09-28 18:09:40.581 E/dalvikvm(731):VM正在中止
09-28 18:09:40.581 E/mono rt(731):堆栈跟踪:
09-28 18:09:40.581 E/mono rt(731):
09-28 18:09:40.592 E/mono rt(731):在
09-28 18:09:40.592 E/mono rt(731):at(包装器管理为本机)object.wrapper\u native\u 0x408027e9(intptr,intptr)
09-28 18:09:40.592 E/mono rt(731):在Android.Runtime.JNIEnv.NewGlobalRef(intptr)[0x00000]中/Users/builder/data/lanes/monodroid-mlion-monodroid-4.8.2-branch/bdc709d1/source/monodroid/src/mono.Android/src/Runtime/JNIEnv.cs:389
我读到美国

Dalvik的JNI层只支持有限数量的JNI对象 引用在任何给定时间点都有效。当这个限制是 一旦发生,事情就会破裂

模拟器中的GREF(全局引用)限制为2000个引用, 以及约52000份硬件参考资料

你知道当你看到的时候,你开始创造太多的gref了 Android调试日志中的此类消息:

您会在错误日志中注意到,我的代码将GREF增加到2001


根据上面的故障排除说明,我假设
RunOnUiThread()
正在为while循环的每个迭代创建一个JNI对象。如果是这种情况,为什么会发生这种情况?我应该如何从不同的线程安全地写入GUI?

RunOnUiThread
对工作进行排队

更新UI的技术还可以,只是在循环中没有停顿,队列几乎在瞬间命中2000个项目


我打赌在那里放一个短的
线程就可以了。Sleep()

试着在这里写你的UI更新

Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
{
     // code to execute
});

我最初在代码中调用了Sleep(1000),但问题仍然存在。尽管GREF的增长速度慢得多,但最终达到了2000年的上限。问题是关于
Xamarin.Android
而不是
Xamarin.Form
09-28 18:09:39.231 D/dalvikvm(  731): GREF has increased to 1701
09-28 18:09:39.461 D/dalvikvm(  731): GREF has increased to 1801
09-28 18:09:40.192 D/dalvikvm(  731): GREF has increased to 1901
09-28 18:09:40.271 D/dalvikvm(  731): GC_CONCURRENT freed 305K, 7% free 6175K/6599K, paused 3ms+5ms
09-28 18:09:40.531 D/dalvikvm(  731): GREF has increased to 2001
09-28 18:09:40.531 W/dalvikvm(  731): JNI global reference table (0x475fd0) dump:
09-28 18:09:40.531 W/dalvikvm(  731):   Last 10 entries (of 2001):
09-28 18:09:40.531 W/dalvikvm(  731):      2000: 0x40fa4e90 java.lang.NoClassDefFoundError
09-28 18:09:40.541 W/dalvikvm(  731):      1999: 0x40fb2e78 mono.java.lang.RunnableImplementor
.
.
.
09-28 18:09:40.581 E/dalvikvm(  731): Excessive JNI global references (2001) //OOPS!
09-28 18:09:40.581 E/dalvikvm(  731): VM aborting
09-28 18:09:40.581 E/mono-rt (  731): Stacktrace:
09-28 18:09:40.581 E/mono-rt (  731): 
09-28 18:09:40.592 E/mono-rt (  731):   at <unknown> <0xffffffff>
09-28 18:09:40.592 E/mono-rt (  731):   at (wrapper managed-to-native) object.wrapper_native_0x408027e9 (intptr,intptr) <IL 0x00026, 0xffffffff>
09-28 18:09:40.592 E/mono-rt (  731):   at Android.Runtime.JNIEnv.NewGlobalRef (intptr) [0x00000] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.8.2-branch/bdc709d1/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.cs:389
Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
{
     // code to execute
});