日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

安卓作品:河北空气质量客户端

發布時間:2023/12/29 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 安卓作品:河北空气质量客户端 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文:http://blog.csdn.net/icyfox_bupt/article/details/18953581#comments

本文將與你一起從零開始,做一個河北省空氣質量自動發布系統的客戶端,文章面向零基礎的、只看過一點安卓教程的同學,對于比較基礎的內容,也會用紅字的鏈接標出,大家可以點開看詳細的介紹。

? ? ? ? 其實做這個,完全是因為老爸的原因,河北的空氣質量太差了,所以他決定天天根據空氣質量來決定散步不散步。總是上這個網站過于復雜,于是我就有了做一個客戶端的想法。下面分幾步介紹關于信息獲取異步獲取網絡數據數據分析界面設計程序邏輯等內容,下面介紹一個完整的程序是如何做出來的。

? ? ? ? 首先需要找到程序的數據源,找到從網上獲得數據接口的網址。

? ? ? ??其次,要把數據從網上的格式,轉換成我們可以使用的格式。

? ? ? ??接下來進行布局的設計,最后把數據填充到布局里,整個程序就完成了。

? ? ? ??下面是這個系統的網站,和我做的客戶端:



1、數據獲取

想做這個軟件我們先要有數據源,數據是河北省環境監測中心給出的,我們現在要找到它的接口。 打開網址:?http://121.28.49.85:8080/?我們可以看到這是一個flash做的頁面,而且有明顯的加載過程,說明瀏覽器獲取過數據。我們使用HttpAnalyze或者Smsniff來查看瀏覽器發送出去的數據包,當然最方便的是使用Chrome的功能。 打開Chrome --> F12 --> 選擇NetWork標簽 --> 打開上面的網絡地址,下面會出現很多條請求的數據,我們按Size排序后找最大的,就是我們需要的數據。如下圖:

發送的請求的地址

得到的回應
如上圖所示:打開網頁后瀏覽器發送了若干條數據,其中有一條遠大于其它數據的包,大小為59.75k,我們可以認為這就是數據的來源了,而我們看到它指向了網址?http://121.28.49.85:8080/datas/hour/130000.xml。在回復中,發現編碼是UTF-8的編碼。?打開這個網址,我們可以看到如下圖所示的XML數據:

? ? ? ??下面我們就以上面的數據為基礎,做一個客戶端。

2、異步信息獲取

2.1 新建一個Android項目

打開一個配置好ADT(Android Developer Tools)的Eclipse(如果沒有配置好點這個教程),選擇File --> New --> Android Application Project,在Application Name里給程序起一個名字比如HebeiAir,然后在最小需求SDK為API14(低一點其實也不影響),其它保持默認,確定。 建立好以后我們的程序至少會有下面這些文件:

2.2 異步獲取網絡數據

在第一章里,我們找到了獲取數據的網址,在這里,我們要把這個網址的數據抓下來供我們使用。在src包里建立一個新的Class,名字定為Util,在里面定義一個新的靜態方法:HttpGet,這個方法可以模擬瀏覽器的訪問,我們輸入參數是網址,這個函數返回得到的網頁源代碼:
[java]?view plaincopy
  • public?static?String?HttpGet(String?url)?throws?ClientProtocolException,?IOException?{??
  • ????//新建一個默認的連接??
  • ????DefaultHttpClient?client?=?new?DefaultHttpClient();??
  • ????//新建一個Get方法??
  • ????HttpGet?get?=?new?HttpGet(url);??
  • ????//得到網絡的回應??
  • ????HttpResponse?response?=?client.execute(get);??
  • ????//獲得的網頁源代碼(xml)??
  • ????String?content?=?null;??
  • ??
  • ????//如果服務器響應的是OK的話!??
  • ????if?(response.getStatusLine().getStatusCode()?==?200)?{??
  • ????????//以下是把網絡數據分段讀取下來的過程??
  • ????????InputStream?in?=?response.getEntity().getContent();??
  • ????????byte[]?data?=?new?byte[1024];??
  • ????????int?length?=?0;??
  • ????????ByteArrayOutputStream?bout?=?new?ByteArrayOutputStream();??
  • ????????while?((length?=?in.read(data))?!=?-1)?{??
  • ????????????bout.write(data,?0,?length);??
  • ????????}??
  • ????????//最后把字節流轉為字符串?轉換的編碼為utf-8.??
  • ????????content?=?new?String(bout.toByteArray(),?"utf-8");??
  • ????}??
  • ????//返回得到的字符串?也就是網頁源代碼??
  • ????return?content;??
  • }??

  • ? ? ? ??在上面的Chrome信息窗口中看到,返回值是utf-8編碼的,所以在這里我們使用了utf-8編碼,如果這里我們使用"gbk"或者"gb-2312"就會出現亂碼,每個網站的編碼都不相同,具體情況要具體分析。? ? ? ??
    要注意的是,在我們的程序里并不能直接使用這個函數,因為Android 4.0中,主線程不能進行網絡操作,所以我們需要開啟一個新的線程。在Android中,有一個成熟的類:AsyncTask(異步任務),可以完成這項工作(Thread + Handler也是一種方法,由于我們的工作比較簡單,暫時不提及它們)。
    ? ? ? ??接下來我們嘗試把XML源代碼顯示出來。 在MainActivity類中新建一個類GetSource,這個類繼承AsyncTask,用來獲取網頁上的數據;得到數據后使用Logcat(可以理解為Android上的控制臺)打印出來: [java]?view plaincopy
  • class?GetSource?extends?AsyncTask<String,?Void,?String>{??
  • ??????
  • ????//此函數用來處理后臺的事物??
  • ????@Override??
  • ????protected?String?doInBackground(String...?params)?{??
  • ????????try?{??
  • ????????????//這里調用了我們剛才寫的下載函數??
  • ????????????return?Util.HttpGet("http://121.28.49.85:8080/datas/hour/130000.xml");??
  • ????????}?catch?(IOException?e)?{}??
  • ????????return?null;??
  • ????}??
  • ??????
  • ????//后臺事物完成后,此函數用來更改界面的內容??
  • ????@Override??
  • ????protected?void?onPostExecute(String?result)?{??
  • ????????//讓Log輸出運行時的記錄??
  • ????????Log.i("test",result);??
  • ????}??
  • ??????
  • }??

  • ? ? ? ??最后在OnCreate函數的最后一行加上下面一句,再添加網絡權限,然后我們來看看效果吧! [java]?view plaincopy
  • new?GetSource().execute();??

  • 3、界面設計

    我們的目標是把軟件設計成文章開始時的那個樣式,這樣我們就要簡單地修改一下activity_main.xml: ·在上方放置一個TextView,背景為淺綠色,文字顏色為白色; ·下方是一個GridView,其中每個格子的顏色根據空氣質量來變化,格子中上方顯示城市名,下方顯示當前的AQI。 ·同時在整個界面上還要顯示一個轉圈的進度條ProgressBar,加載的時候顯示這個進度條 代碼如下: [html]?view plaincopy
  • <RelativeLayout?xmlns:android="http://schemas.android.com/apk/res/android"??
  • ????xmlns:tools="http://schemas.android.com/tools"??
  • ????android:layout_width="match_parent"??
  • ????android:layout_height="match_parent"??
  • ????tools:context=".MainActivity"?>??
  • ??
  • ????????<LinearLayout??
  • ????????????android:id="@+id/ll"??
  • ????????????android:layout_width="match_parent"??
  • ????????????android:layout_height="wrap_content"??
  • ????????????android:visibility="gone"??
  • ????????????android:orientation="vertical"?>??
  • ??
  • ????????????<TextView??
  • ????????????????android:id="@+id/tv_time"??
  • ????????????????android:layout_width="fill_parent"??
  • ????????????????android:layout_height="wrap_content"??
  • ????????????????android:layout_margin="5dp"??
  • ????????????????android:background="#7a7"??
  • ????????????????android:padding="5dp"??
  • ????????????????android:textColor="#eee"??
  • ????????????????android:textSize="20sp"??
  • ????????????????android:textStyle="bold"?/>??
  • ??
  • ????????????<GridView??
  • ????????????????android:id="@+id/gv"??
  • ????????????????android:layout_width="match_parent"??
  • ????????????????android:layout_height="fill_parent"??
  • ????????????????android:layout_margin="5dp"??
  • ????????????????android:horizontalSpacing="3dp"??
  • ????????????????android:verticalSpacing="3dp"??
  • ????????????????android:numColumns="3"?>??
  • ????????????</GridView>??
  • ????????</LinearLayout>??
  • ??
  • ????????<ProgressBar??
  • ????????????android:id="@+id/pb1"??
  • ????????????android:layout_width="wrap_content"??
  • ????????????android:layout_height="wrap_content"??
  • ????????????android:layout_centerHorizontal="true"??
  • ????????????android:visibility="visible"??
  • ????????????android:layout_centerVertical="true"?/>??
  • ??
  • </RelativeLayout>??

  • ? ? ? ??GridView?是一種網格樣式布局,在上面的代碼里我設置的每行格子個數為3個,還設置了格子之間的間距。每個格子中的布局需要另一個文件來控制: gv.xml: [html]?view plaincopy
  • <?xml?version="1.0"?encoding="utf-8"?>??
  • <LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"??
  • ????android:id="@+id/bg"??
  • ????android:layout_width="match_parent"??
  • ????android:layout_height="wrap_content"??
  • ????android:padding="8dp"??
  • ????android:orientation="vertical"?>??
  • ??
  • ????<TextView??
  • ????????android:id="@+id/tv_city"??
  • ????????android:layout_width="wrap_content"??
  • ????????android:layout_height="wrap_content"??
  • ????????android:text="石家莊"??
  • ????????android:textColor="#4bd"??
  • ????????android:textSize="20sp"??
  • ????????android:textStyle="bold"?/>??
  • ??
  • ????<TextView??
  • ????????android:id="@+id/tv_aqi"??
  • ????????android:layout_width="wrap_content"??
  • ????????android:layout_height="wrap_content"??
  • ????????android:text="223"??
  • ????????android:textColor="#4bd"??
  • ????????android:textSize="18sp"??
  • ????????android:textStyle="bold"?/>??
  • ??
  • </LinearLayout>??

  • 4、數據分析

    4.1 解析XML數據

    網上獲得的XML數據需要轉換成我們可以使用的結構化數據,這就使用了基于DOM的XML解析器。更改GetSource中的OnPostExecute中的代碼為:
    [java]?view plaincopy
  • @Override??
  • protected?void?onPostExecute(String?result)?{??
  • ????//建立一個解析器??
  • ????DocumentBuilderFactory?factory?=?DocumentBuilderFactory.newInstance();??
  • ????DocumentBuilder?builder;??
  • ????try?{??
  • ????????builder?=?factory.newDocumentBuilder();??
  • ????????InputStream?is?=?new?ByteArrayInputStream(result.getBytes());??
  • ????????Document?document?=?builder.parse(is);??
  • ????????Element?element?=?document.getDocumentElement();??
  • ????????//獲得所有的Citys節點數據??
  • ????????NodeList?cityList?=?element.getElementsByTagName("Citys");??
  • ??????????
  • ????????//獲得mapstitle數據,并分解為兩部分??
  • ????????NodeList?title?=?element.getElementsByTagName("MapsTitle");??
  • ????????String?text1?=?title.item(0).getTextContent();??
  • ????????String?t[]?=?text1.split("\\(");??
  • ????????text1?=?t[0];??
  • ????????t?=?t[1].split(",");??
  • ????????tv_time.setText(text1+?"\n"?+t[0]);??
  • ??????????
  • ????????Element?citys?=?(Element)cityList.item(0);??
  • ????????NodeList?city?=?citys.getChildNodes();??
  • ??????????
  • ????????for?(int?i=0;i?<?city.getLength();i++){??
  • ????????????//此時的city節點的item上,有的是一個城市的所有數據??
  • ????????????Node?node?=?city.item(i);??
  • ????????????if?(node.getNodeName().equalsIgnoreCase("city"))?{?//這是一個有效的節點??
  • ????????????????CityData?cd?=?new?CityData(node);??
  • ????????????????nodeList.add(node);??
  • ????????????????cdList.add(cd);??
  • ????????????}??
  • ????????}??
  • ????}?catch?(Exception?e)?{}??

  • ? ? ? ??這樣每個城市的數據就成為了一個Node,解析XML的過程比較復雜,需要不斷地去嘗試。

    4.2 應用數據到布局

    接下來要編寫一個Adapter來連接布局和代碼。我們假設每一個每一個城市的數據都是一個Node(節點),GridView的數據存在一個列表里,格子的個數與列表的長度有關。(所以如果河北省城市監測點變多了,程序也可以進行變化而自適應)分析數據源的XML可以得到,我們需要的是其中城市,和每個城市中監測點的列表。所以,在這里新建兩個類:CityData、Pointer,其中,CityData包括一個Pointer的列表。以下是CityData類,Pointer類與這個相似: [java]?view plaincopy
  • public?class?CityData?implements?Serializable{??
  • ??????
  • ????/**?
  • ?????*?繼承Serializable是為了在兩個不同的界面中進行值的傳遞?
  • ?????*/??
  • ????private?static?final?long?serialVersionUID?=?-8473485404751986234L;??
  • ????//城市類包含了一個城市的數據??
  • ????public?String?name,dataTime,aqi,level,maxPoll,color,intro,tips;??
  • ????public?List<Pointer>?pointerList;??
  • ??
  • ????public?CityData(Node?cityNode)?{??
  • ????????super();??
  • ????????//按標簽挨個取出相應標簽的內容??
  • ????????this.name?=?getByTag(cityNode,?"name");??
  • ????????this.dataTime?=?getByTag(cityNode,?"datatime");??
  • ????????this.aqi?=?getByTag(cityNode,?"aqi");??
  • ????????this.level?=?getByTag(cityNode,?"level");??
  • ????????this.maxPoll?=?getByTag(cityNode,?"maxpoll");??
  • ????????String?tmp?=?getByTag(cityNode,?"color");??
  • ????????this.color?=?tmp.replace("0x",?"#");??
  • ????????this.intro?=?getByTag(cityNode,?"intro");??
  • ????????this.tips?=?getByTag(cityNode,?"tips");??
  • ??????????
  • ????????Element?city?=?(Element)cityNode;??
  • ????????NodeList?pointers?=?city.getElementsByTagName("Pointer");??
  • ??????????
  • ????????//向city的pointer列表中添加監測點??
  • ????????pointerList?=?new?ArrayList<Pointer>();??
  • ????????for?(int?i=0;i<pointers.getLength();i++){??
  • ????????????Node?pNode?=?pointers.item(i);??
  • ????????????pointerList.add(new?Pointer(pNode));??
  • ????????}??
  • ????}??
  • ??
  • ????//從XML的node中取出相應標簽中內容的function??
  • ????private?String?getByTag(Node?node,String?tag)?{??
  • ????????for?(int?i=0;i<node.getChildNodes().getLength();i++){??
  • ????????????if?(tag.equalsIgnoreCase(node.getChildNodes().item(i).getNodeName()))??
  • ????????????????return?node.getChildNodes().item(i).getTextContent();??
  • ????????}??
  • ????????return?null;??
  • ????}??
  • }??

  • ? ? ? ??負責把數據填充到布局的Adapter: [java]?view plaincopy
  • class?gvAdapter?extends?BaseAdapter{??
  • ??
  • ????//Adapter的數據源,根據這個數據來填充網格列表??
  • ????List<CityData>?cdList;??
  • ??????
  • ????public?gvAdapter(List<CityData>?cdList)?{??
  • ????????super();??
  • ????????this.cdList?=?cdList;??
  • ????}??
  • ??
  • ????//根據數據的多少返回相應的數值??
  • ????@Override??
  • ????public?int?getCount()?{??
  • ????????return?cdList.size();??
  • ????}??
  • ??
  • ????@Override??
  • ????public?Object?getItem(int?position)?{??
  • ????????return?null;??
  • ????}??
  • ??
  • ????@Override??
  • ????public?long?getItemId(int?position)?{??
  • ????????return?0;??
  • ????}??
  • ??
  • ????@Override??
  • ????public?View?getView(int?position,?View?convertView,?ViewGroup?parent)?{??
  • ????????//解析之前寫好的每個網格的布局??
  • ????????convertView?=?MainActivity.this.getLayoutInflater().inflate(R.layout.gv,?null);??
  • ????????//找到布局中的元素,和布局的背景??
  • ????????TextView?tv_city?=?(TextView)convertView.findViewById(R.id.tv_city);??
  • ????????TextView?tv_aqi?=?(TextView)convertView.findViewById(R.id.tv_aqi);??
  • ????????View?bg?=?convertView.findViewById(R.id.bg);??
  • ????????//根據數據填充每個格子的內容和背景色??
  • ????????tv_city.setText(cdList.get(position).name);??
  • ????????tv_aqi.setText(cdList.get(position).aqi);??
  • ????????bg.setBackgroundColor(Color.parseColor(cdList.get(position).color));??
  • ????????return?convertView;??
  • ????}??
  • ??????
  • }??

  • ? ? ? ??最后在XML解析完成以后,添加一句:gv.setAdapter(new gvAdapter(cdList)); 即把數據填充到了網格中。

    5、其它程序邏輯

    當點擊每個GridView的item的時候,跳轉到相應的城市詳細信息頁面。 右鍵項目的目錄 New --> Other -->Activity,給新的Activity起名為:CityActivity。依照上面介紹的寫法給新的Activity寫好布局和邏輯。 點擊主界面中的網格,自動跳轉到新的界面:
    [java]?view plaincopy
  • gv.setOnItemClickListener(new?OnItemClickListener()?{??
  • ??
  • ????@Override??
  • ????public?void?onItemClick(AdapterView<?>?parent,?View?view,int?position,?long?id)?{?????????????????????????????????????
  • ????????????????//從當前的界面跳轉到城市詳細信息界面??
  • ????<span?style="white-space:pre">??</span>Intent?it?=?new?Intent(MainActivity.this,?CityActivity.class);??
  • ????????????????//對象本身無法使用Intent傳遞,但是我們繼承了Serializable,使傳遞成為了可能??
  • ????????it.putExtra("node",?cdList.get(position));??
  • ????????startActivity(it);??
  • ????}??
  • ????????????});??

  • ? ? ? ??1、在城市詳細信息界面,點擊每個監測點,顯示該監測點的詳細數據。這里需要用到對話框AlertDialog來顯示詳細數據。 2、更改res --> values -->string.xml?中的內容,個性化我們的程序,如下: [html]?view plaincopy
  • <resources>??
  • ????<string?name="app_name">河北空氣質量</string>??
  • ????<string?name="title_activity_city">城市數據</string>??
  • </resources>??
  • ? ? ? ??這樣,程序的名字就變成了“河北空氣質量”,在進入到詳細信息界面的時候,標題欄也變成了“城市數據” 3、找一個圖片,做成png格式,覆蓋res/drawable-hdpi/ic_launcher.png 文件,這樣就更改了在手機APP列表中的圖標了。



    其實做一個APP非常的簡單,只要有想法,上面的工作在一天內就可以完成。本文主要是想帶給大家一個思路,如何發掘身邊的一些內容,來做出自己的APP。 可能光看講解不會太懂,那么可以到http://download.csdn.net/detail/icyfox_bupt/6908053下載程序的源代碼

    總結

    以上是生活随笔為你收集整理的安卓作品:河北空气质量客户端的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。