編輯:關於Android編程
平時的一些Android學習視頻中,他們都是基於Android2.2的去使用ListView,我看到都是會在UI線程中去訪問網絡獲取數據,但是這在Android4.0之後是行不通的。
首先我們來理一下思緒:
我們需要從網絡上下載一份xml數據,裡面包含了需要顯示的文字和圖片路徑。所以我們首先需要的就是先去下載數據,下載數據完成之後再在Adapter中顯示圖片的時候去下載圖片,然後顯示出來。這是基本的思路。但是做著做著會發現一些問題,比如,我們如何能保證數據下載完全,才去綁定適配器和數據他們。然後假如我們是在一條子線程中去完成下載數據,下載完成之後再去綁定適配器,這樣子貌似可以,但是會發現有一些問題,我們需要自定義適配器然後去更新ImageView,這就需要使用到Handler。那麼下載完成綁定適配器,如何再在適配器中去更新UI呢,這時候的適配器是運行在子線程的,假如把Ui線程的handler作為參數給了adapter,那麼宅adapter裡面發送消息給UI的handler,可以UI的handler如何找的到屬於ListView的一個Item的ImageView,所以這個行不通。
所以正確的做法應該是:我們應該在UI線程綁定適配器,我們先使用沒有值的List傳給adapter,這時候適配器就運行在UI線程了,同時在UI線程中啟動一條線程去下載數據,假如下載完成,則發送使用Handler發送一條消息,這時候handler應該使用的是adapter中的handler,因為adapter是運行在UI線程,不需要再有Looper,直接使用Handler的handlerMessage()就好。然後在adapter的getView方法中,在開啟一條線程去完成圖片的下載,假如下載完成,則使用adapter的handler發送一條消息,定義一個tag顯示下載完成。假如下載失敗則發送一個空消息,what為-1這樣,就能在adapter的Handler中去處理ImageView,然後更新它了。這就是大概的思路,下面請看源碼分析:
MainActivity.java他的主要功能是綁定數據和適配器,ListView和適配器,啟動一條線程去現在.xml文件
public class MainActivity extends Activity { private ListView listview;//顯示數據的ListView @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); File cache = new File(Environment.getExternalStorageDirectory(), "cahce");//創建緩存的目錄文件夾 if (!cache.exists()) cache.mkdirs(); listview = (ListView)findViewById(R.id.listview);//找到ListView ListListAdapter.java,他的功能主要是把數據顯示在ListVIew上,然後其中需要啟動線程去下載圖片,有關於這個listview的消息都需要通過該handler發送然後達到這裡去處理。data = new ArrayList ();//首先使用空的data ListViewAdapter adapter = new ListViewAdapter(this,R.layout.item_listview,data,cache);//綁定適配器,這時候就使得適配器運行在UI線程中 listview.setAdapter(adapter);//綁定ListView和適配器 new MyThread().start();//啟動線程去下載.xml數據 } } class MyThread extends Thread { @Override public void run() { try { ContacesService.getContacts(ListViewAdapter.mHandler);//下載.xml數據 } catch (Exception e) { ListViewAdapter.mHandler.sendEmptyMessage(-1);//有異常則利用,必須只能利用adapter的handler去發送一條消息通知下載失敗 e.printStackTrace(); } } }
public class ListViewAdapter extends BaseAdapter { private static final int OK = 2;//圖片下載完成msg.what=1 private static final int FAILE = -1;//圖片下載失敗msg.what=-1 private static ImageView image; private File cache; @SuppressLint("HandlerLeak") public static Handler mHandler = new Handler()//數據UI的Handler { @SuppressWarnings("unchecked") public void handleMessage(android.os.Message msg) { if(msg.what == 1) { data.addAll((List) msg.obj);//數據下載完成則更新data } if(image!= null && msg.what == OK) { image.setImageURI((Uri) msg.obj);//圖片下載完成則更新ImageView } }; }; private static List data;//數據 private int itemListviewl;//layout的id private LayoutInflater inflater;//layout填充器 public ListViewAdapter (Activity mainActivity , int itemListview , List data,File cache) { ListViewAdapter.data = data; this.itemListviewl = itemListview; this.cache = cache; inflater = (LayoutInflater) mainActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } //獲得item的總數目 @Override public int getCount() { return data.size(); } //獲得某一個item的數據 @Override public Object getItem(int position) { return data.get(position); } //獲得某一個item所在數據中的位置 @Override public long getItemId(int position) { return position; } //每一次需要顯示在ListView的條目都會調用該方法,來獲得一個view然後把對應的數據顯示出來 @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView == null) { convertView = inflater.inflate(itemListviewl, null); holder = new ViewHolder(); holder.imageView = (ImageView)convertView.findViewById(R.id.imageview); holder.textview = (TextView)convertView.findViewById(R.id.textView); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } Contacts contact = data.get(position); holder.textview.setText(contact.name); asyncTask(contact.path,holder.imageView,cache); return convertView; } /** * 下載圖片 * @param path 下載路徑 * @param imageView 下載圖片需要顯示的ImageView * @param cache 下載圖片需要保存的文件夾 */ private void asyncTask(final String path, final ImageView imageView,final File cache) { Runnable runnable = new Runnable() { public void run() { try { Uri uri = ContacesService.getImage(path,cache); System.out.println("uri="+uri); if(uri != null) { Message msg = Message.obtain(); msg.what = OK; msg.obj = uri; image = imageView; mHandler.sendMessage(msg);//下載成功發送消息 } else { mHandler.sendEmptyMessage(FAILE);//下載失敗發送消息 } } catch (Exception e) { mHandler.sendEmptyMessage(FAILE);//下載失敗發送消息 e.printStackTrace(); } } }; new Thread(runnable).start();//啟動線程開始下載 } /** * 當條目多的時候用於增加性能 * @author Administrator * */ class ViewHolder { ImageView imageView; TextView textview; } }
/** * 各種數據的下載實現類 * * @author Administrator * */ public class ContacesService { /** * 下載.xml文件的驅動類 * * @param handler * 需要發送消息的adapter中的handler * @throws Exception */ public static void getContacts(Handler handler) throws Exception { String path = "http://192.168.1.101:8080/web/list.xml"; HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if (200 == conn.getResponseCode()) { System.out.println("11111"); InputStream inputStream = conn.getInputStream(); parserXML(inputStream, handler); } } /** * 下載並且解析.xml文件 生成一個集合利用handler發送給adapter處理 * * @param inputStream * 輸入流 * @param handler需要發送消息的adapter中的handler * @throws Exception * @throws IOException */ private static void parserXML(InputStream inputStream, Handler handler) throws Exception, IOException { XmlPullParser parser = Xml.newPullParser(); parser.setInput(inputStream, "UTF-8"); Listdomai類contacts = new ArrayList (); System.out.println(2222); Contacts contact = null; int event = parser.getEventType(); while (XmlPullParser.END_DOCUMENT != event) { switch (event) { case XmlPullParser.START_TAG: if ("contact".equals(parser.getName())) { contact = new Contacts(); contact.id = Integer.valueOf(parser.getAttributeValue(0)); } if ("name".equals(parser.getName())) { contact.name = parser.nextText(); } if ("image".equals(parser.getName())) { contact.path = parser.getAttributeValue(0); } break; case XmlPullParser.END_TAG: if ("contact".equals(parser.getName())) { contacts.add(contact); contact = null; } break; } event = parser.next(); } if (contacts.size() != 0) { Message msg = Message.obtain(); msg.what = 1; msg.obj = contacts; System.out.println(contacts);// 用於測試是否下載成功 handler.sendMessage(msg);// 發送adapter,讓他去更新data的值 } else { handler.sendEmptyMessage(-1);// 失敗發送-1 } } /** * 實現從網絡下載圖片並且保存本地,當本地存在該圖片則直接讀取 * * @param path * 圖片的路徑 * @param cache * 緩存二棟目錄 * @return * @throws Exception */ public static Uri getImage(String path, File cache) throws Exception { File localFile = new File(cache, MD5.getMD5(path) + path.substring(path.lastIndexOf(".")));// MD // 5加密 if (localFile.exists()) { return Uri.fromFile(localFile); } else { HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if (200 == conn.getResponseCode()) { System.out.println("11111"); InputStream inputStream = conn.getInputStream(); FileOutputStream fos = new FileOutputStream(localFile); int len; byte[] buffer = new byte[1024]; while ((len = inputStream.read(buffer)) != -1) { fos.write(buffer, 0, len); } fos.close(); inputStream.close(); return Uri.fromFile(localFile); } } return null; } }
public class Contacts { public int id; public String name; public String path; public Contacts (){} public Contacts (int id , String name , String path) { super(); this.id = id; this.name = name; this.path = path; } @Override public String toString() { return "Contacts [id=" + id + ", name=" + name + ", path=" + path + "]"; } }
public class MD5 { public static String getMD5(String content) { try { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(content.getBytes()); return getHashString(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } private static String getHashString(MessageDigest digest) { StringBuilder builder = new StringBuilder(); for (byte b : digest.digest()) { builder.append(Integer.toHexString((b >> 4) & 0xf)); builder.append(Integer.toHexString(b & 0xf)); } return builder.toString(); } }關於布局:main.xml
item.xml
最後得到的結果截圖:
Introduction 在Android中, 每個應用程序都運行在自己的進程中,擁有獨立的內存空間。但是有些時候我們的應用程序需要跟其它的應用程序進行通信,這個時候該
前言 最近項目做用戶登錄模塊需要一個右邊帶圖片的EditText,圖片可以設置點擊效果,所以就查資料做了一個自定義EditText出來,方便以後復用。原理 下面是自定
本文實例講述了Android開發之ListView列表刷新和加載更多實現方法。分享給大家供大家參考。具體如下:上下拉實現刷新和加載更多的ListView,如下:packa
先說一下adb命令配置,如果遇到adb不是內部或外部命令,也不是可運行的程序或批量文件。配置下環境變量1、adb不是內部或外部命令,也不是可運行的程序或批量文件。解決辦法