3

わかりました、この一般的な質問がここで何度も聞かれていることは理解していますが、私にとって意味のある答えをまだ見つけていません. 私が見たほとんどすべての回答は、「ねえ、これをあなたのメソッドに投げ込むだけで大丈夫です」のような宣伝文句を言っているだけですが、完全な例は見ていません。

これが私が受け取るエラーです:

[mono] android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

つまり、簡単に言えば、Web サービスから情報を取得し、Web サービスの結果をいくつかの TextView にスローするアクティビティがあります。をどこでどのように使用する必要があるかを誰かが教えてくれませんRunOnUiThread()か? コードは次のとおりです。


using Android.App;
using Android.OS;
using System;
using System.Web;
using System.Net;
using System.IO;
using Newtonsoft.Json;
using Android.Widget;

namespace DispatchIntranet
{
    [Activity (Label = "@string/Summary")]          
    public class SummaryActivity : Activity
    {
        private static readonly Log LOG = new Log(typeof(SummaryActivity));
        private TextView summaryTotalRegularLabel;
        private TextView summaryTotalRollover;
        private TextView summaryScheduledLabel;
        private TextView summaryRemainingRegular;
        private string url;

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

            // SET THE LAYOUT TO BE THE SUMMARY LAYOUT
            SetContentView(Resource.Layout.Summary);

            // INITIALIZE CLASS MEMBERS
            init();

            if (LOG.isInfoEnabled())
            {
                LOG.info("Making call to rest endpoint . . .");

                if (LOG.isDebugEnabled())
                {
                    LOG.debug("url: " + this.url);
                }
            }

            try
            {
                // BUILD REQUEST FROM URL
                HttpWebRequest httpReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(this.url));

                // SET METHOD TO 'GET'
                httpReq.Method = GetString(Resource.String.web_service_method_get);

                // ASK FOR JSON RESPONSE
                httpReq.Accept = GetString(Resource.String.web_service_method_accept);

                // INVOKE ASYNCHRONOUS WEB SERVICE
                httpReq.BeginGetResponse((ar) => {
                    HttpWebRequest request = (HttpWebRequest)ar.AsyncState;

                    using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse (ar))
                    {
                        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                        {
                            // PUT RESPONSE INTO STRING
                            string content = reader.ReadToEnd();

                            // CONVERT STRING TO DYNAMIC JSON OBJECT
                            var json = JsonConvert.DeserializeObject<dynamic>(content);

                            if (LOG.isDebugEnabled())
                            {
                                LOG.debug("content: " + content);
                                LOG.debug("json: " + json);

                                LOG.debug("TOTAL_REGULAR_PTO_HOURS: " + json.d[0].TOTAL_REGULAR_PTO_HOURS);
                            }

                            // ** THIS IS WHAT WILL NOT WORK **
                            this.summaryTotalRegularLabel.Text = json.d[0].TOTAL_REGULAR_PTO_HOURS;
                            this.summaryTotalRollover.Text = json.d[0].TOTAL_ROLLOVER_PTO_HOURS;
                            this.summaryScheduledLabel.Text = json.d[0].TOTAL_USED_PTO_HOURS;
                            this.summaryRemainingRegular.Text = json.d[0].TOTAL_REMAINING_PTO_HOURS;
                        }
                    }
                }, httpReq);
            }
            catch (Exception e)
            {
                LOG.error("An exception occurred while attempting to call REST web service!", e);
            }
        }

        private void init()
        {
            // GET GUID FROM PREVIOUS INTENT AND DETERMINE CURRENT YEAR
            string guid = Intent.GetStringExtra("guid");
            int year = DateTime.Now.Year;

            // BUILD URL
            this.url = GetString(Resource.String.web_service_url)
                + GetString(Resource.String.ws_get_pto_summary)
                + "?" + "guid='" + HttpUtility.UrlEncode(guid) + "'"
                + "&" + "year=" + HttpUtility.UrlEncode(year.ToString());

            // GET THE SUMMARY LABELS
            this.summaryTotalRegularLabel = FindViewById<TextView>(Resource.Id.SummaryTotalRegular);
            this.summaryTotalRollover = FindViewById<TextView>(Resource.Id.summaryTotalRollover);
            this.summaryScheduledLabel = FindViewById<TextView>(Resource.Id.summaryScheduledLabel);
            this.summaryRemainingRegular = FindViewById<TextView>(Resource.Id.SummaryRemainingRegular);
        }
    }
}
4

1 に答える 1

3

Web サービス呼び出しを行うと、HttpWebRequest は操作を実行するための新しいスレッドを作成します。これは、ユーザー インターフェイスがロックしたり、フレームをスキップしたりしないようにするために行われます。Web サービスの呼び出しが完了したら、UI スレッドに戻って、そのスレッドに存在する UI コンポーネントを更新する必要があります。いくつかの異なる方法でそれを行うことができます。

まず、次のように無名関数呼び出しでコードをラップできます。

RunOnUiThread(()=>{
    this.summaryTotalRegularLabel.Text = json.d[0].TOTAL_REGULAR_PTO_HOURS;
    this.summaryTotalRollover.Text = json.d[0].TOTAL_ROLLOVER_PTO_HOURS;
    this.summaryScheduledLabel.Text = json.d[0].TOTAL_USED_PTO_HOURS;
    this.summaryRemainingRegular.Text = json.d[0].TOTAL_REMAINING_PTO_HOURS;
});

または、RunOnUiThread を介して関数を呼び出すこともできます (jsonPayload はクラスのフィールドです)。

jsonPayload = json;
RunOnUiThread(UpdateTextViews);

...


void UpdateTextViews()
{
    this.summaryTotalRegularLabel.Text = jsonPayload.d[0].TOTAL_REGULAR_PTO_HOURS;
    this.summaryTotalRollover.Text = jsonPayload.d[0].TOTAL_ROLLOVER_PTO_HOURS;
    this.summaryScheduledLabel.Text = jsonPayload.d[0].TOTAL_USED_PTO_HOURS;
    this.summaryRemainingRegular.Text = jsonPayload.d[0].TOTAL_REMAINING_PTO_HOURS;

}
于 2013-08-22T22:14:23.260 に答える