Xamarin.Android 使用线程无法更改页面文本问题

前言:

  刚接触Xamarin.Android不到一个月时间,却被他折磨的不要不要的,随着开发会出现莫名其妙的问题,网上类似Xamarin.Android的文档也不多,于是本片文章是按照Java开发Android的思路写过来的,于是记录下来,希望大家碰到这个问题少走些弯路。

问题描述:

  在执行线程内想给TextView赋值发生错误。 

错误提示:

  Android.Util.AndroidRuntimeException: Only the original thread that created a view hierarchy can touch its views.

问题原因:

  原来Android中相关的view和控件不是线程安全的,我们必须单独做处理。这里借此引出Handler的使用。

Handler的机制:

  handler机制,在android中提供了一种异步回调机制Handler,使用它,我们可以在完成一个很长时间的任务后做出相应的通知。

Handler的作用:

  当我们需要在子线程处理耗时的操作(例如访问网络,数据库的操作),而当耗时的操作完成后,需要更新UI,这就需要使用Handler来处理,因为子线程不能做更新UI的操作。Handler能帮我们很容易的把任务(在子线程处理)切换回它所在的线程。简单理解,Handler就是解决线程和线程之间的通信的。

原有错误代码:

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Threading;

namespace App1
{
    [Activity(Label = "App1", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    { 
        TextView tv1;
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle); 
            SetContentView(Resource.Layout.Main); 
            Button button = FindViewById<Button>(Resource.Id.MyButton);

            button.Click += delegate { TestThread(); };

            tv1 = FindViewById<TextView>(Resource.Id.textView1);
        }
        private void TestThread()
        {
            Boolean loopFlag = true;
            Thread th = new Thread(new ThreadStart(delegate
            {
                int i = 0;
                while (loopFlag && i < 5)
                {
                    if (i == 3)
                    {
                        tv1.Text = "测试赋值";
                        loopFlag = false;
                    }
                    i++;
                }
            }));
            th.Start(); 
        }
    }
}

修改完成后的代码:

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Threading;

namespace App1
{
    [Activity(Label = "App1", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    { 
        TextView tv1;
        Handler hander;
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle); 
            SetContentView(Resource.Layout.Main); 
            Button button = FindViewById<Button>(Resource.Id.MyButton);

            hander = new UIHand(this);
            button.Click += delegate { TestThread(); };

            tv1 = FindViewById<TextView>(Resource.Id.textView1);
        }

        //模拟一个线程,在线程中修改TextView的文本
        private void TestThread()
        {
            Boolean loopFlag = true;
            Thread th = new Thread(new ThreadStart(delegate
            {
                int i = 0;
                while (loopFlag && i < 5)
                {
                    if (i == 3)
                    {
                        Message ms = new Message();
                        ms.Obj = "测试赋值" + "@" + "123";
                        hander.SendMessage(ms);     //调用HandleMessage方法
                        loopFlag = false;
                    }
                    i++;
                }
            }));
            th.Start(); 
        }

        //创建一个类,继承于Handler
        private class UIHand : Handler
        {
            MainActivity ma;
            public UIHand(MainActivity _ma)
            {
                ma = _ma;
            }

            //重写HandleMessage方法
            public override void HandleMessage(Message msg)
            {
                try
                {
                    String result = msg.Obj + "";       //相当于ToString();
                    String[] str = result.Split('@');
                    ma.tv1.Text = str[0];
                }
                catch (Exception)
                {

                }
            }
        }
    } 
}

这样问题就完美的解决了。

 

posted @ 2018-03-26 18:49  没事儿写个bug  阅读(431)  评论(0编辑  收藏  举报