Android应用开发:网络编程-1
網(wǎng)絡(luò)編程
- Java基礎(chǔ):網(wǎng)絡(luò)編程
- Uri、URL、UriMatcher、ContentUris詳解
- Android應(yīng)用開發(fā):網(wǎng)絡(luò)編程1
- Android應(yīng)用開發(fā):網(wǎng)絡(luò)編程2
1. 請(qǐng)求網(wǎng)絡(luò)圖片
網(wǎng)絡(luò)交互就是基于HTTP協(xié)議請(qǐng)求和響應(yīng)的過程。XMPP協(xié)議用于即時(shí)通訊。
示例:res\layout\activity_main.xml
<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" ><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="請(qǐng)求圖片" android:onClick="click"/><ImageView android:id="@+id/iv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"/></RelativeLayout>src/cn.itcast.imageviewer/MainActivity.java
package cn.itcast.imageviewer;import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.Toast;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){//向服務(wù)器發(fā)送Http請(qǐng)求去請(qǐng)求圖片String path = "http://192.168.1.100:8080/sh.jpg";try{//1. 把網(wǎng)址封裝成url對(duì)象URL url = new URL(path);//2. 打開一個(gè)連接對(duì)象HttpURLConnection conn = (HttpURLConnection) url.openConnection();//3. 給連接對(duì)象做設(shè)置conn.setRequestMethod("GET");conn.setConnectTimeout(8000);conn.setReadTimeout(8000);//4. 發(fā)送請(qǐng)求,建立連接conn.connect();//5. 獲取響應(yīng)碼,如果為200開頭,說明請(qǐng)求成功if(conn.getResponseCode() == 200){//獲取服務(wù)器的流,服務(wù)器返回的數(shù)據(jù)是通過流寫給客戶端的,也就是說,流里就是請(qǐng)求的圖片InputStream is = conn.getInputStream();//讀取流里的數(shù)據(jù),把數(shù)據(jù)構(gòu)造成一個(gè)圖片對(duì)象Bitmap bm = BitmapFactory.decodeStream(is);//把圖片顯示至屏幕ImageView iv = (ImageView) findViewById(R.id.iv);iv.setImageBitmap(bm);}else{Toast.makeText(this, "請(qǐng)求失敗啦啦啦", 0).show();}}catch(Exception e){e.printStackTrace();}} }添加權(quán)限:
在Tomcat服務(wù)器webapps\ROOT存放圖片:
運(yùn)行結(jié)果:雙擊start.bat,啟動(dòng)tomcat。
啟動(dòng)2.3.3版本模擬器,圖片顯示成功:
Handler機(jī)制讓子線程刷新UI,如果上面的示例運(yùn)行在4.3版本的模擬器上,就會(huì)報(bào)警告:
在Android中,主線程是絕對(duì)不能阻塞的。因?yàn)?#xff0c;網(wǎng)絡(luò)請(qǐng)求是耗時(shí)操作,主線程處于阻塞狀態(tài),用戶任何操作都無效,處于類似于死機(jī)的狀態(tài)。此時(shí),點(diǎn)擊HOME鍵有效,點(diǎn)擊返回鍵、菜單鍵都沒有反應(yīng)。因?yàn)?#xff0c;返回鍵和菜單鍵是由當(dāng)前應(yīng)用程序自行處理,HOME鍵是由系統(tǒng)處理。應(yīng)用程序可以阻塞自己的主線程,不可能阻塞Android系統(tǒng)。
為了保證用戶體驗(yàn)良好,所有的耗時(shí)操作都不要寫在主線程里,包括:請(qǐng)求網(wǎng)絡(luò)、加載數(shù)據(jù)(數(shù)據(jù)庫)和資源。
ANR:Application Not Responding,應(yīng)用長(zhǎng)時(shí)間不能響應(yīng)用戶操作。
查看出現(xiàn)ANR的原因,導(dǎo)出data/anr/traces.txt文件,打開。
ANR無法調(diào)試,解決方法就是在主線程中不要做耗時(shí)操作。
只有主線程可以刷新UI,主線程又稱UI線程。這樣做,是為了線程安全,只有一個(gè)線程可以刷新UI,如果有多個(gè)線程同時(shí)刷新UI,就可能出現(xiàn)線程安全導(dǎo)致UI刷新混亂的問題。
如果我們?cè)贛ainActivity.java中啟動(dòng)一個(gè)線程進(jìn)行網(wǎng)絡(luò)請(qǐng)求,再次執(zhí)行該應(yīng)用程序就會(huì)報(bào)警告,如下:
通過異常可以看出來,刷新UI的代碼必須在主線程中執(zhí)行,但是請(qǐng)求圖片的代碼又由于不能引起阻塞,只能在子線程中執(zhí)行,而且只有請(qǐng)求完圖片之后才能刷新UI,這時(shí)候就形成了矛盾。Android里面提供了一種機(jī)制能夠解決這個(gè)問題,也就是Handler機(jī)制。
2. Handler機(jī)制
主線程創(chuàng)建的時(shí)候,主線程中有一個(gè)消息隊(duì)列MessageQueue,用來存放消息。還有一個(gè)Looper用來不斷檢測(cè)MessageQueue是否有消息。如果有消息就交給消息處理器Handler,Handler中有一個(gè)方法handleMessage,用來處理消息,這個(gè)方法是在主線程調(diào)用。那么,這個(gè)方法就可以刷新UI。如此,子線程想要刷新UI,只需調(diào)用Handler的sendMessag方法,將消息發(fā)送到MessageQueue即可。
示例:src/cn.itcast.imageviewer2/MainActivity.java
package cn.itcast.imageviewer2;import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL;import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.ImageView; import android.widget.Toast;public class MainActivity extends Activity {Handler handler = new Handler(){//程序員需要重寫handlerMessage方法,刷新UI@Overridepublic void handleMessage(Message msg) {switch(msg.what){case 1://判斷消息是成功消息還是失敗消息ImageView iv = (ImageView) findViewById(R.id.iv);iv.setImageBitmap((Bitmap)msg.obj);break;case 2:Toast.makeText(MainActivity.this, "請(qǐng)求失敗啦啦啦", 0).show();break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){Thread t = new Thread(){public void run(){String path = "http://192.168.1.100:8080/sh.jpg";try{URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(8000);conn.setReadTimeout(8000);conn.connect();if(conn.getResponseCode() == 200){InputStream is = conn.getInputStream();Bitmap bm = BitmapFactory.decodeStream(is);//創(chuàng)建消息對(duì)象Message msg = new Message();//消息對(duì)象可以攜帶數(shù)據(jù)msg.obj = bm;msg.what = 1;//發(fā)送消息至主線程的消息隊(duì)列handler.sendMessage(msg);}else{Message msg = new Message();msg.what = 2;handler.sendMessage(msg);//由于Message沒有攜帶任何數(shù)據(jù),所以上面3句可以用下面1句替換。//handler.sendEmptyMessage(2);}}catch(Exception e){e.printStackTrace();}}};t.start();} }運(yùn)行結(jié)果:
添加緩存功能的圖片查看器,為了提升效率,查看圖片后,緩存起來,便于下次查看圖片不必在通過網(wǎng)絡(luò)請(qǐng)求。
代碼:src/cn.itcast.imageviewer3/MainActivity.java
package cn.itcast.imageviewer3;import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.ImageView; import android.widget.Toast;public class MainActivity extends Activity {Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch(msg.what){case 1:ImageView iv = (ImageView) findViewById(R.id.iv);iv.setImageBitmap((Bitmap)msg.obj);break;case 2:Toast.makeText(MainActivity.this, "請(qǐng)求失敗啦啦啦", 0).show();break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){final String path = "http://192.168.1.100:8080/sh.jpg";final File file = new File(getCacheDir(),getFileName(path));if(file.exists()){System.out.println("從緩存獲取");Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());ImageView iv = (ImageView) findViewById(R.id.iv);iv.setImageBitmap(bm);}else{Thread t = new Thread(){public void run(){try{System.out.println("從網(wǎng)絡(luò)獲取");URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(8000);conn.setReadTimeout(8000);conn.connect();if(conn.getResponseCode() == 200){InputStream is = conn.getInputStream();//需要自己開啟文件輸出流,讀取流里數(shù)據(jù)的同時(shí),把數(shù)據(jù)寫到本地byte[] b = new byte[1024];int len;FileOutputStream fos = new FileOutputStream(file);while((len = is.read(b)) != -1){fos.write(b, 0, len);}fos.close();//流里數(shù)據(jù)已經(jīng)讀取完畢,這行代碼無法再構(gòu)造圖片了//Bitmap bm = BitmapFactory.decodeStream(is);Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());Message msg = new Message();msg.obj = bm;msg.what = 1;handler.sendMessage(msg);}else{Message msg = new Message();msg.what = 2;handler.sendMessage(msg);}}catch(Exception e){e.printStackTrace();}}};t.start();}}public String getFileName(String path){int index = path.lastIndexOf("/");return path.substring(index+1);} }運(yùn)行結(jié)果:
第一次,從網(wǎng)絡(luò)獲取。第二次再次點(diǎn)擊按鈕,從緩存獲取。
3. 獲取開源代碼
在程序開發(fā)中,會(huì)遇到很多問題。例如,請(qǐng)求圖片過程中遇到斷網(wǎng),網(wǎng)速慢,圖片過大內(nèi)存不夠等等情況。由于這些情況大部分項(xiàng)目都會(huì)遇到,所以網(wǎng)上有很多寫好的現(xiàn)成的模塊。不要重新發(fā)明輪子,可以直接拿來用。
好的開源網(wǎng)站: http://code.google.com http://github.com
搜索,下載源碼,解壓,復(fù)制到我們自己的應(yīng)用程序項(xiàng)目中。
res\layout\activity_main.xml
<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" ><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="請(qǐng)求網(wǎng)絡(luò)圖片" android:onClick="click"/><com.loopj.android.image.SmartImageView android:id="@+id/iv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_launcher"android:layout_centerInParent="true"/> </RelativeLayout>SmartImageView是自定義控件,以后會(huì)有專門的課程講解。
src/cn.itcast.smartimageview/MainActivity.java
package cn.itcast.smartimageview;import android.app.Activity; import android.os.Bundle; import android.view.View;import com.loopj.android.image.SmartImageView;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){String path = "http://192.168.1.100:8080/sh.jpg";SmartImageView iv = (SmartImageView) findViewById(R.id.iv);iv.setImageUrl(path);} }添加權(quán)限:
運(yùn)行結(jié)果:
4. Html源文件查看器
代碼:res\layout\activity_main.xml
<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" ><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="請(qǐng)求網(wǎng)絡(luò)" android:onClick="click"/><ScrollView android:layout_width="match_parent"android:layout_height="match_parent"><TextView android:id="@+id/tv"android:layout_width="match_parent"android:layout_height="match_parent"/></ScrollView> </RelativeLayout>src/cn.itcast.htmlviewer.tool/Tools.java
package cn.itcast.htmlviewer.tool;import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream;public class Tools {public static String getTextFromStream(InputStream is){try{byte[] b = new byte[1024];int len;ByteArrayOutputStream bos = new ByteArrayOutputStream();while((len = is.read(b)) != -1){bos.write(b,0,len);}//把輸出流里的內(nèi)容轉(zhuǎn)換成字節(jié)數(shù)組String text = new String(bos.toByteArray());return text;}catch(IOException e){e.printStackTrace();}return null;} }src/cn.itcast.htmlviewer/MainActivity.java
package cn.itcast.htmlviewer;import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL;import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.TextView; import cn.itcast.htmlviewer.tool.Tools;public class MainActivity extends Activity {Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {TextView tv = (TextView) findViewById(R.id.tv);tv.setText((String)msg.obj);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){Thread t = new Thread(){public void run(){String path = "http://192.168.1.100:8080/baidu.html";try{URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(8000);conn.setReadTimeout(8000);//先發(fā)送請(qǐng)求,再獲取響應(yīng)碼,getResponseCode方法自身會(huì)發(fā)送請(qǐng)求消息if(conn.getResponseCode() == 200){InputStream is = conn.getInputStream();String text = Tools.getTextFromStream(is);//如果消息池中沒有消息,new一個(gè),如果有,復(fù)用這條空閑消息Message msg = handler.obtainMessage();msg.obj = text;handler.sendMessage(msg);}}catch(Exception e){e.printStackTrace();}}};t.start();} }添加權(quán)限:
運(yùn)行結(jié)果:
如果html文件為gbk編碼:
那么Tools.java中代碼只要進(jìn)行如下修改即可:
新聞客戶端布局
res\layout\item_listview.xml
<?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="wrap_content" ><ImageView android:id="@+id/iv"android:layout_width="90dp"android:layout_height="70dp"android:src="@drawable/ic_launcher"android:layout_centerVertical="true"/><!-- android:singleLine是為了讓過長(zhǎng)的標(biāo)題不會(huì)導(dǎo)致?lián)Q行,影響美觀 --><TextView android:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="22sp"android:text="這是標(biāo)題"android:singleLine="true"android:layout_toRightOf="@+id/iv"/><!-- android:lines表示如果文本過長(zhǎng),最多顯示幾行 --><TextView android:id="@+id/tv_detail"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="15sp"android:text="這是詳細(xì)"android:lines="2"android:textColor="@android:color/darker_gray"android:layout_toRightOf="@+id/iv"android:layout_below="@id/tv_title"/><TextView android:id="@+id/tv_comment"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="12345條評(píng)論"android:textColor="#ff0000"android:layout_alignParentRight="true"android:layout_below="@id/tv_detail"/></RelativeLayout>效果:
獲取新聞信息,將news.xml和images文件夾存放在Tomcat服務(wù)器中。
News.xml
<?xml version="1.0" encoding="UTF-8" ?> <newslist><news><title>西安一期就業(yè)快報(bào)</title><detail>熱烈祝賀西安一期平均薪水突破13k</detail><comment>15687</comment><image>http://192.168.1.100:8080/images/6.jpg</image></news><news><title>程序員因?qū)懘a太亂被殺害</title><detail>兇手是死者同事,維護(hù)死者代碼時(shí)完全看不懂而痛下殺手</detail><comment>16359</comment><image>http://192.168.1.100:8080/images/7.jpg</image></news><news><title>產(chǎn)品經(jīng)理因頻繁改需求被殺害</title><detail>兇手是一名程序員,因死者對(duì)項(xiàng)目需求頻繁改動(dòng)而痛下殺手</detail><comment>14112</comment><image>http://192.168.1.100:8080/images/7.jpg</image></news><news><title>3Q大戰(zhàn)宣判: 騰訊獲賠500萬</title><detail>最高法駁回360上訴, 維持一審宣判.</detail><comment>6427</comment><image>http://192.168.1.100:8080/images/1.jpg</image></news><news><title>今日之聲:北大雕塑被戴口罩</title><detail>市民: 因霧霾起訴環(huán)保局; 公務(wù)員談"緊日子": 堅(jiān)決不出去.</detail><comment>681</comment><image>http://192.168.1.100:8080/images/2.jpg</image></news><news><title>奧巴馬見達(dá)賴是裝蒜</title><detail>外文局: 國(guó)際民眾認(rèn)可中國(guó)大國(guó)地位;法院: "流量清零"未侵權(quán).</detail><comment>1359</comment><image>http://192.168.1.100:8080/images/3.jpg</image></news><news><title>輕松一刻: 我要沉迷學(xué)習(xí)不自拔</title><detail>放假時(shí)我醒了不代表我起床了, 如今我起床了不代表我醒了!</detail><comment>11616</comment><image>http://192.168.1.100:8080/images/4.jpg</image></news><news><title>男女那些事兒</title><detail>"媽, 我在東莞被抓, 要2萬保釋金, 快匯錢到xxx!"</detail><comment>10339</comment><image>http://192.168.1.100:8080/images/5.jpg</image></news><news><title>趙帥哥語錄一</title><detail>少壯不努力,老大做IT</detail><comment>14612</comment><image>http://192.168.1.100:8080/images/8.jpg</image></news><news><title>趙帥哥語錄二</title><detail>問君能有幾多愁,恰似調(diào)完代碼改需求</detail><comment>13230</comment><image>http://192.168.1.100:8080/images/8.jpg</image></news><news><title>趙帥哥語錄三</title><detail>覺得我?guī)浀娜斯べY一般都比較高</detail><comment>9928</comment><image>http://192.168.1.100:8080/images/8.jpg</image></news><news><title>今日之聲:北大雕塑被戴口罩</title><detail>市民: 因霧霾起訴環(huán)保局; 公務(wù)員談"緊日子": 堅(jiān)決不出去.</detail><comment>681</comment><image>http://192.168.1.100:8080/images/2.jpg</image></news><news><title>奧巴馬見達(dá)賴是裝蒜</title><detail>外文局: 國(guó)際民眾認(rèn)可中國(guó)大國(guó)地位;法院: "流量清零"未侵權(quán).</detail><comment>1359</comment><image>http://192.168.1.100:8080/images/3.jpg</image></news> </newslist> src/cn.itcast.news.domain/News.java package cn.itcast.news.domain;public class News {private String title; private String detail;private String comment;private String imageUrl;public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getDetail() {return detail;}public void setDetail(String detail) {this.detail = detail;}public String getComment() {return comment;}public void setComment(String comment) {this.comment = comment;}public String getImageUrl() {return imageUrl;}public void setImageUrl(String imageUrl) {this.imageUrl = imageUrl;} } src/cn.itcast.news/MainActivity.java package cn.itcast.news;import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.List;import org.xmlpull.v1.XmlPullParser;import android.app.Activity; import android.os.Bundle; import android.util.Xml; import cn.itcast.news.domain.News;public class MainActivity extends Activity {List<News> newsList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getNewsInfo();}private void getNewsInfo(){Thread t = new Thread(){public void run(){String path = "http://192.168.1.100:8080/news.xml";try{URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection)url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(8000);conn.setReadTimeout(8000);if(conn.getResponseCode() == 200){//獲取服務(wù)器返回的流,流里就是xml文件InputStream is = conn.getInputStream();parserNewsInfo(is);}}catch(Exception e){e.printStackTrace();}}};t.start();}private void parserNewsInfo(InputStream is){XmlPullParser xp = Xml.newPullParser();try{xp.setInput(is,"utf-8"); int type = xp.getEventType(); News news = null; while(type != XmlPullParser.END_DOCUMENT){switch(type){case XmlPullParser.START_TAG:if("newslist".equals(xp.getName())){newsList = new ArrayList<News>();}else if("news".equals(xp.getName())){news = new News();}else if("title".equals(xp.getName())){String title = xp.nextText();news.setTitle(title);}else if("detail".equals(xp.getName())){String detail = xp.nextText();news.setDetail(detail);}else if("comment".equals(xp.getName())){String comment = xp.nextText();news.setComment(comment);}else if("image".equals(xp.getName())){String image = xp.nextText();news.setImageUrl(image);}break;case XmlPullParser.END_TAG:if("news".equals(xp.getName())){newsList.add(news);}break;}type = xp.next();}}catch(Exception e){e.printStackTrace();}} }把新聞信息顯示至界面
修改res\layout\item_listview.xml中的ImageView標(biāo)簽為SmartImageView標(biāo)簽,便于顯示圖片。
src/cn.itcast.news/MainActivity.java package cn.itcast.news;import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.xmlpull.v1.XmlPullParser; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Xml; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import cn.itcast.news.domain.News;import com.loopj.android.image.SmartImageView;public class MainActivity extends Activity {List<News> newsList;Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {ListView lv = (ListView)findViewById(R.id.lv);lv.setAdapter(new MyAdapter());}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getNewsInfo();//由于getNewsInfo方法中是開啟了一個(gè)子線程,與主線程并行。所以當(dāng)listview顯示內(nèi)容時(shí),newsList還沒來得及創(chuàng)建,所以lv設(shè)置顯示內(nèi)容的代碼不能運(yùn)行在這里。要保證運(yùn)行在xml解析完畢之后。//ListView lv = (ListView)findViewById(R.id.lv);//lv.setAdapter(new MyAdapter());}class MyAdapter extends BaseAdapter{@Overridepublic int getCount() {//之所以系統(tǒng)需要知道條目數(shù)量,是因?yàn)槠聊挥覀?cè)的控制條顯示基于此數(shù)據(jù)而定return newsList.size();}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}//視圖保存器class ViewHolder{TextView tv_title;TextView tv_detail;TextView tv_comment;SmartImageView siv;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View v = null;ViewHolder vh = null;News news = newsList.get(position);if(convertView == null){v = View.inflate(MainActivity.this, R.layout.item_listview, null);vh = new ViewHolder();//如果緩存為空,那么需要填充新的View對(duì)象,同時(shí)找到布局文件中的所有組件,并封裝至ViewHolder對(duì)象中vh.tv_title = (TextView)v.findViewById(R.id.tv_title);vh.tv_detail = (TextView)v.findViewById(R.id.tv_detail);vh.tv_comment = (TextView)v.findViewById(R.id.tv_comment);vh.siv = (SmartImageView) v.findViewById(R.id.iv);//把ViewHolder對(duì)象存入View對(duì)象中,緩存View對(duì)象,同時(shí)緩存了ViewHolder對(duì)象v.setTag(vh);}else{v = convertView;//從緩存中取出ViewHolder對(duì)象,這個(gè)對(duì)象中就封裝了布局文件中所有的組件對(duì)象,那么就不需要再次findViewById了vh = (ViewHolder)v.getTag();}vh.tv_title.setText(news.getTitle());vh.tv_detail.setText(news.getDetail());vh.tv_comment.setText(news.getComment() + "條評(píng)論");vh.siv.setImageUrl(news.getImageUrl());return v;}}private void getNewsInfo(){Thread t = new Thread(){public void run(){String path = "http://192.168.1.100:8080/news.xml";try{URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection)url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(8000);conn.setReadTimeout(8000);if(conn.getResponseCode() == 200){InputStream is = conn.getInputStream();parserNewsInfo(is);}}catch(Exception e){e.printStackTrace();}}};t.start();}private void parserNewsInfo(InputStream is){XmlPullParser xp = Xml.newPullParser();try{xp.setInput(is,"utf-8");int type = xp.getEventType();News news = null;while(type != XmlPullParser.END_DOCUMENT){switch(type){case XmlPullParser.START_TAG:if("newslist".equals(xp.getName())){newsList = new ArrayList<News>();}else if("news".equals(xp.getName())){news = new News();}else if("title".equals(xp.getName())){String title = xp.nextText();news.setTitle(title);}else if("detail".equals(xp.getName())){String detail = xp.nextText();news.setDetail(detail);}else if("comment".equals(xp.getName())){String comment = xp.nextText();news.setComment(comment);}else if("image".equals(xp.getName())){String image = xp.nextText();news.setImageUrl(image);}break;case XmlPullParser.END_TAG:if("news".equals(xp.getName())){newsList.add(news);}break;}type = xp.next();}}catch(Exception e){e.printStackTrace();}//xml解析完畢,發(fā)送消息,通知主線程,設(shè)置lv的顯示內(nèi)容handler.sendEmptyMessage(1);} }
添加權(quán)限:
運(yùn)行結(jié)果:
使用get方式提交表單
使用MyEclipse,新建一個(gè)Servlet:Login.java,把該Web項(xiàng)目部署到Tomcat服務(wù)器上。
src/cn.itcast.login/Login.java
package cn.itcast.login;import java.io.IOException;import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public class Login extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String name = request.getParameter("name");String pass = request.getParameter("pass");ServletOutputStream os = response.getOutputStream();if("asd".equals(name)&&"123".equals(pass)){os.write("登陸成功".getBytes("utf-8"));}else{os.write("登陸失敗".getBytes("utf-8"));}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);} }WebRoot/index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html><head></head><body><form action="/Web/servlet/Login" method=get>賬號(hào):<input type="text" name="name"><br/>密碼:<input type="text" name="pass"><br/><input type="submit" value="登陸"/></form></body> </html>打開瀏覽器,輸入地址,然后輸入用戶名和密碼,提交。
將瀏覽器編碼改為UTF-8。
結(jié)果如下:
Android之Get方式提交數(shù)據(jù): res\layout\activity_main.xml <LinearLayout 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" android:orientation="vertical"><EditText android:id="@+id/et_name"android:layout_width="match_parent"android:layout_height="wrap_content"/><EditText android:id="@+id/et_pass"android:layout_width="match_parent"android:layout_height="wrap_content"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="登陸"android:onClick="click"/> </LinearLayout> src/cn.itcast.getmethod.tool/Tools.java package cn.itcast.getmethod.tool;import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream;public class Tools {public static String getTextFromStream(InputStream is){try{byte[] b = new byte[1024];int len;ByteArrayOutputStream bos = new ByteArrayOutputStream();while((len = is.read(b)) != -1){bos.write(b,0,len);}//把輸出流里的內(nèi)容轉(zhuǎn)換成字節(jié)數(shù)組String text = new String(bos.toByteArray());return text;}catch(IOException e){e.printStackTrace();}return null;} } src/cn.itcast.getmethod/MainActivity.java package cn.itcast.getmethod;import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL;import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.EditText; import android.widget.Toast; import cn.itcast.getmethod.tool.Tools;public class MainActivity extends Activity {Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){EditText et_name = (EditText)findViewById(R.id.et_name);EditText et_pass = (EditText)findViewById(R.id.et_pass);String name = et_name.getText().toString();String pass = et_pass.getText().toString();//在url后面拼接要提交的數(shù)據(jù)final String path = "http://localhost:8080/Web/servlet/Login?name=" + name + "&pass=" + pass;Thread t = new Thread(){public void run(){URL url;try {url = new URL(path);HttpURLConnection conn = (HttpURLConnection)url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(8000);conn.setReadTimeout(8000);if(conn.getResponseCode() == 200){InputStream is = conn.getInputStream();String text = Tools.getTextFromStream(is);Message msg = handler.obtainMessage();msg.obj = text;handler.sendMessage(msg);}} catch (Exception e) {e.printStackTrace();}}};t.start();} }
添加權(quán)限:
運(yùn)行結(jié)果:
提交表單的亂碼問題
將Login.java中“zhangsan”修改為“張三”,并且打印出接收到的用戶名及密碼。src/cn.itcast.login/Login.java
package cn.itcast.login;import java.io.IOException;import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public class Login extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String name = request.getParameter("name");String pass = request.getParameter("pass");System.out.println(name);System.out.println(pass);ServletOutputStream os = response.getOutputStream();if("張三".equals(name)&&"123".equals(pass)){os.write("登陸成功".getBytes("utf-8"));}else{os.write("登陸失敗".getBytes("utf-8"));}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);} }重新部署,運(yùn)行。結(jié)果如下:
將瀏覽器編碼調(diào)整為UTF-8。
可以看到,打印出來的為亂碼。原因在于瀏覽器提交表單的時(shí)候,會(huì)把“張三”用UTF-8編碼變成字節(jié)數(shù)組,然后傳給服務(wù)器。服務(wù)器拿到這些字節(jié)以后,因?yàn)間etParameter默認(rèn)使用iso8859-1編碼把讀取到的字節(jié)數(shù)組構(gòu)造成字符串,導(dǎo)致亂碼。因此,解決方案為,首先使用iso8859-1把字符串重新轉(zhuǎn)換成字節(jié)數(shù)組,然后再用utf-8構(gòu)造成字符串即可。
重新部署,運(yùn)行,結(jié)果如下:
嘗試通過手機(jī)端發(fā)送中文的情況,如下:輸入中文,首先選擇谷歌拼音輸入法。
由上面的圖片可以看到,依然存在亂碼問題。原因在于瀏覽器提交的數(shù)據(jù)都是經(jīng)過URL編碼的,所以,通過代碼提交的數(shù)據(jù)就需要手動(dòng)編碼。
修改后,運(yùn)行結(jié)果:
使用post方式提交表單,修改表單為post提交方式:
通過代碼實(shí)現(xiàn)post提交請(qǐng)求,一方面通過流的方式將數(shù)據(jù)傳輸給服務(wù)器,一方面是給post請(qǐng)求頭添加額外屬性。
src/cn.itcast.postmethod/MainActivity.java
package cn.itcast.postmethod;import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder;import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.EditText; import android.widget.Toast; import cn.itcast.getmethod.tool.Tools;public class MainActivity extends Activity {Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){EditText et_name = (EditText)findViewById(R.id.et_name);EditText et_pass = (EditText)findViewById(R.id.et_pass);final String name = et_name.getText().toString();final String pass = et_pass.getText().toString();final String path = "http://192.168.1.100:8080/Web/servlet/Login";Thread t = new Thread(){public void run(){URL url;try {url = new URL(path);HttpURLConnection conn = (HttpURLConnection)url.openConnection();conn.setRequestMethod("POST");conn.setConnectTimeout(8000);conn.setReadTimeout(8000);//post請(qǐng)求頭需要添加額外屬性conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");String content = "name=" + URLEncoder.encode(name) + "&pass=" + pass;conn.setRequestProperty("Content-Length", content.length() + "");//開啟請(qǐng)求頭的流,把要提交的數(shù)據(jù)寫入流中//設(shè)置打開連接對(duì)象輸出流conn.setDoOutput(true);OutputStream os = conn.getOutputStream();os.write(content.getBytes());if(conn.getResponseCode() == 200){InputStream is = conn.getInputStream();String text = Tools.getTextFromStream(is);Message msg = handler.obtainMessage();msg.obj = text;handler.sendMessage(msg);}} catch (Exception e) {e.printStackTrace();}}};t.start();} }運(yùn)行結(jié)果:
1. 網(wǎng)絡(luò)圖片查看器
- 確定圖片的網(wǎng)址
- 發(fā)送http請(qǐng)求
- 服務(wù)器的圖片是以流的形式返回給瀏覽器的
- 把圖片設(shè)置為ImageView的顯示內(nèi)容
- 添加網(wǎng)絡(luò)權(quán)限
1.1 主線程不能被阻塞
- 在Android中,主線程被阻塞會(huì)導(dǎo)致應(yīng)用不能刷新ui界面,不能響應(yīng)用戶操作,用戶體驗(yàn)將非常差
- 主線程阻塞時(shí)間過長(zhǎng),系統(tǒng)會(huì)拋出ANR異常
- ANR:Application Not Response;應(yīng)用無響應(yīng)
- 任何耗時(shí)操作都不可以寫在主線程
- 因?yàn)榫W(wǎng)絡(luò)交互屬于耗時(shí)操作,如果網(wǎng)速很慢,代碼會(huì)阻塞,所以網(wǎng)絡(luò)交互的代碼不能運(yùn)行在主線程
1.2 只有主線程能刷新ui
- 刷新ui的代碼只能運(yùn)行在主線程,運(yùn)行在子線程是沒有任何效果的
- 如果需要在子線程中刷新ui,使用消息隊(duì)列機(jī)制
1.3 消息隊(duì)列
- Looper一旦發(fā)現(xiàn)Message Queue中有消息,就會(huì)把消息取出,然后把消息扔給Handler對(duì)象,Handler會(huì)調(diào)用自己的handleMessage方法來處理這條消息
- handleMessage方法運(yùn)行在主線程
- 主線程創(chuàng)建時(shí),消息隊(duì)列和輪詢器對(duì)象就會(huì)被創(chuàng)建,但是消息處理器對(duì)象,需要使用時(shí),自行創(chuàng)建
- 在子線程中往消息隊(duì)列里發(fā)消息
- 通過switch語句區(qū)分不同的消息
1.4 案例1:網(wǎng)絡(luò)圖片查看器
public class MainActivity extends Activity {static ImageView iv;static MainActivity ma;static Handler handler = new Handler(){//此方法在主線程中調(diào)用,可以用來刷新uipublic void handleMessage(android.os.Message msg) {//處理消息時(shí),需要知道到底是成功的消息,還是失敗的消息switch (msg.what) {case 1://把位圖對(duì)象顯示至imageviewiv.setImageBitmap((Bitmap)msg.obj);break;case 0:Toast.makeText(ma, "請(qǐng)求失敗", 0).show();break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);ma = this;}public void click(View v){Thread t = new Thread(){@Overridepublic void run() {//下載圖片//1.確定網(wǎng)址String path = "http://192.168.13.13:8080/dd.jpg";try {//2.把網(wǎng)址封裝成一個(gè)url對(duì)象URL url = new URL(path);//3.獲取客戶端和服務(wù)器的連接對(duì)象,此時(shí)還沒有建立連接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//4.對(duì)連接對(duì)象進(jìn)行初始化//設(shè)置請(qǐng)求方法,注意大寫conn.setRequestMethod("GET");//設(shè)置連接超時(shí)conn.setConnectTimeout(5000);//設(shè)置讀取超時(shí)conn.setReadTimeout(5000);//5.發(fā)送請(qǐng)求,與服務(wù)器建立連接conn.connect();//如果響應(yīng)碼為200,說明請(qǐng)求成功if(conn.getResponseCode() == 200){//獲取服務(wù)器響應(yīng)頭中的流,流里的數(shù)據(jù)就是客戶端請(qǐng)求的數(shù)據(jù)InputStream is = conn.getInputStream();//讀取出流里的數(shù)據(jù),并構(gòu)造成位圖對(duì)象Bitmap bm = BitmapFactory.decodeStream(is);// ImageView iv = (ImageView) findViewById(R.id.iv); // //把位圖對(duì)象顯示至imageview // iv.setImageBitmap(bm);Message msg = new Message();//消息對(duì)象可以攜帶數(shù)據(jù)msg.obj = bm;msg.what = 1;//把消息發(fā)送至主線程的消息隊(duì)列handler.sendMessage(msg);}else{ // Toast.makeText(MainActivity.this, "請(qǐng)求失敗", 0).show();Message msg = handler.obtainMessage();msg.what = 0;handler.sendMessage(msg);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}};t.start();} }1.5 加入緩存圖片的功能
- 把服務(wù)器返回的流里的數(shù)據(jù)讀取出來,然后通過文件輸入流寫至本地文件
- 創(chuàng)建bitmap對(duì)象的代碼改成
- 每次發(fā)送請(qǐng)求前檢測(cè)一下在緩存中是否存在同名圖片,如果存在,則讀取緩存
1.6 案例2:帶緩存的網(wǎng)絡(luò)圖片查看器
public class MainActivity extends Activity {static ImageView iv;static MainActivity ma;static Handler handler = new Handler(){//此方法在主線程中調(diào)用,可以用來刷新uipublic void handleMessage(android.os.Message msg) {//處理消息時(shí),需要知道到底是成功的消息,還是失敗的消息switch (msg.what) {case 1://把位圖對(duì)象顯示至imageviewiv.setImageBitmap((Bitmap)msg.obj);break;case 0:Toast.makeText(ma, "請(qǐng)求失敗", 0).show();break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);ma = this;}public void click(View v){//下載圖片//1.確定網(wǎng)址final String path = "http://192.168.13.13:8080/dd.jpg";final File file = new File(getCacheDir(), getFileName(path));//判斷,緩存中是否存在該文件if(file.exists()){//如果緩存存在,從緩存讀取圖片System.out.println("從緩存讀取的");Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());iv.setImageBitmap(bm);}else{//如果緩存不存在,從網(wǎng)絡(luò)下載System.out.println("從網(wǎng)上下載的");Thread t = new Thread(){@Overridepublic void run() {try {//2.把網(wǎng)址封裝成一個(gè)url對(duì)象URL url = new URL(path);//3.獲取客戶端和服務(wù)器的連接對(duì)象,此時(shí)還沒有建立連接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//4.對(duì)連接對(duì)象進(jìn)行初始化//設(shè)置請(qǐng)求方法,注意大寫conn.setRequestMethod("GET");//設(shè)置連接超時(shí)conn.setConnectTimeout(5000);//設(shè)置讀取超時(shí)conn.setReadTimeout(5000);//5.發(fā)送請(qǐng)求,與服務(wù)器建立連接conn.connect();//如果響應(yīng)碼為200,說明請(qǐng)求成功if(conn.getResponseCode() == 200){//獲取服務(wù)器響應(yīng)頭中的流,流里的數(shù)據(jù)就是客戶端請(qǐng)求的數(shù)據(jù)InputStream is = conn.getInputStream();//讀取服務(wù)器返回的流里的數(shù)據(jù),把數(shù)據(jù)寫到本地文件,緩存起來FileOutputStream fos = new FileOutputStream(file);byte[] b = new byte[1024];int len = 0;while((len = is.read(b)) != -1){fos.write(b, 0, len);}fos.close();//讀取出流里的數(shù)據(jù),并構(gòu)造成位圖對(duì)象//流里已經(jīng)沒有數(shù)據(jù)了 // Bitmap bm = BitmapFactory.decodeStream(is);Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());Message msg = new Message();//消息對(duì)象可以攜帶數(shù)據(jù)msg.obj = bm;msg.what = 1;//把消息發(fā)送至主線程的消息隊(duì)列handler.sendMessage(msg);}else{ // Toast.makeText(MainActivity.this, "請(qǐng)求失敗", 0).show();Message msg = handler.obtainMessage();msg.what = 0;handler.sendMessage(msg);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}};t.start();}}public String getFileName(String path){int index = path.lastIndexOf("/");return path.substring(index + 1);}}1.7 案例3:開源圖片查看器
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){//下載圖片//1.確定網(wǎng)址String path = "http://192.168.13.13:8080/dd.jpg";//2.找到智能圖片查看器對(duì)象SmartImageView siv = (SmartImageView) findViewById(R.id.iv);//3.下載并顯示圖片siv.setImageUrl(path);}}2. 獲取開源代碼的網(wǎng)站
- code.google.com
- github.com
- 在github搜索smart-image-view
- 下載開源項(xiàng)目smart-image-view
- 使用自定義組件時(shí),標(biāo)簽名字要寫包名
- SmartImageView的使用
3. 新聞客戶端
public class MainActivity extends Activity {List<News> newsList;Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {ListView lv = (ListView) findViewById(R.id.lv);lv.setAdapter(new MyAdapter());}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getNewsInfo(); // ListView lv = (ListView) findViewById(R.id.lv); // //要保證在設(shè)置適配器時(shí),新聞xml文件已經(jīng)解析完畢了 // lv.setAdapter(new MyAdapter());}class MyAdapter extends BaseAdapter{//得到模型層中元素的數(shù)量,用來確定listview需要有多少個(gè)條目@Overridepublic int getCount() {// TODO Auto-generated method stubreturn newsList.size();}@Override//返回一個(gè)View對(duì)象,作為listview的條目顯示至界面public View getView(int position, View convertView, ViewGroup parent) {News news = newsList.get(position);View v = null;ViewHolder mHolder;if(convertView == null){v = View.inflate(MainActivity.this, R.layout.item_listview, null);mHolder = new ViewHolder();//把布局文件中所有組件的對(duì)象封裝至ViewHolder對(duì)象中mHolder.tv_title = (TextView) v.findViewById(R.id.tv_title);mHolder.tv_detail = (TextView) v.findViewById(R.id.tv_detail);mHolder.tv_comment = (TextView) v.findViewById(R.id.tv_comment);mHolder.siv = (SmartImageView) v.findViewById(R.id.iv);//把ViewHolder對(duì)象封裝至View對(duì)象中v.setTag(mHolder);}else{v = convertView;mHolder = (ViewHolder) v.getTag();}//給三個(gè)文本框設(shè)置內(nèi)容mHolder.tv_title.setText(news.getTitle());mHolder.tv_detail.setText(news.getDetail());mHolder.tv_comment.setText(news.getComment() + "條評(píng)論");//給新聞圖片imageview設(shè)置內(nèi)容mHolder.siv.setImageUrl(news.getImageUrl());return v;}class ViewHolder{//條目的布局文件中有什么組件,這里就定義什么屬性TextView tv_title;TextView tv_detail;TextView tv_comment;SmartImageView siv;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}}private void getNewsInfo() {Thread t = new Thread(){@Overridepublic void run() {String path = "http://192.168.13.13:8080/news.xml";try {URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);//發(fā)送http GET請(qǐng)求,獲取相應(yīng)碼if(conn.getResponseCode() == 200){InputStream is = conn.getInputStream();//使用pull解析器,解析這個(gè)流parseNewsXml(is);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}};t.start();}private void parseNewsXml(InputStream is) {XmlPullParser xp = Xml.newPullParser();try {xp.setInput(is, "utf-8");//對(duì)節(jié)點(diǎn)的事件類型進(jìn)行判斷,就可以知道當(dāng)前節(jié)點(diǎn)是什么節(jié)點(diǎn)int type = xp.getEventType();News news = null;while(type != XmlPullParser.END_DOCUMENT){switch (type) {case XmlPullParser.START_TAG:if("newslist".equals(xp.getName())){newsList = new ArrayList<News>();}else if("news".equals(xp.getName())){news = new News();}else if("title".equals(xp.getName())){String title = xp.nextText();news.setTitle(title);}else if("detail".equals(xp.getName())){String detail = xp.nextText();news.setDetail(detail);}else if("comment".equals(xp.getName())){String comment = xp.nextText();news.setComment(comment);}else if("image".equals(xp.getName())){String image = xp.nextText();news.setImageUrl(image);}break;case XmlPullParser.END_TAG:if("news".equals(xp.getName())){newsList.add(news);}break;}//解析完當(dāng)前節(jié)點(diǎn)后,把指針移動(dòng)至下一個(gè)節(jié)點(diǎn),并返回它的事件類型type = xp.next();}//發(fā)消息,讓主線程設(shè)置listview的適配器,如果消息不需要攜帶數(shù)據(jù),可以發(fā)送空消息handler.sendEmptyMessage(1);// for (News n : newsList) { // System.out.println(n.toString()); // }} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}3.1 案例5:新聞客戶端
public class MainActivity extends Activity {List<News> newsList;Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {ListView lv = (ListView) findViewById(R.id.lv);lv.setAdapter(new MyAdapter());}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getNewsInfo(); // ListView lv = (ListView) findViewById(R.id.lv); // //要保證在設(shè)置適配器時(shí),新聞xml文件已經(jīng)解析完畢了 // lv.setAdapter(new MyAdapter());}class MyAdapter extends BaseAdapter{//得到模型層中元素的數(shù)量,用來確定listview需要有多少個(gè)條目@Overridepublic int getCount() {// TODO Auto-generated method stubreturn newsList.size();}@Override//返回一個(gè)View對(duì)象,作為listview的條目顯示至界面public View getView(int position, View convertView, ViewGroup parent) {News news = newsList.get(position);View v = null;ViewHolder mHolder;if(convertView == null){v = View.inflate(MainActivity.this, R.layout.item_listview, null);mHolder = new ViewHolder();//把布局文件中所有組件的對(duì)象封裝至ViewHolder對(duì)象中mHolder.tv_title = (TextView) v.findViewById(R.id.tv_title);mHolder.tv_detail = (TextView) v.findViewById(R.id.tv_detail);mHolder.tv_comment = (TextView) v.findViewById(R.id.tv_comment);mHolder.siv = (SmartImageView) v.findViewById(R.id.iv);//把ViewHolder對(duì)象封裝至View對(duì)象中v.setTag(mHolder);}else{v = convertView;mHolder = (ViewHolder) v.getTag();}//給三個(gè)文本框設(shè)置內(nèi)容mHolder.tv_title.setText(news.getTitle());mHolder.tv_detail.setText(news.getDetail());mHolder.tv_comment.setText(news.getComment() + "條評(píng)論");//給新聞圖片imageview設(shè)置內(nèi)容mHolder.siv.setImageUrl(news.getImageUrl());return v;}class ViewHolder{//條目的布局文件中有什么組件,這里就定義什么屬性TextView tv_title;TextView tv_detail;TextView tv_comment;SmartImageView siv;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}}private void getNewsInfo() {Thread t = new Thread(){@Overridepublic void run() {String path = "http://192.168.13.13:8080/news.xml";try {URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);//發(fā)送http GET請(qǐng)求,獲取相應(yīng)碼if(conn.getResponseCode() == 200){InputStream is = conn.getInputStream();//使用pull解析器,解析這個(gè)流parseNewsXml(is);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}};t.start();}private void parseNewsXml(InputStream is) {XmlPullParser xp = Xml.newPullParser();try {xp.setInput(is, "utf-8");//對(duì)節(jié)點(diǎn)的事件類型進(jìn)行判斷,就可以知道當(dāng)前節(jié)點(diǎn)是什么節(jié)點(diǎn)int type = xp.getEventType();News news = null;while(type != XmlPullParser.END_DOCUMENT){switch (type) {case XmlPullParser.START_TAG:if("newslist".equals(xp.getName())){newsList = new ArrayList<News>();}else if("news".equals(xp.getName())){news = new News();}else if("title".equals(xp.getName())){String title = xp.nextText();news.setTitle(title);}else if("detail".equals(xp.getName())){String detail = xp.nextText();news.setDetail(detail);}else if("comment".equals(xp.getName())){String comment = xp.nextText();news.setComment(comment);}else if("image".equals(xp.getName())){String image = xp.nextText();news.setImageUrl(image);}break;case XmlPullParser.END_TAG:if("news".equals(xp.getName())){newsList.add(news);}break;}//解析完當(dāng)前節(jié)點(diǎn)后,把指針移動(dòng)至下一個(gè)節(jié)點(diǎn),并返回它的事件類型type = xp.next();}//發(fā)消息,讓主線程設(shè)置listview的適配器,如果消息不需要攜帶數(shù)據(jù),可以發(fā)送空消息handler.sendEmptyMessage(1);// for (News n : newsList) { // System.out.println(n.toString()); // }} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}4. Html源文件查看器
- 發(fā)送GET請(qǐng)求
- 獲取服務(wù)器返回的流,從流中把html源碼讀取出來
4.1 亂碼的處理
- 亂碼的出現(xiàn)是因?yàn)榉?wù)器和客戶端碼表不一致導(dǎo)致
4.2 案例4:HTML源文件查看器
public class MainActivity extends Activity {Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {TextView tv = (TextView) findViewById(R.id.tv);tv.setText((String)msg.obj);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){Thread t = new Thread(){@Overridepublic void run() {String path = "http://192.168.13.13:8080/baidu.html";try {URL url = new URL(path);//獲取連接對(duì)象,此時(shí)還未建立連接HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);//先建立連接,然后獲取響應(yīng)碼if(conn.getResponseCode() == 200){//拿到服務(wù)器返回的輸入流,流里的數(shù)據(jù)就是html的源文件InputStream is = conn.getInputStream();//從流里把文本數(shù)據(jù)取出來String text = Utils.getTextFromStream(is);//發(fā)送消息,讓主線程刷新ui,顯示源文件Message msg = handler.obtainMessage();msg.obj = text;handler.sendMessage(msg);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}};t.start();}}5. 提交數(shù)據(jù)
5.1 GET方式提交數(shù)據(jù)
- get方式提交的數(shù)據(jù)是直接拼接在url的末尾
- 發(fā)送get請(qǐng)求,代碼和之前一樣
- 瀏覽器在發(fā)送請(qǐng)求攜帶數(shù)據(jù)時(shí)會(huì)對(duì)數(shù)據(jù)進(jìn)行URL編碼,我們寫代碼時(shí)也需要為中文進(jìn)行URL編碼
5.2 案例6:使用get方式提交數(shù)據(jù)
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();}};public void click(View v){EditText et_name = (EditText) findViewById(R.id.et_name);EditText et_pass = (EditText) findViewById(R.id.et_pass);final String name = et_name.getText().toString();final String pass = et_pass.getText().toString();Thread t = new Thread(){@Overridepublic void run() {//提交的數(shù)據(jù)需要經(jīng)過url編碼,英文和數(shù)字編碼后不變@SuppressWarnings("deprecation")String path = "http://192.168.13.13/Web2/servlet/LoginServlet?name=" + URLEncoder.encode(name) + "&pass=" + pass;try {URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);if(conn.getResponseCode() == 200){InputStream is =conn.getInputStream();String text = Utils.getTextFromStream(is);Message msg = handler.obtainMessage();msg.obj = text;handler.sendMessage(msg);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}};t.start();}} public class Utils {public static String getTextFromStream(InputStream is){byte[] b = new byte[1024];int len = 0;//創(chuàng)建字節(jié)數(shù)組輸出流,讀取輸入流的文本數(shù)據(jù)時(shí),同步把數(shù)據(jù)寫入數(shù)組輸出流ByteArrayOutputStream bos = new ByteArrayOutputStream();try {while((len = is.read(b)) != -1){bos.write(b, 0, len);}//把字節(jié)數(shù)組輸出流里的數(shù)據(jù)轉(zhuǎn)換成字節(jié)數(shù)組String text = new String(bos.toByteArray());return text;} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;} }5.3 POST方式提交數(shù)據(jù)
- post提交數(shù)據(jù)是用流寫給服務(wù)器的
- 協(xié)議頭中多了兩個(gè)屬性
- Content-Type: application/x-www-form-urlencoded,描述提交的數(shù)據(jù)的mimetype
- Content-Length: 32,描述提交的數(shù)據(jù)的長(zhǎng)度
- 設(shè)置允許打開post請(qǐng)求的流
- 獲取連接對(duì)象的輸出流,往流里寫要提交給服務(wù)器的數(shù)據(jù)
5.4 案例7:使用post方式提交數(shù)據(jù)
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();}};public void click(View v){EditText et_name = (EditText) findViewById(R.id.et_name);EditText et_pass = (EditText) findViewById(R.id.et_pass);final String name = et_name.getText().toString();final String pass = et_pass.getText().toString();Thread t = new Thread(){@Overridepublic void run() {//提交的數(shù)據(jù)需要經(jīng)過url編碼,英文和數(shù)字編碼后不變@SuppressWarnings("deprecation")String path = "http://192.168.13.13/Web2/servlet/LoginServlet";try {URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("POST");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);//拼接出要提交的數(shù)據(jù)的字符串String data = "name=" + URLEncoder.encode(name) + "&pass=" + pass;//添加post請(qǐng)求的兩行屬性conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");conn.setRequestProperty("Content-Length", data.length() + "");//設(shè)置打開輸出流conn.setDoOutput(true);//拿到輸出流OutputStream os = conn.getOutputStream();//使用輸出流往服務(wù)器提交數(shù)據(jù)os.write(data.getBytes());if(conn.getResponseCode() == 200){InputStream is = conn.getInputStream();String text = Utils.getTextFromStream(is);Message msg = handler.obtainMessage();msg.obj = text;handler.sendMessage(msg);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}};t.start();} }6. 網(wǎng)絡(luò)請(qǐng)求
6.1 主線程阻塞
- UI停止刷新,應(yīng)用無法響應(yīng)用戶操作
- 耗時(shí)操作不應(yīng)該在主線程進(jìn)行
ANR
- application not responding
- 應(yīng)用無響應(yīng)異常
- 主線程阻塞時(shí)間過長(zhǎng),就會(huì)拋出ANR
主線程又稱UI線程,因?yàn)橹挥性谥骶€程中,才能刷新UI
6.2 消息隊(duì)列機(jī)制
- 主線程創(chuàng)建時(shí),系統(tǒng)會(huì)同時(shí)創(chuàng)建消息隊(duì)列對(duì)象(MessageQueue)和消息輪詢器對(duì)象(Looper)
- 輪詢器的作用,就是不停的檢測(cè)消息隊(duì)列中是否有消息(Message)
- 消息隊(duì)列一旦有消息,輪詢器會(huì)把消息對(duì)象傳給消息處理器(Handler),處理器會(huì)調(diào)用handleMessage方法來處理這條消息,handleMessage方法運(yùn)行在主線程中,所以可以刷新ui
- 總結(jié):只要消息隊(duì)列有消息,handleMessage方法就會(huì)調(diào)用
- 子線程如果需要刷新ui,只需要往消息隊(duì)列中發(fā)一條消息,觸發(fā)handleMessage方法即可
- 子線程使用處理器對(duì)象的sendMessage方法發(fā)送消息
總結(jié)
以上是生活随笔為你收集整理的Android应用开发:网络编程-1的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android应用开发-快速入门
- 下一篇: Android应用开发:网络编程-2