1. 功能描述
这一讲中我们将对如何实现新闻列表做一个详细的介绍,新闻列表会把所有我们从网上获取的新闻的标题显示给用户,用户通过阅读标题,选择自己想要查看的新闻,进入具体的新闻显示页。
下图是我们设计的样式,最上方的按钮栏这边不再多做介绍了,相信看过前几章的读者已经如何实现这个按钮栏了。
按钮栏下方就是新闻列表,里面会显示一个ImageView 和 一个 TextView
ImageView: 1张图片
TextView: 新闻标题
如果列表长度超出当前屏幕大小,可上下拖动该列表。
2.界面布局
在layout 目录下分别创建 news_result_list.xml 和 news_result_list_item.xml布局文件.
news_result_list.xml: 整个页面的布局,包括上放的按钮栏 和 下方的列表控件
news_result_list_item.xml:列表控件中 单个ITEM 的布局,所谓单个ITEM 就是类似如下图就是单个的ITEM
下面让我们先来看下news_result_list.xml 里面的代码:
1 2 <?xml version="1.0" encoding="utf-8"?> 3 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 4 android:orientation="vertical" 5 android:layout_width="fill_parent" 6 android:layout_height="fill_parent" 7 android:background="@color/white"> 8 //按钮栏布局,上篇课程已经讲解过,这里不再多做介绍 9 <RelativeLayout android:id="@+id/result_RelativeLayout01" 10 android:layout_width="fill_parent" 11 android:layout_height="wrap_content" 12 android:background="@color/yellow"> 13 <Button android:id="@+id/result_back" //定义了一个新的 ID result_back 14 android:layout_width="wrap_content" 15 android:layout_height="wrap_content" 16 android:layout_alignParentLeft="true" 17 android:paddingLeft="2dip" 18 android:text="@string/back"/> 19 //定义了一个新的 ID result_collection 20 <Button android:id="@+id/result_collection" 21 android:layout_width="wrap_content" 22 android:layout_height="wrap_content" 23 android:layout_alignParentRight="true" 24 android:paddingRight="2dip" 25 android:text="@string/collection"/> 26 </RelativeLayout> 27 28 // 开始定义ListView,给ListView的最外层定义一个LinearLayout 布局 29 <LinearLayout android:id="@+id/result_LinearLayout01" 30 android:layout_width="fill_parent" 31 android:layout_height="fill_parent" 32 android:padding="5dip" 33 android:orientation="vertical"> 34 // 定义一个RelativeLayout 布局 35 <RelativeLayout android:id="@+id/android:empty" 36 android:layout_width="fill_parent" 37 android:layout_height="wrap_content" 38 xmlns:android="http://schemas.android.com/apk/res/android"> 39 //定义一个TextView 用来显示诸如:数据读取中,不存在新闻数据 这类让用户了解现在软件运行状态的信息 40 <TextView android:id="@+id/newsResultListEmptyText" 41 android:layout_width="fill_parent" 42 android:gravity="center" //布局居中 43 android:layout_height="100dip" 44 //对应上层布局居中 45 android:layout_centerInParent="true" 46 android:text="@string/wait_loading" //默认显示内容 47 android:textColor="@color/black" //字体颜色 48 android:textStyle="bold"> //字体样式 49 </TextView> 50 </RelativeLayout> 51 // 定义ListView 控件,ID 设为 newsResultList 52 <ListView android:id="@+id/newsResultList" 53 android:cacheColorHint="#00000000" //这个属性可以有效防止滑动过程中,ITEM 颜色变黑 54 android:dividerHeight="1dip" //2个ITEM 之间的间隔距离 55 android:scrollbars="none" //是否显示滑动条,默认是显示,我们这里设置成不显示 56 android:divider="@color/semi_black" //2个ITEM 之间间隔条的颜色 57 android:layout_width="fill_parent" 58 android:layout_height="fill_parent"> 59 </ListView> 60 </LinearLayout> 61 62 </LinearLayout> 63
ListView 是整个ANDROID 中非常重要的一个内容,几乎每个应用程序都需要涌动啊 ListView,这里鉴于篇幅,我们只做和该应用相关的内容的介绍,稍后,我们会单独用一篇课程来讲解介绍ListView
这里我们只需要了解,定义使用ListView在xml布局文件中的常规写法就可以了。
在定义完整个页面的布局文件 news_result_list.xml 后,我就开始着手news_result_list_item.xml 文件,这个文件的布局就非常简单了, 因为它只需要标示一个ITEM 的内容,ListView会不断的使用这个布局来创建每个ITEM。
具体如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="horizontal" //注意这里定义的是 horizontal 的布局,也就是横向的 4 android:layout_width="fill_parent" 5 android:layout_height="50dip" 6 android:background="@color/white"> 7 //定义一个ImageView ID 为 result_newsImg 8 <ImageView android:id="@+id/result_newsImg" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:layout_gravity="center_vertical" //设置为布局剧中 12 android:src="@drawable/news_icon"/> //图片指向的目录 13 //定义一个 TextView ID 为 result_newsImg 14 <TextView android:id="@+id/result_newsTitle" 15 android:layout_width="fill_parent" 16 android:layout_height="wrap_content" 17 android:layout_gravity="center_vertical" //设置为布局剧中 18 android:padding="5dip" 19 android:textSize="15px" 20 android:textColor="@color/black" 21 android:textStyle="bold"/> 22 </LinearLayout>
这样,前台的布局文件我们就完成了,接下来着手后台的逻辑实现
3. 后台逻辑层
首先,我们定义一个集成Activity 的class newsResultListActivity.java
重写 onCreate 方法:
1 public String newsType = "0"; 2 public Context mContext; 3 4 public void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.news_result_list); 7 8 mContext = newsResultListActivity.this; 9 10 Intent aIntent = getIntent(); 11 Bundle aBundle = aIntent.getExtras(); 12 if(aBundle != null){ 13 //获取上一个Activity 传递过来的新闻类型参数 14 newsType = aBundle.getString(MyNewsReaderConstant.MAIN_NEWS_TYPE); 15 } 16 17 //显示一个loading框 18 startLoadingDialog(); 19 20 //获取页面上定义的控件资源,包括listview 21 findView(); 22 23 //开启一个线程用来获取网络新闻数据 24 Thread webThread = new Thread(new getWebData()); 25 webThread.start(); 26 }
上面的代码中多我们开启了一个新的线程用来从网络上获取新闻数据,因为这是一个比较耗时的动作,所以我们又在执行这个线程之前调用了一个方法 statLoadingDialog(), 用来显示一个loading的动画,这样用户就知道现在在读取数据,需要等待一段时间,
下面是这个方法的实现内容:
1 public ProgressDialog pd; 2 3 public void startLoadingDialog(){ 4 pd = ProgressDialog.show(newsResultListActivity.this, null, MyNewsReaderConstant.PROGRESS_ALERT_LOADING, true,true); 5 }
而方法fnidView 则获取页面控件资源,当然也包括ListView 控件
1 public Button result_back, result_collection; 2 //用来显示无新闻记录,或者请用户等待 一类的提示信息 3 public TextView newsResultListEmptyText; 4 public ListView newsResultList; //页面的ListView控件 5 6 public void findView(){ 7 8 result_back = (Button)this.findViewById(R.id.result_back); 9 result_collection = (Button)this.findViewById(R.id.result_collection); 10 newsResultListEmptyText = (TextView)this.findViewById(R.id.newsResultListEmptyText); 11 newsResultList = (ListView)this.findViewById(R.id.newsResultList); 12 13 }
这些都完成后就开启一个线程 getWebDate(),在这个线程内,我们通过定义在接口 getWebDataHelperI 中的 getNewsResultListByType()返回一个List,该List内保存有网络数据.
1 protected static final int threadS1 = 0x2311; 2 protected static final int threadF1 = 0x2312; 3 public List<newsDataTO> dataList; //存放数据的List 4 public getWebDataHelperI gwdhI; //实现网络功能的接口 5 6 public class getWebData implements Runnable{ 7 8 @Override 9 public void run() { 10 Message m1 = new Message(); 11 Message m2 = new Message(); 12 m1.what = threadS1; 13 m2.what = threadF1; 14 15 dataList = new ArrayList<newsDataTO>(); 16 boolean sendErrorMsg = false; 17 18 //searchValues 数组,用来存放网络查询参数 19 String[] searchColumns = {"type"}; 20 String[] searchValues = {newsType}; 21 //实例化这个借口 22 gwdhI = new getWebDataHelperImpl(); 23 //调用该接口的实现方法,把 searchColumnns, searchValues作为参数 24 dataList = gwdhI.getNewsResultListByType(searchColumns, searchValues); 25 //如果返回的List为空,发送错误消息 26 if(dataList == null || dataList.size() == 0){ 27 messageListener.sendMessage(m2); 28 return; 29 } 30 //List不为空,发送正确消息 31 messageListener.sendMessage(m1); 32 } 33 34 }
如果返回的List内有值的话,说明从网络上获取到了新闻的数据,然后发送消息 通知 Handler消息监听器 获取新闻数据成功,然后显示该新闻列表。如果返回的List 为空,则发送消息通知监听器 获取新闻数据失败,显示无法获取新闻的提示信息。
下面就是Handler 的代码:
1 Handler messageListener = new Handler(){ 2 3 public void handleMessage(Message msg){ 4 switch(msg.what){ 5 case threadS1: 6 pd.dismiss(); //关闭loading框 7 displayNewsResult(); //显示新闻列表 8 break; 9 case threadF1: 10 pd.dismiss(); //关闭loading框 11 //显示未能查询到记录的信息 12 newsResultListEmptyText.setVisibility(View.VISIBLE); 13 //显示提示信息,该信息定义在string.xml中的serverConnectErrorMsg newsResultListEmptyText.setText(getResources().getString(R.string.serverConnectErrorMsg)); 14 break; 15 } 16 } 17 };
里面有调用方法 displayNewsResult()来显示新闻列表, 这个方法里包括了自定义List,
1 public void displayNewsResult(){ 2 //当有返回新闻数据时,提示信息不用显示 设置为不可见,这样用户就看不到页面上 '请等待' 这些提示 3 newsResultListEmptyText.setVisibility(View.GONE); 4 //自定义一个 Adapter 5 newsResultListAdapter newsResultAdapter = new newsResultListAdapter(dataList, mContext); 6 //将自定义的Adapter set进newsResultList,该List就是页面上的 ListView控件 7 newsResultList.setAdapter(newsResultAdapter); 8 //给ListView控件添加 onItemClickListener 事件,使用户点击ITEM 的时候能触发事件 9 newsResultList.setOnItemClickListener(new OnItemClickListener(){ 10 @Override 11 public void onItemClick(AdapterView<?> arg0, View arg1, 12 int arg2, long arg3) { 13 // TODO Auto-generated method stub 14 15 } 16 17 }); 18 }
上面就是一个显示自定义ListView的大致的框架,不过这时候还无法显示新闻列表,因为你会发现有2个地方我们还没有详细说明
l newsResultListAdapter newsResultAdapter =
new newsResultListAdapter(dataList, mContext);
和
l gwdhI.getNewsResultListByType(searchColumns, searchValues);
另外我们还需要定义一个数据结构用来存储新闻内容:
1 public class newsDataTO { 2 private long id; //唯一的ID 3 private long newsId; //新闻的唯一的ID 4 private String newsType; //新闻的类型 5 private String newsTitle; //新闻的标题 6 private String newsContent; //新闻的内容 7 8 public long getId() { 9 return id; 10 } 11 public void setId(long id) { 12 this.id = id; 13 } 14 public long getNewsId() { 15 return newsId; 16 } 17 public void setNewsId(long newsId) { 18 this.newsId = newsId; 19 } 20 public String getNewsType() { 21 return newsType; 22 } 23 public void setNewsType(String newsType) { 24 this.newsType = newsType; 25 } 26 public String getNewsTitle() { 27 return newsTitle; 28 } 29 public void setNewsTitle(String newsTitle) { 30 this.newsTitle = newsTitle; 31 } 32 public String getNewsContent() { 33 return newsContent; 34 } 35 public void setNewsContent(String newsContent) { 36 this.newsContent = newsContent; 37 } 38 39 }
A. gwdhI.getNewsResultListByType(searchColumns, searchValues); 网络数据的获取
调用getNewsResultListByType() 我们传入了2个参数,一个是 searchColumns 用来存放网络查询字段的名称,另一个是searchValues 存放查询字段对应的值,这2个参数都是数组类型,见代码:
1 //searchValues 数组,用来存放网络查询参数 2 String[] searchColumns = {"type"}; 3 String[] searchValues = {newsType};
说明我们传入了一个 查询的字段type, 其值是newsType。
我们先创建接口文件:
getWebDataHelperI.java 下面定义一个接口 getNewsResultListByType
1 import java.util.List; 2 import com.thinkland.demo.mnr.data.newsDataTO; 3 4 public interface getWebDataHelperI { 5 6 public List<newsDataTO> getNewsResultListByType(String[] searchColumns, String[] searchValues); 7 8 }
接口内方法的实现:
1. 我们先处理传入的参数 String[] searchColumns 和 String[] searchValues
分别循环着2个数组,将获得的值,键值配对。在我们的示例代码中,最后得到的因该是type=4
下面是具体的代码
1 Map searchMap = new HashMap(); 2 //如果查询字段存放数组内有值,将 hashMap 的键设置成 查询的字段名字 3 if(searchColumns != null){ 4 for(int i = 0; i< searchColumns.length; i++){ 5 searchMap.put(searchColumns[i], ""); 6 } 7 } 8 //如果查询具体内容存放数组有值,将该值按顺序放入searchMap 的值中 9 if(searchValues != null){ 10 for(int ii = 0; ii< searchValues.length; ii++){ 11 //这里防止 value 超出了searchColumns 数组的范围 12 if(ii <= searchColumns.length){ 13 searchMap.put(searchColumns[ii], searchValues[ii]); 14 } 15 } 16 } 17 18 StringBuffer sb = new StringBuffer(); 19 sb.append(""); 20 Iterator it = searchMap.entrySet().iterator(); 21 while (it.hasNext()) { 22 Entry entry = (java.util.Map.Entry) it.next(); 23 sb.append("&"); 24 sb.append(entry.getKey()); // 返回与此项对应的键 25 sb.append("="); 26 sb.append(entry.getValue()); // 返回与此项对应的值 27 28 } 29 String searchUrlValue = sb.toString(); 30 if(searchUrlValue != null && !"".equals(searchUrlValue)){ 31 searchUrlValue = searchUrlValue.substring(1); //跳过开头的&符号,最后产生的查询参数因该是类似: parameter1=a¶meter2=b 32 } 33
我们使用测试用的URL 来获取数据: http://pic.think-land.com/xmlall.php?
配合参数最后查询的URL是: http://pic.think-land.com/xmlall.php?type=4
认识URL是进行网络编程的第一步。java.net.URL提供了丰富的URL构建方式,并可以通过java.net.URL来获取资源。类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。
我们可以通过下面的方法来获取URL指定的资源
1 URL connectUrl = new URL(“http://pic.think-land.com/xmlall.php?type=4”); 2 //返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。 3 URLConnection uc = connectUrl.openConnection(); 4 //打开的连接读取的输入流。 5 InputStream is = uc.getInputStream();
返回的是XML 格式的stream流
解析返回的XML,每个节点<row></row>内的内容就是一笔新闻资料,通过解析每一笔新闻内容都会保存进 newsDataTO 对象,然后add进List:
1 2 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); 3 DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); 4 5 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 6 int i=-1; 7 while((i=is.read())!=-1){ 8 baos.write(i); 9 } 10 String returnIs = baos.toString().trim(); 11 // Log.v("test", "-------------------- parseXML_rg returnIs is : \n" + returnIs); 12 InputStream iis = new ByteArrayInputStream(returnIs.getBytes()); 13 14 15 16 Document doc = docBuilder.parse(iis); 17 doc.getDocumentElement ().normalize (); 18 19 NodeList listOfTeams = doc.getElementsByTagName("row"); 20 21 for(int s=0; s<listOfTeams.getLength() ; s++){ 22 Node firstTeamNode = listOfTeams.item(s); 23 if(firstTeamNode.getNodeType() == Node.ELEMENT_NODE){ 24 25 Element firstTeamElement = (Element)firstTeamNode; 26 //实例化一个新的newsDataTO 27 newsDataTO ndTO = new newsDataTO(); 28 //通过节点获取到值,新闻的ID 29 String id = getValueByElement(firstTeamElement, "id"); 30 //通过节点获取到值,新闻的标题 31 String newsTitle = getValueByElementAfterUtf(firstTeamElement,"title"); 32 //保存进数据结构,通过set方法 33 ndTO.setId(Integer.parseInt(id)); 34 ndTO.setNewsId(Integer.parseInt(id)); 35 ndTO.setNewsTitle(newsTitle); 36 //将该数据结构添加进list 37 dataList.add(ndTO); 38 } 39 }
通过解析XML 里的节点来获取对应节点内存放的值。
这里需要注意的是如果值是中文字符的话,通常需要对字符进行一些编码,解码的处理,所以我们定义了2个解析节点的方法来处理不同的情况:
1 /** 2 * 根据节点获取内容 3 * @param element 4 * @param tagName 5 * @return String 6 */ 7 private String getValueByElement(Element element, String tagName){ 8 String returnValue = ""; 9 10 NodeList firstNameList = element.getElementsByTagName(tagName); 11 Element firstNameElement = (Element)firstNameList.item(0); 12 NodeList textList = firstNameElement.getChildNodes(); 13 if(textList != null && (Node)textList.item(0)== null){ 14 returnValue = ""; 15 }else if(textList != null && ((Node)textList.item(0)).getNodeValue() != null){ 16 returnValue = ((Node)textList.item(0)).getNodeValue().trim(); 17 } 18 return returnValue; 19 } 20 21 /** 22 * 根据节点获取内容,并对获取的值做 UTF-8 的编码处理,一般针对中文 23 * @param element 节点对象 24 * @param tagName 节点名字 25 * @return String 26 */ 27 private String getValueByElementAfterUtf(Element element, String tagName){ 28 String returnValue = ""; 29 NodeList firstNameList = element.getElementsByTagName(tagName); 30 Element firstNameElement = (Element)firstNameList.item(0); 31 NodeList textList = firstNameElement.getChildNodes(); 32 if(textList != null && ((Node)textList.item(0)).getNodeValue() != null){ 33 try { 34 //对该节点下的字节流进行 utf-8 解码 35 returnValue = new String( ((Node)textList.item(0)).getNodeValue().getBytes(), "utf-8"); 36 } catch (UnsupportedEncodingException e) { 37 e.printStackTrace(); 38 } catch (DOMException e) { 39 e.printStackTrace(); 40 } 41 } 42 return returnValue; 43 }
下面是完整的代码:
1 import java.io.ByteArrayInputStream; 2 import java.io.ByteArrayOutputStream; 3 import java.io.InputStream; 4 import java.io.UnsupportedEncodingException; 5 import java.net.URL; 6 import java.util.ArrayList; 7 import java.util.HashMap; 8 import java.util.Iterator; 9 import java.util.List; 10 import java.util.Map; 11 import java.util.Map.Entry; 12 13 import javax.xml.parsers.DocumentBuilder; 14 import javax.xml.parsers.DocumentBuilderFactory; 15 16 import org.w3c.dom.DOMException; 17 import org.w3c.dom.Document; 18 import org.w3c.dom.Element; 19 import org.w3c.dom.Node; 20 import org.w3c.dom.NodeList; 21 import org.xml.sax.SAXException; 22 import org.xml.sax.SAXParseException; 23 24 import android.util.Log; 25 26 import com.thinkland.demo.mnr.data.newsDataTO; 27 28 public class getWebDataHelperImpl implements getWebDataHelperI{ 29 30 public List<newsDataTO> getNewsResultListByType(String[] searchColumns, String[] searchValues) { 31 32 //测试用URL 地址 33 String netUrl = "http://pic.think-land.com/xmlall.php?"; 34 35 try{ 36 Map searchMap = new HashMap(); 37 //如果查询字段存放数组内有值,将 hashMap 的键设置成 查询的字段名字 38 if(searchColumns != null){ 39 for(int i = 0; i< searchColumns.length; i++){ 40 searchMap.put(searchColumns[i], ""); 41 } 42 } 43 //如果查询具体内容存放数组有值,将该值按顺序放入searchMap 的值中 44 if(searchValues != null){ 45 for(int ii = 0; ii< searchValues.length; ii++){ 46 //这里防止 value 超出了searchColumns 数组的范围 47 if(ii <= searchColumns.length){ 48 searchMap.put(searchColumns[ii], searchValues[ii]); 49 } 50 } 51 } 52 53 StringBuffer sb = new StringBuffer(); 54 sb.append(""); 55 Iterator it = searchMap.entrySet().iterator(); 56 while (it.hasNext()) { 57 Entry entry = (java.util.Map.Entry) it.next(); 58 sb.append("&"); 59 sb.append(entry.getKey()); // 返回与此项对应的键 60 sb.append("="); 61 sb.append(entry.getValue()); // 返回与此项对应的值 62 63 } 64 String searchUrlValue = sb.toString(); 65 if(searchUrlValue != null && !"".equals(searchUrlValue)){ 66 searchUrlValue = searchUrlValue.substring(1); //跳过开头的&符号,最后产生的查询参数因该是类似: parameter1=a¶meter2=b 67 } 68 Log.v("getWebDataHelperImp", "---------------------- searchUrlValue : " + searchUrlValue); 69 return netXMLPrase(netUrl + searchUrlValue); 70 71 }catch(Exception e){ 72 e.printStackTrace(); 73 } 74 75 return null; 76 } 77 78 public List netXMLPrase(String uriStr) throws Exception{ 79 try{ 80 List dataList = new ArrayList<newsDataTO>(); 81 82 URL connectUrl = new URL(uriStr); 83 //返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。 84 URLConnection uc = connectUrl.openConnection(); 85 //打开的连接读取的输入流。 86 InputStream is = uc.getInputStream(); 87 if(is == null){ 88 throw new Exception("netXMLPraseComicName - The inputStream is null"); 89 } 90 91 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); 92 DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); 93 94 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 95 int i=-1; 96 while((i=is.read())!=-1){ 97 baos.write(i); 98 } 99 String returnIs = baos.toString().trim(); 100 // Log.v("test", "-------------------- parseXML_rg returnIs is : \n" + returnIs); 101 InputStream iis = new ByteArrayInputStream(returnIs.getBytes()); 102 103 104 105 Document doc = docBuilder.parse(iis); 106 doc.getDocumentElement ().normalize (); 107 108 NodeList listOfTeams = doc.getElementsByTagName("row"); 109 110 for(int s=0; s<listOfTeams.getLength() ; s++){ 111 Node firstTeamNode = listOfTeams.item(s); 112 if(firstTeamNode.getNodeType() == Node.ELEMENT_NODE){ 113 114 Element firstTeamElement = (Element)firstTeamNode; 115 116 newsDataTO ndTO = new newsDataTO(); 117 118 String id = getValueByElement(firstTeamElement, "id"); 119 String newsTitle = getValueByElementAfterUtf(firstTeamElement,"title"); 120 121 ndTO.setId(Integer.parseInt(id)); 122 ndTO.setNewsId(Integer.parseInt(id)); 123 ndTO.setNewsTitle(newsTitle); 124 125 dataList.add(ndTO); 126 } 127 } 128 129 return dataList; 130 131 }catch (SAXParseException err) { 132 throw new Exception(err); 133 } catch (SAXException e) { 134 Exception x = e.getException(); 135 ((x == null) ? e : x).printStackTrace(); 136 throw new Exception(e); 137 } catch (Exception t) { 138 t.printStackTrace(); 139 throw new Exception(t); 140 } 141 } 142 143 144 /** 145 * 根据节点获取内容 146 * @param element 147 * @param tagName 148 * @return String 149 */ 150 private String getValueByElement(Element element, String tagName){ 151 String returnValue = ""; 152 153 NodeList firstNameList = element.getElementsByTagName(tagName); 154 Element firstNameElement = (Element)firstNameList.item(0); 155 NodeList textList = firstNameElement.getChildNodes(); 156 if(textList != null && (Node)textList.item(0)== null){ 157 returnValue = ""; 158 }else if(textList != null && ((Node)textList.item(0)).getNodeValue() != null){ 159 returnValue = ((Node)textList.item(0)).getNodeValue().trim(); 160 } 161 return returnValue; 162 } 163 164 /** 165 * 根据节点获取内容,并对获取的值做 UTF-8 的编码处理,一般针对中文 166 * @param element 167 * @param tagName 168 * @return String 169 */ 170 private String getValueByElementAfterUtf(Element element, String tagName){ 171 String returnValue = ""; 172 173 NodeList firstNameList = element.getElementsByTagName(tagName); 174 Element firstNameElement = (Element)firstNameList.item(0); 175 NodeList textList = firstNameElement.getChildNodes(); 176 if(textList != null && ((Node)textList.item(0)).getNodeValue() != null){ 177 try { 178 returnValue = new String( ((Node)textList.item(0)).getNodeValue().getBytes(), "utf-8"); 179 } catch (UnsupportedEncodingException e) { 180 e.printStackTrace(); 181 } catch (DOMException e) { 182 e.printStackTrace(); 183 } 184 } 185 return returnValue; 186 } 187 188 189 }
B. 自定义新闻列表
newsResultListAdapter newsResultAdapter =
new newsResultListAdapter(dataList, mContext);
在com.thinkland.demo.mnr.helper下新建一个类 newsResultListAdapter.java
继承 BaseAdapter,代码如下:
1 import java.util.List; 2 import com.thinkland.demo.mnr.R; 3 import com.thinkland.demo.mnr.data.newsDataTO; 4 import android.content.Context; 5 import android.view.LayoutInflater; 6 import android.view.View; 7 import android.view.ViewGroup; 8 import android.widget.BaseAdapter; 9 import android.widget.TextView; 10 11 public class newsResultListAdapter extends BaseAdapter{ 12 13 private String TAG = "newsResultListAdapter"; 14 private LayoutInflater mInflater; 15 private List<newsDataTO> item; 16 private Context context; 17 18 public newsResultListAdapter(List<newsDataTO> item, Context context) { 19 super(); 20 //从给定的context中获取 LayoutInflater 21 mInflater = LayoutInflater.from(context); 22 this.item = item; 23 this.context = context; 24 } 25 26 //item 的数量 27 public int getCount() { 28 return item.size(); 29 } 30 31 //获取item的实例对象,参数position通常都是指当前item的id 32 public newsDataTO getItem(int position) { 33 return item.get(position); 34 } 35 36 //获取当前item 的id 37 public long getItemId(int position) { 38 return position; 39 } 40 41 42 //实例化这个adapter时传入要显示的数据,然后用getView来显示每一个ListView的item 43 public View getView(int position, View convertView, ViewGroup parent) { 44 //将 news_result_list_item 转换为 view 45 if(convertView == null) { 46 convertView = mInflater.inflate(R.layout.news_result_list_item, null); 47 } 48 //获取 view里的 TextView 49 TextView newsTitle = (TextView) convertView.findViewById(R.id.result_newsTitle); 50 //获取对应的 newsDataTO 51 newsDataTO newsDatato = (newsDataTO)getItem(position); 52 //将存放在 该数据结构中的 新闻标题 在页面布局上显示 53 newsTitle.setText(newsDatato.getNewsTitle()); 54 55 return convertView; 56 } 57 58 } 59
adapter中最重要的是getView:
通过重写BaseAdapter中的方法,在实例化这个adapter时传入要显示的数据,然后用getView来显示每一个ListView的item,通过实例化刚才建立的View:convertView 传入要显示在当前位置的数据项,然后返回处理完毕的view。
再回过头看 newsResultListActivity 中的方法 displayNewsResult()
1 newsResultListAdapter newsResultAdapter = new newsResultListAdapter(dataList, mContext); 2 newsResultList.setAdapter(newsResultAdapter);
就是将返回的 newsResultAdapter 实例化的对象赋值后显示在ListView newsResultList 中.
4. Manifest 配置
a. 新增加一个Activity
1 <activity android:name=".newsResultListActivity"/>
b. 增加一个访问internet的权限
1 <uses-permission android:name="android.permission.INTERNET"/>
如果没有添加该权限,会出现如下的错误
catch (Exception e) 输出异常信息:
java.net.SocketException: Permission denied(maybe missing INTERNET permission)
5. 运行效果
a. 读取网络数据过程,显示loading……,同时提示用户耐心等待。
- 显示新闻列表内容