編輯:關於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 LruCachemCache; 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 ListmNews; 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; } }
一個類似於破解的初級實驗。用到的gdb的指令並不多,只是基礎的使用和內存查看的指令。考的大多是匯編代碼的熟練程度和分析能力。不過有幾個函數長的讓人吐血。本著不輕易爆炸的原
Earthquake(地震顯示器) 項目 詳解 環境: Android Studio 0.5.2, Gradle 1.11, kindle f
Intent的匹配過程中有三個步驟,包括Action , category與data 的匹配。如果匹配出了多個結果,系統會顯示一個dialog讓用戶來選
前言開發做得久了,總免不了會遇到各種坑。而在Android開發的路上,『軟鍵盤擋住了輸入框』這個坑,可謂是一個曠日持久的巨坑——來來來,我們慢慢看。入門篇最基本的情況,如