首先,我就是用很容易理解的方法去實現這個功能。
在伺服器端,做一個index.php檔案,用來讀取MySQL資料庫的資訊:
index.php:
<?php
$link = mysql_connect("localhost", "root", "123456");
mysql_query("SET NAMES utf8");
mysql_select_db("test", $link); //test為資料庫名
$sql = mysql_query("select * from interp_images ", $link); //interp_images 為表名
while ($row = mysql_fetch_assoc($sql))
$output[] = $row;
print (json_encode($output));
mysql_close();
?>
這個PHP檔案執行得到的是從資料庫表讀取出來的所在資料數組。
程式的主代碼的一些詳解:
ListViewPerformaceActivity .java:
public class ListViewPerformaceActivity extends Activity {
protected static final String TAG = "ListViewPerformaceActivity";
/** Called when the activity is first created. */
private ListView mListview;
ImageLoader mImageLoader = new ImageLoader();
MyAdapter adapter;
private JSONArray jArray;
private String result = null;
private InputStream is = null;
private StringBuilder sb = null;
//private ListView mListView;
private View mView;
private String imageUrl;
private String imageDetailUrl;
private int ct_id;
private String ct_name;
private String ct_detail_name;
private JSONObject json_data = null;
private String[] fileUrl;
private String[] detailUrl;
private int count;
private Bitmap bitmap;
private byte buff[] = new byte[1024 * 250];
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// TODO http get
try {
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://192.168.18.29/Test/index.php");//IP為自己的伺服器的IP因為手機串連區域網路的WIFI,所以只用自己的電腦作為伺服器也可以測試效果。
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e) {
Log.e("log_tag", "2013Error in http connection" + e.toString());
}
// convert response to string
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);
sb = new StringBuilder();
sb.append(reader.readLine() + "\n");
String line = "0";
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e) {
e.printStackTrace();
Log.e("log_tag", "Error converting result " + e.toString());
}
// /////////////////////////////////////////////////////////////////////////////
// paring data
try {
jArray = new JSONArray(result);
// JSONObject json_data = null;
count = 0;
detailUrl = new String[jArray.length()];
fileUrl = new String[jArray.length()];
for (int i = 0; i < jArray.length(); i++) { //把讀取到資料庫表的資料通過for迴圈添加到數組裡
json_data = jArray.getJSONObject(i);
ct_id = json_data.getInt("categoryid");
ct_name = json_data.getString("androidfilename");
imageUrl = "http://192.168.18.29/Test/MyWebsiteImages/2013_07_to7szt75poNC/760x760/" + ct_name; //這裡只是把伺服器上的圖片路徑寫死了
fileUrl[count] = imageUrl;
ct_detail_name = json_data.getString("filename");
imageDetailUrl = "http://192.168.18.29/Test/MyWebsiteImages/2013_07_to7szt75poNC/760x760/"
+ ct_detail_name;
detailUrl[count] = imageDetailUrl;
count++;
}
} catch (JSONException e1) {
e1.printStackTrace();
} catch (ParseException e1) {
e1.printStackTrace();
}
setupViews();
}
private void setupViews() {
mListview = (ListView) findViewById(R.id.main_lv_list);
adapter = new MyAdapter(fileUrl, count, this);//這裡把從資料庫讀取出來的圖片URL傳給Adapter
mListview.setAdapter(adapter);
mListview.setOnScrollListener(mScrollListener);
// 添加ListView中Item的點擊事件,針對整個Item,如果Item布局不同的組件,對不同的組件添加不同的事件,剛要另外處理,我實現了這個功能,這裡就不多說,可以自己再找資料研究。
mListview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
setTitle("點擊第" + arg2 + "列" );
// bitmap = getBitmap(detailUrl[arg2]);
//
// buff = Bitmap2Bytes(bitmap);
// Intent mIntent = new Intent();
// mIntent.putExtra("image", buff);
// mIntent.setClass(ZhiXunActivity.this,
// ZhiXunDetailActivity.class);
// startActivity(mIntent);
}
});
}
OnScrollListener mScrollListener = new OnScrollListener() {//載入圖片的緩衝處理
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_FLING:
adapter.setFlagBusy(true);
break;
case OnScrollListener.SCROLL_STATE_IDLE:
adapter.setFlagBusy(false);
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
adapter.setFlagBusy(false);
break;
default:
break;
}
adapter.notifyDataSetChanged();
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
};
}
ImageLoader .java:
public class ImageLoader {
private static final String TAG = "ImageLoader";
private static final int MAX_CAPACITY = 10;// 一級緩衝的最大空間
private static final long DELAY_BEFORE_PURGE = 10 * 1000;// 定時清理緩衝
// 0.75是載入因子為經驗值,true則表示按照最近訪問量的高低排序,false則表示按照插入順序排序
private HashMap<String, Bitmap> mFirstLevelCache = new LinkedHashMap<String, Bitmap>(MAX_CAPACITY / 2, 0.75f, true) {
private static final long serialVersionUID = 1L;
protected boolean removeEldestEntry(Entry<String, Bitmap> eldest) {
if (size() > MAX_CAPACITY) {// 當超過一級緩衝閾值的時候,將老的值從一級緩衝搬到二級緩衝
mSecondLevelCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
return true;
}
return false;
};
};
// 二級緩衝,採用的是軟應用,只有在記憶體吃緊的時候軟應用才會被回收,有效避免了oom
private ConcurrentHashMap<String, SoftReference<Bitmap>> mSecondLevelCache = new ConcurrentHashMap<String, SoftReference<Bitmap>>(
MAX_CAPACITY / 2);
// 定時清理緩衝
private Runnable mClearCache = new Runnable() {
@Override
public void run() {
clear();
}
};
private Handler mPurgeHandler = new Handler();
// 重設緩衝清理的timer
private void resetPurgeTimer() {
mPurgeHandler.removeCallbacks(mClearCache);
mPurgeHandler.postDelayed(mClearCache, DELAY_BEFORE_PURGE);
}
/**
* 清理緩衝
*/
private void clear() {
mFirstLevelCache.clear();
mSecondLevelCache.clear();
}
/**
* 返回緩衝,如果沒有則返回null
*
* @param url
* @return
*/
public Bitmap getBitmapFromCache(String url) {
Bitmap bitmap = null;
bitmap = getFromFirstLevelCache(url);// 從一級緩衝中拿
if (bitmap != null) {
return bitmap;
}
bitmap = getFromSecondLevelCache(url);// 從二級緩衝中拿
return bitmap;
}
/**
* 從二級緩衝中拿
*
* @param url
* @return
*/
private Bitmap getFromSecondLevelCache(String url) {
Bitmap bitmap = null;
SoftReference<Bitmap> softReference = mSecondLevelCache.get(url);
if (softReference != null) {
bitmap = softReference.get();
if (bitmap == null) {// 由於記憶體吃緊,軟引用已經被gc回收了
mSecondLevelCache.remove(url);
}
}
return bitmap;
}
/**
* 從一級緩衝中拿
*
* @param url
* @return
*/
private Bitmap getFromFirstLevelCache(String url) {
Bitmap bitmap = null;
synchronized (mFirstLevelCache) {
bitmap = mFirstLevelCache.get(url);
if (bitmap != null) {// 將最近訪問的元素放到鏈的頭部,提高下一次訪問該元素的檢索速度(LRU演算法)
mFirstLevelCache.remove(url);
mFirstLevelCache.put(url, bitmap);
}
}
return bitmap;
}
/**
* 載入圖片,如果緩衝中有就直接從緩衝中拿,緩衝中沒有就下載
*
* @param url
* @param adapter
* @param holder
*/
public void loadImage(String url, BaseAdapter adapter, ViewHolder holder) {
resetPurgeTimer();
Bitmap bitmap = getBitmapFromCache(url);// 從緩衝中讀取
if (bitmap == null) {
holder.mImageView.setImageResource(R.drawable.ic_launcher);// 緩衝沒有設為預設圖片
ImageLoadTask imageLoadTask = new ImageLoadTask();
imageLoadTask.execute(url, adapter, holder);
} else {
holder.mImageView.setImageBitmap(bitmap);// 設為緩衝圖片
}
}
/**
* 放入緩衝
*
* @param url
* @param value
*/
public void addImage2Cache(String url, Bitmap value) {
if (value == null || url == null) {
return;
}
synchronized (mFirstLevelCache) {
mFirstLevelCache.put(url, value);
}
}
class ImageLoadTask extends AsyncTask<Object, Void, Bitmap> {
String url;
BaseAdapter adapter;
@Override
protected Bitmap doInBackground(Object... params) {
url = (String) params[0];
adapter = (BaseAdapter) params[1];
Bitmap drawable = loadImageFromInternet(url);// 擷取網狀圖片
return drawable;
}
@Override
protected void onPostExecute(Bitmap result) {
if (result == null) {
return;
}
addImage2Cache(url, result);// 放入緩衝
adapter.notifyDataSetChanged();// 觸發getView方法執行,這個時候getView實際上會拿到剛剛緩衝好的圖片
}
}
public Bitmap loadImageFromInternet(String url) {
Bitmap bitmap = null;
HttpClient client = AndroidHttpClient.newInstance("Android");
HttpParams params = client.getParams();
HttpConnectionParams.setConnectionTimeout(params, 3000);
HttpConnectionParams.setSocketBufferSize(params, 3000);
HttpResponse response = null;
InputStream inputStream = null;
HttpGet httpGet = null;
try {
httpGet = new HttpGet(url);
response = client.execute(httpGet);
int stateCode = response.getStatusLine().getStatusCode();
if (stateCode != HttpStatus.SC_OK) {
Log.d(TAG, "func [loadImage] stateCode=" + stateCode);
return bitmap;
}
HttpEntity entity = response.getEntity();
if (entity != null) {
try {
inputStream = entity.getContent();
return bitmap = BitmapFactory.decodeStream(inputStream);
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (ClientProtocolException e) {
httpGet.abort();
e.printStackTrace();
} catch (IOException e) {
httpGet.abort();
e.printStackTrace();
} finally {
((AndroidHttpClient) client).close();
}
return bitmap;
}
}
MyAdapter.java:
public class MyAdapter extends BaseAdapter {
private static final String TAG = "MyAdapter";
private boolean mBusy = false;
public void setFlagBusy(boolean busy) {
this.mBusy = busy;
}
private ImageLoader mImageLoader;
private int mCount;
private Context mContext;
String[] URLS;
public MyAdapter(String[] URLS, int count, Context context) {
this.URLS=URLS;
this.mCount = count;
this.mContext = context;
mImageLoader = new ImageLoader();
}
@Override
public int getCount() {
return mCount;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.d(TAG, "position=" + position + ",convertView=" + convertView);
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, null);// 這個過程相當耗時間
viewHolder = new ViewHolder();
viewHolder.mTextView = (TextView) convertView.findViewById(R.id.tv_tips);
viewHolder.mImageView = (ImageView) convertView.findViewById(R.id.iv_image);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
String url = "";
url = URLS[position % URLS.length];
if (!mBusy) {
mImageLoader.loadImage(url, this, viewHolder);
viewHolder.mTextView.setText("--" + position + "--IDLE ||TOUCH_SCROLL");
} else {
Bitmap bitmap = mImageLoader.getBitmapFromCache(url);
if (bitmap != null) {
viewHolder.mImageView.setImageBitmap(bitmap);
} else {
viewHolder.mImageView.setImageResource(R.drawable.ic_launcher);
}
viewHolder.mTextView.setText("--" + position + "--FLING");
}
return convertView;
}
static class ViewHolder {
TextView mTextView;
ImageView mImageView;
}
}