摘要:每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainThread),主线程负责处理和ui相关的事件,因此主线程通常又叫UI线程。而由于Android采用UI单线程模型,所以只能在主线程中对UI元素进行操作。如果在非UI线程直接对UI进行了操作,则会报错:CalledFromWrongThreadException:only the original thread that created a view hierarchy can touch its views。

Android为我们提供了消息循环的机制,我们可以利用这个机制来实现线程间的通信。那么,我们就可以在非UI线程发送消息到UI线程,最终让Ui线程来进行ui的操作。

对于运算量较大的操作和IO操作,我们需要新开线程来处理这些繁重的工作,以免阻塞ui线程。在发送http等网络请求时,会经常使用!

下面承接前几篇文章中对天气情况(Weather)的一些详细说明,继续完善,实现在Android客户端的一个天气预报功能的开发:

WeatherActivity主程序代码:

package com.dm.weather;import android.annotation.TargetApi;import android.app.Activity;import android.os.Build;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v4.widget.SwipeRefreshLayout;import android.util.Log;import android.view.View;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;import com.dm.CommonData.RetData;import com.dm.CommonData.Weather;import com.google.gson.Gson;import org.apache.http.HttpResponse;import org.apache.http.NameValuePair;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.message.BasicNameValuePair;import org.apache.http.protocol.HTTP;import org.apache.http.util.EntityUtils;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.List;/** * Thread + Handler 实例 */public class WeatherActivity extends Activity {    private SwipeRefreshLayout swipeRefreshLayout;    private TextView refreshTv;    private static final String LOG_TAG = "WeatherActivity";    private static final int MSG_SUCCESS = 1; // 成功标识    private static final int MSG_FAILURE = 0; // 失败标识    private static final String REQUEST_URL = "http://apistore.baidu.com/microservice/weather?cityname=郑州";    private static final String REQUEST_BASE_URL = "http://apistore.baidu.com/microservice/weather";    private ImageView weatherIcon;    private TextView weatherDateTv;    private TextView weatherTimeTv;    private TextView weatherStatusTv;    private TextView windDirectionTv;    private TextView windSpeedTv;    private TextView weatherCurrentTmpTv;    private TextView weatherLowTmpTv;    private TextView weatherHighTmpTv;    private TextView sunRiseTimeTv;    private TextView sunSetTimeTv;    private Thread mThread = null;    private Handler weatherHander = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case MSG_SUCCESS:                    // 使用Gson对Json数据的解析,请翻看之前的文章:[Java中使用Gson解析json数据](http://blog.csdn.net/mduanfire/article/details/44703059%20+ "Java中使用Gson解析json数据")                    Gson weatherGson = new Gson();                    Log.i(LOG_TAG, msg.obj.toString());                    Weather weather = weatherGson.fromJson(msg.obj.toString(), Weather.class);                    RetData retData = weather.getRetData();                    weatherDateTv.setText(retData.getDate() + " ");                    weatherTimeTv.setText(retData.getTime());                    windDirectionTv.setText(retData.getWD());                    windSpeedTv.setText(retData.getWS());                    weatherStatusTv.setText(retData.getWeather());                    weatherCurrentTmpTv.setText(retData.getTemp());                    weatherLowTmpTv.setText(retData.getL_tmp());                    weatherHighTmpTv.setText(retData.getH_tmp());                    sunRiseTimeTv.setText(retData.getSunrise());                    sunSetTimeTv.setText(retData.getSunset());                    switch (retData.getWeather()) {                        case "晴":                            weatherIcon.setImageResource(R.drawable.qing);                            break;                        case "多云":                            weatherIcon.setImageResource(R.drawable.duoyun);                            break;                        case "阴":                            weatherIcon.setImageResource(R.drawable.yin);                            break;                        case "阵雨":                            weatherIcon.setImageResource(R.drawable.zhengyu);                            break;                        case "雷阵雨":                            weatherIcon.setImageResource(R.drawable.leizhengyu);                            break;                        case "雷阵雨伴有冰雹":                            weatherIcon.setImageResource(R.drawable.leizhengyubanyoubingbao);                            break;                        case "雨夹雪":                            weatherIcon.setImageResource(R.drawable.yujiaxue);                            break;                        case "小雨":                            weatherIcon.setImageResource(R.drawable.xiaoyu);                            break;                        case "中雨":                            weatherIcon.setImageResource(R.drawable.zhongyu);                            break;                        case "大雨":                            weatherIcon.setImageResource(R.drawable.dayu);                            break;                        case "暴雨":                            weatherIcon.setImageResource(R.drawable.baoyu);                            break;                        case "大暴雨":                            weatherIcon.setImageResource(R.drawable.dabaoyu);                            break;                        case "特大暴雨":                            weatherIcon.setImageResource(R.drawable.tedabaoyu);                            break;                        case "阵雪":                            weatherIcon.setImageResource(R.drawable.zhengxue);                            break;                        case "小雪":                            weatherIcon.setImageResource(R.drawable.xiaoxue);                            break;                        case "中雪":                            weatherIcon.setImageResource(R.drawable.zhongxue);                            break;                        case "大雪":                            weatherIcon.setImageResource(R.drawable.daxue);                            break;                        case "暴雪":                            weatherIcon.setImageResource(R.drawable.baoxue);                            break;                        case "雾":                            weatherIcon.setImageResource(R.drawable.wu);                            break;                        case "冻雨":                            weatherIcon.setImageResource(R.drawable.dongyu);                            break;                        case "沙尘暴":                            weatherIcon.setImageResource(R.drawable.shachenbao);                            break;                        case "浮尘":                            weatherIcon.setImageResource(R.drawable.fuchen);                            break;                        case "扬沙":                            weatherIcon.setImageResource(R.drawable.yangsha);                            break;                        case "强沙尘暴":                            weatherIcon.setImageResource(R.drawable.qiangshachenbao);                            break;                        case "霾":                            weatherIcon.setImageResource(R.drawable.mai);                            break;                        case "小到中雨":                            weatherIcon.setImageResource(R.drawable.zhongyu);                            break;                        case "中到大雨":                            weatherIcon.setImageResource(R.drawable.dayu);                            break;                        case "大到暴雨":                            weatherIcon.setImageResource(R.drawable.baoyu);                            break;                        case "暴雨到大暴雨":                            weatherIcon.setImageResource(R.drawable.dabaoyu);                            break;                        case "大暴雨到特大暴雨":                            weatherIcon.setImageResource(R.drawable.tedabaoyu);                            break;                        case "小到中雪":                            weatherIcon.setImageResource(R.drawable.zhongxue);                            break;                        case "中到大雪":                            weatherIcon.setImageResource(R.drawable.daxue);                            break;                        case "大到暴雪":                            weatherIcon.setImageResource(R.drawable.baoxue);                            break;                        default:                            weatherIcon.setImageResource(R.drawable.qita);                            break;                    }                    refreshTv.setText("刷新成功");                    swipeRefreshLayout.setRefreshing(false);                    break;                case MSG_FAILURE:                    Toast.makeText(getApplicationContext(), "FAILURE, 网络繁忙!", Toast.LENGTH_LONG).show();                    break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.weather_activity);        initTitleView();        initWeatherView();        initBaseView();    }    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)    private void initBaseView() {        refreshTv = (TextView) findViewById(R.id.refresh_tv);        swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);        swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light);        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {            @Override            public void onRefresh() {                refreshTv.setText("正在刷新");                // 开启新的线程,请求网络数据,返回json数据                mThread = new Thread(runnable);                mThread.start();            }        });    }    Runnable runnable = new Runnable() {        @Override        public void run() {            // Http get//            String requestUrl = REQUEST_URL;////            HttpGet httpGet = new HttpGet(requestUrl);////            try {//                HttpResponse httpResponse = new DefaultHttpClient().execute(httpGet);////                if (httpResponse.getStatusLine().getStatusCode() == 200) {//                    String requestResult = EntityUtils.toString(httpResponse.getEntity());////                    Log.i(LOG_TAG, "requestResult = " + requestResult);//                    // 使用定义的weatherHander的obtainMessage()方法将成功标志和请求成功得到的json字符串传递过去,之后在Hander中进行解析weatherHander.obtainMessage(MSG_SUCCESS, requestResult).sendToTarget();//                } else {//                    Log.i(LOG_TAG, "requestError = " + httpResponse.getStatusLine());//                    Toast.makeText(getApplicationContext(), "Response Error!!" + httpResponse.getStatusLine(), Toast.LENGTH_SHORT).show();//                }//            } catch (IOException e) {//                Log.i(LOG_TAG, e.getMessage());//                e.printStackTrace();//            }            // Http post            String url = REQUEST_URL;            HttpPost httpPost = new HttpPost(url);            try {                HttpResponse httpResponse = new DefaultHttpClient().execute(httpPost);                if (httpResponse.getStatusLine().getStatusCode() == 200) {                    String requestResult = EntityUtils.toString(httpResponse.getEntity());                    Log.i(LOG_TAG, "requestResult = " + requestResult);                    weatherHander.obtainMessage(MSG_SUCCESS, requestResult).sendToTarget();                } else {                    Log.i(LOG_TAG, "requestError = " + httpResponse.getStatusLine());                    Toast.makeText(getApplicationContext(), "Response Error!!" + httpResponse.getStatusLine(), Toast.LENGTH_SHORT).show();                }            } catch (IOException e) {                Log.i(LOG_TAG, "+++++: " + e.getMessage());                e.printStackTrace();            }        }    };    private void initTitleView() {        ImageView titleBackImv = (ImageView) findViewById(R.id.titleBack_iv);        TextView titleTextTv = (TextView) findViewById(R.id.titleText_tv);        titleTextTv.setText("天气状况");        titleBackImv.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                finish();            }        });    }    private void initWeatherView() {        weatherIcon = (ImageView) findViewById(R.id.weather_icon);        weatherDateTv = (TextView) findViewById(R.id.weather_date);        weatherTimeTv = (TextView) findViewById(R.id.weather_time);        windDirectionTv = (TextView) findViewById(R.id.weather_windstatus);        windSpeedTv = (TextView) findViewById(R.id.weather_windspeed);        weatherStatusTv = (TextView) findViewById(R.id.weather_status);        weatherCurrentTmpTv = (TextView) findViewById(R.id.weather_curent_tmp);        weatherLowTmpTv = (TextView) findViewById(R.id.weather_low_tmp);        weatherHighTmpTv = (TextView) findViewById(R.id.weather_high_tmp);        sunRiseTimeTv = (TextView) findViewById(R.id.weather_sunrise_time);        sunSetTimeTv = (TextView) findViewById(R.id.weather_sunset_time);    }}

weather_activity界面布局代码

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@color/seashell">    <include        android:id="@+id/weather_include"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        layout="@layout/title_layout" />    <android.support.v4.widget.SwipeRefreshLayout        android:id="@+id/swipe_container"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_alignTop="@+id/weather_icon">        <TextView            android:id="@+id/refresh_tv"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="Refresh?"            android:padding="5dp"            android:gravity="center_horizontal" />    </android.support.v4.widget.SwipeRefreshLayout>    <ImageView        android:id="@+id/weather_icon"        android:layout_width="120dp"        android:layout_height="120dp"        android:background="@color/powderblue"        android:padding="10dp"        android:layout_marginTop="15dp"        android:layout_marginLeft="15dp"        android:layout_below="@+id/weather_include"        android:src="@drawable/qita" />    <TextView        android:id="@+id/weather_city"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="郑州"        android:textSize="24sp"        android:textColor="@color/black"        android:layout_alignParentRight="true"        android:layout_marginTop="15dp"        android:layout_marginRight="15dp"        android:layout_below="@+id/weather_include"        android:layout_alignRight="@+id/weather_icon" />    <TextView        android:id="@+id/weather_status"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="~~~~~~"        android:textSize="22sp"        android:textColor="@color/black"        android:layout_alignBottom="@+id/weather_icon"        android:layout_centerHorizontal="true" />    <TextView        android:id="@+id/weather_windspeed"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="~~~ "        android:textSize="18sp"        android:textColor="@color/black"        android:layout_below="@+id/weather_windstatus"        android:layout_alignRight="@+id/weather_city"        android:layout_alignEnd="@+id/weather_city" />    <TextView        android:id="@+id/weather_windstatus"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="~~~~~~"        android:textSize="18sp"        android:textColor="@color/black"        android:layout_above="@+id/weather_status"        android:layout_alignRight="@+id/weather_windspeed"        android:layout_alignEnd="@+id/weather_windspeed" />    <TextView        android:id="@+id/weather_date"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="~~~~~~ "        android:textSize="18sp"        android:textColor="@color/black"        android:layout_toLeftOf="@+id/weather_time"        android:layout_below="@+id/weather_city" />    <TextView        android:id="@+id/weather_time"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="~~~ "        android:textSize="18sp"        android:textColor="@color/black"        android:layout_below="@+id/weather_city"        android:layout_alignLeft="@+id/weather_city"        android:layout_alignStart="@+id/weather_city" />    <TextView        android:id="@+id/weather_curent_tmp_hint"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="当前气温: "        android:textSize="20sp"        android:textColor="@color/black"        android:layout_marginTop="15dp"        android:layout_below="@+id/weather_icon"        android:layout_alignLeft="@+id/weather_icon"        android:layout_alignStart="@+id/weather_icon" />    <TextView        android:id="@+id/weather_curent_tmp"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="~~~"        android:textSize="20sp"        android:textColor="@color/black"        android:layout_alignTop="@+id/weather_curent_tmp_hint"        android:layout_toRightOf="@+id/weather_curent_tmp_hint"        android:layout_toEndOf="@+id/weather_curent_tmp_hint" />    <TextView        android:id="@+id/weather_low_tmp_hint"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="最低气温: "        android:textSize="20sp"        android:textColor="@color/black"        android:layout_below="@+id/weather_curent_tmp_hint"        android:layout_toLeftOf="@+id/weather_curent_tmp"        android:layout_toStartOf="@+id/weather_curent_tmp" />    <TextView        android:id="@+id/weather_low_tmp"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="~~~"        android:textSize="20sp"        android:textColor="@color/black"        android:layout_alignTop="@+id/weather_low_tmp_hint"        android:layout_toRightOf="@+id/weather_low_tmp_hint"        android:layout_toEndOf="@+id/weather_low_tmp_hint" />    <TextView        android:id="@+id/weather_high_tmp_hint"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="最高气温: "        android:textSize="20sp"        android:textColor="@color/black"        android:layout_below="@+id/weather_low_tmp_hint"        android:layout_toLeftOf="@+id/weather_high_tmp"        android:layout_toStartOf="@+id/weather_high_tmp" />    <TextView        android:id="@+id/weather_high_tmp"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="~~~"        android:textSize="20sp"        android:textColor="@color/black"        android:layout_below="@+id/weather_low_tmp"        android:layout_toRightOf="@+id/weather_low_tmp_hint"        android:layout_toEndOf="@+id/weather_low_tmp_hint" />    <TextView        android:id="@+id/weather_sunrise_time_hint"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="日出时间: "        android:textSize="20sp"        android:textColor="@color/black"        android:layout_alignTop="@+id/weather_low_tmp"        android:layout_alignRight="@+id/weather_date"        android:layout_alignEnd="@+id/weather_date" />    <TextView        android:id="@+id/weather_sunrise_time"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="~~~"        android:textSize="20sp"        android:textColor="@color/black"        android:layout_alignTop="@+id/weather_sunrise_time_hint"        android:layout_alignLeft="@+id/weather_time"        android:layout_alignStart="@+id/weather_time" />    <TextView        android:id="@+id/weather_sunset_time_hint"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="日落时间: "        android:textSize="20sp"        android:textColor="@color/black"        android:layout_below="@+id/weather_sunrise_time_hint"        android:layout_alignLeft="@+id/weather_sunrise_time_hint"        android:layout_alignStart="@+id/weather_sunrise_time_hint" />    <TextView        android:id="@+id/weather_sunset_time"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="~~~"        android:textSize="20sp"        android:textColor="@color/black"        android:layout_below="@+id/weather_sunrise_time"        android:layout_alignLeft="@+id/weather_sunrise_time"        android:layout_alignStart="@+id/weather_sunrise_time" /></RelativeLayout>

{ 布局代码中使用到的SwipeRefreshLayout Google官方下拉刷新控件将在下篇文章中介绍 }

在AndroidManifest.xml中添加获取网络的权限

    <uses-permission android:name="android.permission.INTERNET"></uses-permission><!--不要忘记设置网络访问权限-->    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

最终效果预览:


总结:

非UI线程发送消息到UI线程分为两个步骤

  1. 发送消息到UI线程的消息队列:
    通过使用Handler的
Message obtainMessage(int what,Object object)

构造一个Message对象,这个对象存储了是否成功标识what和json字符串,然后通过message.sendToTarget()方法把这条message放到消息队列中去。

  1. 处理发送到UI线程的消息:
    ui线程中,我们覆盖了handler的
public void handleMessage (Message msg)   

这个方法是处理分发给ui线程的消息,判断msg.what的值可以知道mThread是否成功获取数据,如果json字符串数据成功获取,那么可以通过msg.obj获取到这个对象,之后开始解析。

最后在使用布局中相应的TextView将数据填充,实现更新。

更多相关文章

  1. Android开发实践:Android交叉编译工具链的使用
  2. Android面试题(六)--重要
  3. [原]零基础学习SDL开发之在Android使用SDL2.0显示BMP叠加图
  4. Android异步加载图像小结(含线程池,缓存方法)[转]
  5. mybatisplus的坑 insert标签insert into select无参数问题的解决
  6. 箭头函数的基础使用
  7. python起点网月票榜字体反爬案例
  8. NPM 和webpack 的基础使用
  9. Python list sort方法的具体使用

随机推荐

  1. 有关架构创建的课程推荐
  2. 关于Xml序列化的10篇课程推荐
  3. 有关XML入门的文章推荐10篇
  4. 关于App.config的9篇文章推荐
  5. 关于处理指令的10篇文章推荐
  6. 有关XHTML的相关推荐10篇
  7. 关于原理及性能的详细介绍
  8. 总结关于百度新闻注意点
  9. 关于添加链接的详细介绍
  10. 有关WSD的详细介绍