xamarin学习笔记A14(安卓AsyncTask和RunOnUiThread)

(每次学习一点xamarin就做个学习笔记和视频来加深记忆巩固知识)

如有不正确的地方,请帮我指正。

简介

    AsyncTask类和Activity.RunOnUiThread()方法都是对Hanlder消息处理的封装。

    在android中 1.只能在子线程进行耗时任务。2.只能在主线程进行UI更新。 所以要使用异步消息处理机制

方法/

说明

作用

Activity.RunOnUiThread(回调方法)

Handler+Message的封装

创建消息并关联回调方法,发送到消息队列。

AsyncTask

Handler+Message+Thread的封装

创建消息和使用线程池子线程,发送消息到队列,最后执行相应的回调方法。

先看Activity.RunOnUiThread()方法

    从android源码中抽出主要部分如下

public class Activity {
    //......省略其它代码......
    //1
    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }
}


public class Handler{
    //......省略其它代码......

    //2
    public final boolean post(Runnable r)
    {
        return  sendMessageDelayed(getPostMessage(r), 0);
    }
    //3
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();//创建一个消息
        m.callback = r; //这里设置了消息关联的回调方法
        return m;
    }
    //4
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    //5
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {return false;}

        return enqueueMessage(queue, msg, uptimeMillis);
    }
    //6
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        return queue.enqueueMessage(msg, uptimeMillis);//将消息发送到消息队列
    }
    //7 在主线程执行(自动被调用)
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);//调用消息对象关联的回调方法
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    //8 在主线程执行(自动被调用)
    private static void handleCallback(Message message) {
        message.callback.run();//调用消息对象关联的回调方法
    }
}

主要看标记的序号,执行runOnUiThread方法时先设用了post方法,post方法则调用的getPostMessage方法来创建了一个Message对象并关联了回调方法,最后通过enqueueMessage将Message对象发送到了消息队列。然后主线程的Looper对象自动从MessageQueue中取出消息并调用消息对象关联的回调方法。

 

    举个例子,我们可以这样使用,贴上部分代码:

private TextView textView;
private string address = "http://www.hao123.com";
public void OnClick(View v)
        {
            switch (v.Id)
            {
                //请求网络数据(记得在AndroidManifest.xml的Applincation节点之上声明网络权限<uses-permission android:name="android.permission.INTERNET"/>)
                case Resource.Id.button1:
                    new Thread(new ThreadStart(
                            () =>
                            {
                                #region 子线程执行请求
                                HttpURLConnection conn = null;
                                try
                                {
                                    URL url = new URL(address);
                                    conn = (HttpURLConnection)url.OpenConnection(); //打开连接
                                    conn.RequestMethod = "GET";
                                    conn.DoInput = true;  //允许接收数据,以后就可以使用conn.InputStream

                                    Stream inStream = conn.InputStream; //实际请求数据
                                    string result;
                                    using (StreamReader reader = new StreamReader(inStream, Encoding.UTF8))
                                    {
                                        result = reader.ReadToEnd();
                                    }

                                    this.RunOnUiThread(
                                            //RunOnUiThread本质是对Handler异步消息处理的封装,
                                            //它内部创建了一个消息对象,并把下面的匿名方法关联到消息对象上,然后发送消息到队列中(子线程中执行)
                                            //最后主线程运行的Looper对象会自动去从MessageQueue中取消息,并执行消息对象关联的方法 (主线程中执行)
                                            () =>
                                            {
                                                Toast.MakeText(this, "请求成功", ToastLength.Short).Show();
                                                textView.Text = result;
                                            } //在主线程更新UI
                                        );                                }
                                catch (System.Exception e)
                                {
                                    Toast.MakeText(this, "请求出错"+e.Message, ToastLength.Long).Show();
                                }
                                finally
                                {
                                    if (conn != null) conn.Disconnect();//关闭连接
                                }
                                #endregion
                            }
                        )).Start();
                    break;           
 }
}

接着看AsyncTask类

   就不抽取android源码了,太多了也不太好怎么抽取。它内部也同样是对Handler消息机制的封装,不需要像上面那样要求自己创建线程,它内部帮我们创建了线程,而且还用了线程池来提高性能。

    打开这个类的定义,可以看到这是个抽像类,主要有五个方法让我们来重写。

//范型参数1是输入参数的类型,参数2是进度值的类型,参数3是任务返回值类型
public abstract class AsyncTask<TParams, TProgress, TResult> : AsyncTask
    {
        public AsyncTask();

	    //启动异步任务
        public AsyncTask<TParams, TProgress, TResult> Execute(params TParams[] @params);

	   //在异步任务开始之前被调用(在主线程)
protected virtual void OnPreExecute();
        
//(在子线程运行具体任务)
protected abstract TResult RunInBackground(params TParams[] @params);

        //进度有变化时被调用(在主线程)
        protected virtual void OnProgressUpdate(params TProgress[] values);

        //异步任务执行完后被调用(在主线程)
protected virtual void OnPostExecute(TResult result);

//任务被取消后调用
protected virtual void OnCancelled();
}

下面就来具体使用这个类,贴上部分代码
//异步任务处理
    public class MyTask : AsyncTask<string, int, string >//参数1是输入参数的类型,参数2是进度值的类型,参数3是任务返回值类型
    {
        public interface IMyTask
        {
            void OnFinish(string result);//定义一个回调方法
        }

        private IMyTask _myTask;
        public void SetLitener(IMyTask listener)//传递一个实现了IMyTask接口的对象来监听任务结果
        {
            _myTask = listener;
        }

        //在异步任务开始之前被调用(在主线程)
        protected override void OnPreExecute()
        {
            Log.Debug("MyTask", "在异步任务开始之前OnPreExecute()被调用");
        }

        //(在子线程运行具体任务)
        //此方法内部会创建子线程Thread,然后执行任务,然后会发送Message到消息队列。
        protected override string RunInBackground(params string[] @params)因为params和C#关键字params同名,所以要加 @ 符号
        {
            Log.Debug("MyTask", "RunInBackground()被调用");
            HttpURLConnection conn = null;
            try
            {
                string address = @params[0];//取出请求地址
                URL url = new URL(address);
                conn = (HttpURLConnection)url.OpenConnection(); //打开连接
                conn.RequestMethod = "GET";
                conn.DoInput = true;  //允许接收数据,以后就可以使用conn.InputStream

                Stream inStream = conn.InputStream; //实际请求数据
                string result;
                using (StreamReader reader = new StreamReader(inStream, Encoding.UTF8))
                {
                    result = reader.ReadToEnd(); 
                }
                return result;
            }
            catch
            {
                return "";
            }
            finally
            {
                if (conn != null) conn.Disconnect();//关闭连接
            }
        }

        //进度有变化时被调用(在主线程)
        //protected override void OnProgressUpdate(params int[] values)
        //{
        //    base.OnProgressUpdate(values);
        //}

        //异步任务执行完后被调用(在主线程)
        protected override void OnPostExecute(string result)
        {
            Log.Debug("MyTask", "异步任务执行完后OnPostExecute()被调用");
            if (_myTask!=null)
            {
                _myTask.OnFinish(result); //执行回调方法
            }
        }

        //任务被取消后调用
        //protected override void OnCancelled()
        //{
        //    base.OnCancelled();
        //}
    }

然后在Activity中调用
public class SecondActivity : AppCompatActivity, IOnClickListener, MyTask.IMyTask
    {
        private TextView textView;
        private string address = "http://www.hao123.com";
        public void OnClick(View v)
        {
            switch (v.Id)
            {
                case Resource.Id.button1:
                    MyTask myTask = new MyTask();
                    myTask.SetLitener(this);
                    myTask.Execute(address); //启动异步任务
                    break;
            }
        }

        public void OnFinish(string result)
        {
            textView.Text = result; //显示请求结果
        }
}

最后的结果如下图



代码和视频在我上传的CSDN资源中http://download.csdn.net/download/junshangshui/10048297

猜你喜欢

转载自blog.csdn.net/junshangshui/article/details/78413542