天气Widget

StarkHuang 2010-03-29

天气Widget : 负责显示 当天 未来几天 天气信息

还是一步步从头说吧:

[代码 步骤]

1. 定义widget所需界面: weatherlayout.xml  包括以下几个View

* ImageView 用于显示:天气图片
* TextView 用于描述天气信息 比如:温度 湿度 紫外线指数 紫外线强度
* ImageView 相当于Button 负责查询明天天气情况
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ImageView
    android:id="@+id/image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
<TextView
    android:id="@+id/text"
    android:textSize="12px"
    android:textStyle="bold|italic"
    android:textColor="#008800"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
<ImageView
    android:id="@+id/next"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
</LinearLayout>

2. 定义 weathersetting.xml 用于定义widget相关各属性

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    //widget最小宽度
    android:minWidth="246dip"

    //widget最小高度
    android:minHeight="22dip"
 
    //刷新率 因为该widget要求从网络获取信息 导致运行时间较长 而该单位偏大 故使其为0 至于数据刷新 通过别的方法 具体见下文
    android:updatePeriodMillis="0"
   
     //widget使用的布局
    android:initialLayout="@layout/weatherlayout" />

3.  定义一些后续用到的字串

public class WeatherColumn {
	
	//HK 地区天气查询 相关地址
	public final static String WeatherHttpHead = "http://202.140.96.134:8080/FS-RSS/";
	public final static String WeatherLocal = WeatherHttpHead + "ftpfile/local_weather.xml";
	public final static String WeatherForcast = WeatherHttpHead + "ftpfile/forecast_weather.xml";
	
	//broadcast definition
	public final static String BroadcastWidget = "BroadcastWidget";
	public final static String BroadcastMoniterNext = "BroadcastMoniterNext";
	
	//天气信息数据 比如:哪里 时间 温度 湿度 紫外线指数 紫外线强度 或 所有信息一起
	public final static String WeatherLocation = "WeatherLocation";
	public final static String WeatherTime = "WeatherTime";
	public final static String WeatherTemporary = "WeatherTemporary";
	public final static String WeatherHumidity = "WeatherHumidity";
	public final static String WeatherUvIndext = "WeatherUvIndext";
	public final static String WeatherUvIntensity = "WeatherUvIntensity";
	public final static String WeatherIco = "WeatherIco";
	
	//用于标记查询哪天天气
	public final static String DayInfo_Widget = "DayInfo_Widget";
	public final static String DayInfo_Activity = "DayInfo_Activity";
	public final static String DayNow = "DayNow";
	public final static String DayNext = "DayNext";
}

4. 定义2 Service 作用:

* WidgetUpdate 用于执行AppWidgetProvider 天气信息显示 及其他事情
* WeatherMoniter 用于执行与天气查询有关事情

5. WidgetUpdate 定义如下:

//负责具体数据查询 显示
    public static class WidgetUpdate extends Service {
    	Context context;
    	
    	RemoteViews rView;
    	
    	public void onStart(Intent intent, int startId) {
    		
    		rView = new RemoteViews(getPackageName(),
                    R.layout.weatherlayout);
    		
    		WidgetInfoListenerHelper helper = new WidgetInfoListenerHelper(this);
    		helper.registerAction(WeatherColumn.BroadcastWidget);
    		
    		setViewBroadcastClickListener(rView,R.id.next,WeatherColumn.BroadcastMoniterNext);
    		
    		rView.setTextViewText(R.id.text, "Hi,WeatherWidget!");
    		rView.setImageViewResource(R.id.next,R.drawable.next);
    		
			//setViewActivityClickListener(rView,	R.id.image,
			//				new Intent(this, WeatherActivity.class));
			
    		notifyViewChanged();
    	}
    	
    	public void notifyViewChanged(){
    		// Push update for this widget to the home screen
            ComponentName batteryWidget = new ComponentName(this, WeatherWidget.class);
            AppWidgetManager manager = AppWidgetManager.getInstance(this);
            manager.updateAppWidget(batteryWidget, rView);
    	}
    	
    	//refer- startActivity(Intent)
    	public void setViewActivityClickListener(RemoteViews remte,int id,Intent i){
    		
    		PendingIntent pi = PendingIntent.getActivity(this,1,i,0);
    		
    		remte.setOnClickPendingIntent(id, pi);
    	}
    	
    	//refer- sendBroadcast(Intent)
    	public void setViewBroadcastClickListener(RemoteViews remte,int id,String filter){
    		Intent i = new Intent(filter);
    		
    		PendingIntent pi = PendingIntent.getBroadcast(this,1,i,0);
    		
    		remte.setOnClickPendingIntent(id, pi);
    		
    	}
    		
    	//显示 天气数据
    	public void displayText(String s){
    		rView.setTextViewText(R.id.text, s);
    		
    		notifyViewChanged();
    	}
    	
    	//显示 天气图片
    	public void displayImage(Bitmap bp){
    		rView.setImageViewBitmap(R.id.image,bp);
    		
    		notifyViewChanged();
    	}
    	
    	//下载 目标地址 网络图片
    	public Bitmap queryImageByURI(String iu){
    	try{
    		
			URL imgURL = new URL(iu);
			URLConnection conn = imgURL.openConnection();
			
			conn.connect();
			InputStream is = conn.getInputStream();
			
			BufferedInputStream bis = new BufferedInputStream(is);
			
			Bitmap bm = BitmapFactory.decodeStream(bis);
			
			bis.close();
			is.close();
			return bm;
		}catch(Exception e){
          return null;
		} 
    }

6.  在WidgetUpdate 里面定义BroadcastReceiver 用于接收天气数据 并显示之

//负责接收天气数据
    	public class WidgetInfoListenerHelper extends BroadcastReceiver {
    		Context context;
    		
    		WidgetInfoListenerHelper listener;
    		
    		//construct 
    		public WidgetInfoListenerHelper(Context c){
    			context = c;
    			
    			//to instance it
    			listener = this;
    		}
    		
    		public void registerAction(String action){
    			IntentFilter filter = new IntentFilter();
    			filter.addAction(action);
    			
    			context.registerReceiver(listener,filter);
    		}
    		
    		@Override
    		public void onReceive(Context arg0, Intent arg1) {
    			// TODO Auto-generated method stub
    			Bundle b = arg1.getExtras();
    			
    			if(b.containsKey(WeatherColumn.DayInfo_Widget)){
    				String string = b.getString(WeatherColumn.DayInfo_Widget);
    				
    				//区分该Bundle是 今天/明天
    				if(string.equals(WeatherColumn.DayNow)){
    				//Log.d("TAG","[Widget: retutn Weather - now]");
    				}
    				else {
    				//Log.d("TAG","[Widget: retutn Weather - forcast]");
    				}
    				
    			}
    			
    			String weather_info = "";
    			
    			/* 忽略一些查询到的信息
    			if(b.containsKey(WeatherColumn.WeatherLocation)){
    				weather_info  += b.getString(WeatherColumn.WeatherLocation);
    			}
    			if(b.containsKey(WeatherColumn.WeatherTime)){
    				weather_info += b.getString(WeatherColumn.WeatherTime);
    			}
    			*/
    			
    			if(b.containsKey(WeatherColumn.WeatherTemporary)){
    				weather_info +="温度:"+ b.getString(WeatherColumn.WeatherTemporary);
    				displayText(weather_info);
    			}
    			if(b.containsKey(WeatherColumn.WeatherHumidity)){
    				weather_info += "\n" + "湿度:"+b.getString(WeatherColumn.WeatherHumidity);
    				displayText(weather_info);
    			}

    			if(b.containsKey(WeatherColumn.WeatherIco)){
    				Bitmap bmp = queryImageByURI(WeatherColumn.WeatherHttpHead + b.getString(WeatherColumn.WeatherIco));
    				displayImage(bmp);
    			}
    			
    		}
    		
    	}

7. WeatherMoniter 定义2 Bundle 一个用于存放当天天气数据 一个用于存放明天数据

8. 定义2个用于查询天气的函数 因为这2个*.xml的节点不同 所以需要分别定义

* 查询今天

public void queryWeatherLocal(String s){
		try {
			URL url = new URL(s);
			URLConnection connection = url.openConnection();
		    
		    HttpURLConnection httpConnection = (HttpURLConnection)connection;
		    InputStream in = httpConnection.getInputStream(); 
		    int responseCode = httpConnection.getResponseCode();
		    
		    if (responseCode == HttpURLConnection.HTTP_OK) {
			      DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
			      DocumentBuilder db = dbfactory.newDocumentBuilder();

			      //解析目标
			      Document dom = db.parse(in);
			      
			      //得到其所有子Element
			      Element docEle = dom.getDocumentElement();
			        
			      //得到指定的列
			      NodeList nl = docEle.getElementsByTagName("channel");
			      
			      if (nl != null && nl.getLength() > 0) {
			        for (int i = 0 ; i < nl.getLength(); i++) {
			        	
			        	//得到某行数据
			        	Element entry = (Element)nl.item(i);
			          
			        	Element info = (Element)entry.getElementsByTagName("item").item(0);
			        	
			        	//从该行中取出目标  方法:键值 Key-Value
			        	Element eTitle = (Element)info.getElementsByTagName("title").item(0);
			        	Element eDay = (Element)info.getElementsByTagName("pubDate").item(0);
			        	Element eDescription = (Element)info.getElementsByTagName("description").item(0);
			        	
			        	//取出其内容
			        	String scity = eTitle.getFirstChild().getNodeValue();
			        	String stime = eDay.getFirstChild().getNodeValue();
			        	String sdescription = eDescription.getFirstChild().getNodeValue();
			        	
			        	//遍历目标 以指定字符分割 然后按顺序放入String[]
			        	String[] string = sdescription.split("<br>");
			        	
			        	String temporary = string[0];
			        	String temp = temporary.split("=")[1];
			        	
			        	String humidity = string[1];
			        	String hum = humidity.split("=")[1];
			        	
			        	String uIndex = string[2];
			        	String uv_Index = uIndex.split("=")[1];
			        	
			        	String uIntensity = string[3];
			        	String uv_Intensity = uIntensity.split("=")[1];
			        	
			        	
			        	//String uIntensity = string[3];
			        	String icoName = string[5];
			        	
			        	String address = icoName.split(" ")[1];
			        	
			        	String address1 = address.split("=")[1];
			        	
			        	//去除两边的"\""
			        	String address2 = address1.replaceAll("\"", "");
			        	
			        	//Log.d("TAG","location:"+scity);
			        	//Log.d("TAG","time:"+stime);
			        	//Log.d("TAG","temporary:"+temp);
			        	//Log.d("TAG","humidity:"+hum);
			        	//Log.d("TAG","uv index:"+uv_Index);
			        	//Log.d("TAG","uv intension:"+uv_Intensity);
			        	//image.setImageBitmap(queryImageByURI(ico_preface+address2));
			        	
			        	//Bundle bundle = new Bundle();
			        	wLocal.clear();
			        	
			        	wLocal.putString(WeatherColumn.WeatherLocation, scity);
			        	wLocal.putString(WeatherColumn.WeatherTime, stime);
			        	wLocal.putString(WeatherColumn.WeatherTemporary, temp);
			        	wLocal.putString(WeatherColumn.WeatherHumidity, hum);
			        	wLocal.putString(WeatherColumn.WeatherUvIndext, uv_Index);
			        	wLocal.putString(WeatherColumn.WeatherUvIntensity, uv_Intensity);
			        	wLocal.putString(WeatherColumn.WeatherIco, address2);
			        	
			        	//标记此Bundle为 local_weather 数据
			        	wLocal.putString(WeatherColumn.DayInfo_Widget, WeatherColumn.DayNow);
			        }
			      }
			    }
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (ParserConfigurationException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}catch (SAXException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
        
    }

如何调用:

String local = WeatherColumn.WeatherLocal;

queryWeatherLocal(local);

* 查询明天 因为目标会提供后4天天气信息 所以只选择第一天 并显示之

public void queryWeatherForcast(String s){
		try {
			URL url = new URL(s);
			URLConnection connection = url.openConnection();
		    
		    HttpURLConnection httpConnection = (HttpURLConnection)connection;
		    InputStream in = httpConnection.getInputStream(); 
		    int responseCode = httpConnection.getResponseCode();
		    
		    if (responseCode == HttpURLConnection.HTTP_OK) {
			      DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
			      DocumentBuilder db = dbfactory.newDocumentBuilder();

			      //解析目标
			      Document dom = db.parse(in);
			      
			      /* 步骤:
			       * 1. 得到解析后目标:Document dom
			       * 2. 在Document基础上做getDocumentElement()以得到最基本处理单位:Element e
			       * 3. 再在Element基础上做getElementsByTagName() 
			       */
			      
			      Element docEle = dom.getDocumentElement();
			        
			      //得到指定的列
			      NodeList item = (NodeList)docEle.getElementsByTagName("item");
			      
			      if (item != null && item.getLength() > 0) {
			        for (int i = 0 ; i < item.getLength(); i++) {
			        	
			        	Element entry = (Element)item.item(0);
			        	
			        	//从该行中取出目标  方法:键值 Key-Value
			        	
			        	//取出 <title>....</title>
			        	Element eTitle = (Element)entry.getElementsByTagName("title").item(0);
			        	String title = eTitle.getFirstChild().getNodeValue();
			        	
			        	//取出 <pubDate>....</pubDate>
			        	Element eData = (Element)entry.getElementsByTagName("title").item(0);
			        	String data = eTitle.getFirstChild().getNodeValue();
			        	
			        	//取出 <description>....</description>
			        	Element eDescription = (Element)entry.getElementsByTagName("description").item(0);
			        	String description = eDescription.getFirstChild().getNodeValue();
			        	
			        	//一次记录所有天气数据 以"\n"代替<br>
			        	//String all = description.replace("<br>", "\n");
			        	//wForcast.putString(WeatherColumn.WeatherAll, all);
			        	
			        	String[] string = description.split("<br>");
			        	
			        	String lTemp = string[0].split("=")[1];
			        	String hTemp = string[1].split("=")[1];
			        	
			        	String lHumidity = string[2].split("=")[1];
			        	String hHumidity = string[3].split("=")[1];
			        	
			        	
			        	String icoName = string[5];
			        	String address = icoName.split(" ")[1];
			        	String address1 = address.split("=")[1];
			        	//去除两边的"\""
			        	String ico = address1.replaceAll("\"", "");
			        	
			        	wForcast.clear();
			        	
			        	wForcast.putString(WeatherColumn.WeatherTemporary, lTemp+"-"+hTemp);
			        	wForcast.putString(WeatherColumn.WeatherHumidity, lHumidity+"-"+hHumidity);
			        	wForcast.putString(WeatherColumn.WeatherIco, ico);
			        	
			        	
			        }
			      }
			    }
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (ParserConfigurationException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}catch (SAXException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
        
    }

如何调用:

String forcast = WeatherColumn.WeatherForcast;

queryWeatherForcast(forcast);

9. 何时查询 查询哪天

1. WeatherMoniter 启动以后 会查询当天天气 并把查询结果返回给WeatherWidget 由其负责显示

2. 收到WeatherWidget的命令后 查询明天天气 并返回结果

10. 最上面提到的数据刷新问题 我的办法:开辟Thread 计时 时间到就重新查询数据 并返回结果给WeatherWidget 与WeatherMoniter 一同启动之

//创建Thread 用于计时
	public void startLoop(){
		Thread loop = new Thread(new TimeCounter());
    	loop.start();
	}
	
	public class TimeCounter implements Runnable {
		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(true){
				loop(100000000);
				Log.d("TAG","[WeatherMoniter: Time to refresh!]");
				
				//刷新天气数据
				requeryWeatherInfo();
				sendWeatherInfo(WeatherColumn.BroadcastWidget,wLocal);
				
			}
		}
		
		public void loop(long i){
			long l = i;
		
			while(l>0){
				l--;
			}
		}
	}

11. emulator 运行截图 对了 别忘记权限

* 当天:

天气Widget

* 明天:

天气Widget

结束!

相关推荐

kktode / 0评论 2013-09-09
pipimob / 0评论 2011-10-18