Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 基於Android4.0ListView從網絡獲取圖片文字資源顯示

基於Android4.0ListView從網絡獲取圖片文字資源顯示

編輯:關於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
		List 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();
		}
	}
}
ListAdapter.java,他的功能主要是把數據顯示在ListVIew上,然後其中需要啟動線程去下載圖片,有關於這個listview的消息都需要通過該handler發送然後達到這裡去處理。

 

 

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;
	}
}

ContacesService.java,他的作用是把從網絡下載的數據封裝一起,下載各種數據,發送各種消息

 

 

/**
 * 各種數據的下載實現類
 * 
 * @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");
		List 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;
	}

}
domai類

 

 

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 + "]";
	}
}

然後是MD5加密命名類:

 

 

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



    

    


最後,由於需要訪問網絡以及從SD 卡寫入讀取數據,需要權限:

 

 


    
    

這樣就可以完成了。

 

最後得到的結果截圖:

\\

 

 

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved