編輯:關於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;
}
}
/**
* 各種數據的下載實現類
*
* @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 + "]";
}
}
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
最後得到的結果截圖:


Android AIDL開發
Introduction 在Android中, 每個應用程序都運行在自己的進程中,擁有獨立的內存空間。但是有些時候我們的應用程序需要跟其它的應用程序進行通信,這個時候該
Android自定義EditText右側帶圖片控件
前言 最近項目做用戶登錄模塊需要一個右邊帶圖片的EditText,圖片可以設置點擊效果,所以就查資料做了一個自定義EditText出來,方便以後復用。原理 下面是自定
Android開發之ListView列表刷新和加載更多實現方法
本文實例講述了Android開發之ListView列表刷新和加載更多實現方法。分享給大家供大家參考。具體如下:上下拉實現刷新和加載更多的ListView,如下:packa
Android 用adb pull或push 拷貝手機文件到到電腦上,拷貝手機數據庫到電腦上,拷貝電腦數據庫到手機上
先說一下adb命令配置,如果遇到adb不是內部或外部命令,也不是可運行的程序或批量文件。配置下環境變量1、adb不是內部或外部命令,也不是可運行的程序或批量文件。解決辦法