編輯:關於Android編程
上次我們學習如何從網絡上獲取一張圖片,今天我們學習如何從網絡上獲取文本文件,以XML文件為例子。因為XML文件在實際開發中最為常見。
我們以下面圖片為例子學習如何從網絡上獲取XML文件
我們的xml文件為:
方案要求,從2015年2月1日起,基礎電信企業和虛擬運營商的各類營銷渠道在為用戶辦理電話入網手續時,停止人工錄入方式,改用專用移動應用程序 15687 http://192.168.1.100:8080/images/6.jpg中國制造”和“印度制造”正展開新一輪的競爭與合作關系。全球最大的代工企業、中國台灣的富士康8月8日在印度簽約,它到印度投資設廠的計劃變為現實 16359 http://192.168.1.100:8080/images/7.jpg8月8日,京東集團董事長兼CEO劉強東與奶茶妹妹的結婚證照片在朋友圈裡刷屏了。可就在前一天,劉強東還將自己未來十年的年薪降至1元 14112 http://192.168.1.100:8080/images/7.jpg
既然我們要將xml文件中的內容顯示到界面上,那必須先要拿到xml文件中的內容。
1: 從網絡上獲取XML文件的內容
開啟一個子線程從網絡上獲取服務器的數據
public void getNewsInfo() { //在子線程中獲取服務器的數據 Thread thread = new Thread(){ @Override public void run() { //1:確定地址 String path = http://192.168.1.123:8080/news.xml; 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(); //解析輸入流中的數據 parseXmlInfo(is); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; //啟動線程 thread.start(); }
public void parseXmlInfo(InputStream is) { /*我們用pull解析器解析xml文件*/ //1.先拿到pull解析器 XmlPullParser xParser = Xml.newPullParser(); try { xParser.setInput(is, utf-8); //獲取事件的類型 int eventType = xParser.getEventType(); News news = null; while(eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_TAG: //當事件的開始類型newslist,代表的是xml文件的數據開始 if(newslist.equals(xParser.getName())) { //這時候我們就new出來一個list,用於保存數據 newList = new ArrayList打印為:(); }//當事件類型是news,說明是一條新聞 else if (news.equals(xParser.getName())) { //new出一個news的對象 news = new News(); } else if (detail.equals(xParser.getName())) { String detail = xParser.nextText(); news.setDetail(detail); } else if (title.equals(xParser.getName())) { String title = xParser.nextText(); news.setTitle(title); } else if (comment.equals(xParser.getName())) { String comment = xParser.nextText(); news.setComment(comment); } else if (image.equals(xParser.getName())) { String image = xParser.nextText(); news.setImage(image); } break; case XmlPullParser.END_TAG: //當結束時間是news時,說明一條news已經解析完成,並且加入到集合中 if(news.equals(xParser.getName())) { newList.add(news); } break; } eventType = xParser.next(); } //打印 for (News n : newList) { System.out.println(n.toString()); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
可以看到我們是從服務器取到了數據,並且數據是正確的。
2: 既然可以正確的取到數據,那我們就將數據顯示到界面上,既然要顯示, 那就的用listview,既然要用listview,那就必須為listview的每一個增加一個布局文件
我們找到listview,然後設置Adapter即可
ListView lv = (ListView) findViewById(R.id.lv); lv.setAdapter(new MyAdapter());
class MyAdapter extends BaseAdapter { @Override public int getCount() { // TODO Auto-generated method stub return newList.size(); } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int arg0) { // TODO Auto-generated method stub return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { //取到一條新聞 News news = newList.get(position); //找到一個view對象 View v = View.inflate(MainActivity.this, R.layout.item_listview, null); //根據ID找到控件 TextView tv_title = (TextView) v.findViewById(R.id.tv_title); TextView tv_detail = (TextView) v.findViewById(R.id.tv_detail); TextView tv_comment = (TextView) v.findViewById(R.id.tv_comment); ImageView siv = (ImageView)v.findViewById(R.id.iv); //設置數據 tv_title.setText(news.getTitle()); tv_detail.setText(news.getDetail()); tv_comment.setText(news.getComment() + 條評論); siv.setImageResource(R.drawable.ic_launcher); return v; } }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getNewsInfo(); ListView lv = (ListView) findViewById(R.id.lv); lv.setAdapter(new MyAdapter()); }
運行效果為NULL指針異常,這是為什麼呢?
既然NULL指針異常,代碼是哪行有問題? 仔細一看是
lv.setAdapter(new MyAdapter());這是因為,我們的獲取服務器的數據是在一個子線程中運行的,而我們setAdapter的任務是在主線程中獲取的,這時候當我們的服務器數據還沒獲取完畢,我們就設置數據了,就會導致異常發生。所以我們要當服務器的數據獲取完後,才去設置adapter
修改代碼:增加消息機制
//當數據接受完成後,發生消息 handler.sendEmptyMessage(1); //打印 for (News n : newList) { System.out.println(n.toString()); }
//在消息中設置數據 Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { ListView lv = (ListView) findViewById(R.id.lv); lv.setAdapter(new MyAdapter()); }; };
這樣的話就出現了剛開始的截圖。但是我們還需要優化listview
優化後的listview
public View getView(int position, View convertView, ViewGroup parent) { News news = newList.get(position); ViewHolder mHolder; View v = null; //當緩沖為空的時候,創建view對象,並將組件封裝到view的tag中 if(convertView == null) { v = View.inflate(MainActivity.this, R.layout.item_listview, null); mHolder = new ViewHolder(); 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 = (ImageView)v.findViewById(R.id.iv); v.setTag(mHolder); } else {//當緩沖不為空時,就將緩沖的數據取出來用,不用重新創建,這樣可節省系統資源 v = convertView; mHolder =(ViewHolder) v.getTag(); } //設置數據到組件 mHolder.tv_title.setText(news.getTitle()); mHolder.tv_detail.setText(news.getDetail()); mHolder.tv_comment.setText(news.getComment() + 條評論); mHolder.siv.setImageResource(R.drawable.ic_launcher); return v; }
這樣我們的從服務端的獲取數據就算完成了,但是我們還沒獲取服務器的圖片資源,圖片資源是通過一個地址封裝到xml文件中的,我們需要再次拿到xml文件中的圖片地址再次請求服務器獲取圖片資源,關於如何獲取服務器圖片資源我上節都講過了,這裡就不做了。
下面是簡單的流程圖,從java到kernel層。 ShutdownThread.java文件 stop playing mus
關於ListView側滑刪除這是個老話題,大多數APP都具有這樣類似的功能,對於一位Android初涉者來說,實現這樣的功能確實有一點難度,網上的實現方法也層出不窮,我仔
0x00本文參考Android WebView 遠程代碼執行漏洞簡析。代碼地址為,https://github.com/jltxgcy/AppVulnerability/
效果: 代碼:https://github.com/ldb-github/Layout_Tab1、布局:使用LinearLayout布置標簽;再使用FrameL