編輯:關於Android編程
該例子實現的是從網絡上異步獲取數據,包括圖片與文字,然後顯示在listView中,並對圖片進行內存緩存。

第一次錄制gif。。。效果很差

主界面就一個listView
然後定義一個item_layout用於設置子項的布局也很簡單
根據對json數據的分析,我新建了一個實體類,三個屬性,一個是Tilte,一個是Content,一個是imageUrl
public class NewsBean {
private String mImageUrl;
private String mTitle;
private String mContent;
public String getmContent() {
return mContent;
}
public String getmTitle() {
return mTitle;
}
public String getmImageUrl() {
return mImageUrl;
}
public void setmImageUrl(String mImageUrl) {
this.mImageUrl = mImageUrl;
}
public void setmTitle(String mTitle) {
this.mTitle = mTitle;
}
public void setmContent(String mContent) {
this.mContent = mContent;
}
}
這裡用AsyncTask訪問網絡獲取到json,並解析json成NewsBean類型,在doInbackground方法裡面進行訪問,在onPostExecute方法裡面對ListView設置Adapter
class MyAsyncTask extends AsyncTask> { @Override protected List doInBackground(String... params) { List newsBeans = getJsonData(params[0]); return newsBeans; } @Override protected void onPostExecute(List newsBeen) { super.onPostExecute(newsBeen); mAdapter = new MyAdapter(newsBeen, MainActivity.this); mListView.setAdapter(mAdapter); } //根據url獲取json數據,返回集合 public List getJsonData(String url) { List newsBeens = new ArrayList<>(); try { String jsonString = readStream(new URL(url).openStream()); JSONObject object; NewsBean newsBean; object = new JSONObject(jsonString); JSONArray jsonArray = object.getJSONArray("data"); for (int i = 0; i < jsonArray.length(); i++) { newsBean = new NewsBean(); object = jsonArray.getJSONObject(i); newsBean.setmTitle(object.getString("name")); newsBean.setmContent(object.getString("description")); newsBean.setmImageUrl(object.getString("picSmall")); newsBeens.add(newsBean); } } catch (Exception e) { e.printStackTrace(); } return newsBeens; } public String readStream(InputStream in) { InputStreamReader isb; String result = ""; try { String line = ""; isb = new InputStreamReader(in, "UTF-8"); BufferedReader br = new BufferedReader(isb); while ((line = br.readLine()) != null) { result += line; } } catch (Exception e) { e.printStackTrace(); } return result; } }
通過調用ImageLoader提供的displayImageByAsyncTask(ImageView imageview,String url)方法,來加載圖片。定義NewsAsyncTask類來實現網絡加載圖片,定義一個LruCache(Least recently used 最近最少使用算法)來緩存圖片到內存中。如果第一次加載就通過網絡加載圖片,並添加到緩存中,再次加載如果緩存中存在就直接從緩存中獲取。這裡只做了內存緩存,當然也可以加上磁盤緩存。進行二級緩存。
public class ImageLoader {
;
private ImageView mImageView;
private String mUrl;
private LruCache mCache;
public ImageLoader() {
//新建緩存,緩存大小為系統內存的1/4
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheMemory = maxMemory / 4;
mCache = new LruCache(cacheMemory) {
@Override
//獲取每個緩存的大小,這裡為圖片的大小
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
};
}
//添加圖片到緩存中,LruCache的實質就是Map
public void addBitmapToCache(String url, Bitmap bitmap) {
if (getBitmapFromCache(url) == null) {
mCache.put(url, bitmap);
}
}
//從緩存中通過url獲取到緩存的圖片
public Bitmap getBitmapFromCache(String url) {
return mCache.get(url);
}
public void displayImageByAsyncTask(final ImageView imageView, final String url) {
Bitmap bitmap = getBitmapFromCache(url);
if (bitmap == null) {
//如果緩存中沒有,就從網絡加載
new NewsAsyncTask(imageView, url).execute(url);
} else {
//緩存中有的話直接使用緩存中的圖片
imageView.setImageBitmap(bitmap);
}
}
//通過url從網絡加載圖片的方法
public Bitmap getBitmapFromUrl(String url) {
Bitmap bitmap;
InputStream in = null;
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
in = connection.getInputStream();
//通過BitmapFactory的decodeStream方法可直接獲取到bitmap對象
bitmap = BitmapFactory.decodeStream(in);
//注意釋放資源
connection.disconnect();
return bitmap;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
private class NewsAsyncTask extends AsyncTask {
private ImageView mImageView;
private String mUrl;
public NewsAsyncTask(ImageView imageView, String url) {
//接收傳遞過來的image和url
mImageView = imageView;
mUrl = url;
}
@Override
protected Bitmap doInBackground(String... params) {
String url = params[0];
//從網絡加載圖片,如果加載到了就放到緩存中
Bitmap bitmap = getBitmapFromUrl(url);
if (bitmap != null) {
addBitmapToCache(url, bitmap);
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
//通過為imageView設置的Tag來與url比較,防止網絡不好時出現異步加載圖片錯位的問題
if (mImageView.getTag().equals(mUrl)) {
mImageView.setImageBitmap(bitmap);
}
}
}
}
關鍵點在於為imageView設置TAG,我們知道listView都是復用的,因此有時候網絡不好的時候,當一個View的圖片還沒加載完成時,他就被劃出了屏幕被再次復用,雖然位置不同,但是他們使用的都是同一個View,這時候可能就會先顯示之前沒加載好的圖片,然後再顯示當前需要顯示的圖片,這就出現了錯位。解決方法是為ImageView設置唯一標識比如加載的url。當被復用的時候,TAG會改變,這時候判斷一個TAG值,當前的與之前的TAG不一樣,因此就不加載之前的image,只需要加載目前需要現實的image。這樣在加載的時候就不會錯位了。
public class MyAdapter extends BaseAdapter{
private Context mContext;
private List mNews;
private LayoutInflater mInflater;
private ImageLoader mImageLoader;
public MyAdapter(List news,Context context){
mContext=context;
mNews=news;
mInflater=LayoutInflater.from(mContext);
//初始化ImageLoader,確保緩存只有一個
mImageLoader=new ImageLoader();
}
@Override
public int getCount() {
return mNews.size();
}
@Override
public Object getItem(int position) {
return mNews.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder mHolder;
if(convertView==null){
mHolder=new ViewHolder();
convertView=mInflater.inflate(R.layout.item_layout,null);
mHolder.mIconImageView= (ImageView) convertView.findViewById(R.id.item_iv_icon);
mHolder.mTitleTextView= (TextView) convertView.findViewById(R.id.item_tv_title);
mHolder.mContentTextView= (TextView) convertView.findViewById(R.id.item_tv_content);
convertView.setTag(mHolder);
}else {
mHolder= (ViewHolder) convertView.getTag();
}
mHolder.mIconImageView.setImageResource(R.mipmap.ic_launcher);
mImageLoader.displayImageByAsyncTask(mHolder.mIconImageView,mNews.get(position).getmImageUrl());
mHolder.mTitleTextView.setText(mNews.get(position).getmTitle());
mHolder.mContentTextView.setText(mNews.get(position).getmContent());
//為ImageView設置TAG為對應的url,防止圖片加載錯位
mHolder.mIconImageView.setTag(mNews.get(position).getmImageUrl());
return convertView;
}
class ViewHolder{
public TextView mContentTextView;
public TextView mTitleTextView;
public ImageView mIconImageView;
}
}
CSAPP第二次實驗 bomb二進制炸彈的破解
一個類似於破解的初級實驗。用到的gdb的指令並不多,只是基礎的使用和內存查看的指令。考的大多是匯編代碼的熟練程度和分析能力。不過有幾個函數長的讓人吐血。本著不輕易爆炸的原
Android - Earthquake(地震顯示器) 項目 詳解
Earthquake(地震顯示器) 項目 詳解 環境: Android Studio 0.5.2, Gradle 1.11, kindle f
Android------Intent.createChooser
Intent的匹配過程中有三個步驟,包括Action , category與data 的匹配。如果匹配出了多個結果,系統會顯示一個dialog讓用戶來選
Android軟鍵盤擋住輸入框的終極解決方案
前言開發做得久了,總免不了會遇到各種坑。而在Android開發的路上,『軟鍵盤擋住了輸入框』這個坑,可謂是一個曠日持久的巨坑——來來來,我們慢慢看。入門篇最基本的情況,如