#Android异步加载图片

一、概述
Android中异步加载图片的方式有俩种,此文通过从服务器取出的Json数据后,通过这俩种方式去加载服务器的图片数据。

二、案例描述:
这里写图片描述

三、实现编码思路

1、写布局
2、取到服务器的Json转成JavaBean保存在List中当数据源
3、在适配器中把数据源对应显示在ListView
4、在适配器显示图片时开启异步线程去服务器读取照片
5、图片缓存优化下

1、布局xml文件代码

就一个简单的ListView + 每一个Item的布局

ListView在主布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.kuxiao.tran.studyActivity.MainActivity">

    <ListView
        android:id="@+id/id_lv_news"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>
每一个Item的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:padding="4dp"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_marginLeft="5dp"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:id="@+id/id_iv_icon"
        android:src="@mipmap/ic_launcher"/>

    <LinearLayout
        android:layout_marginLeft="3dp"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_marginTop="5dp"
            android:id="@+id/id_tv_title"
            android:textSize="18dp"
            android:text="标题"
            android:paddingLeft="3dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <TextView
            android:layout_marginTop="3dp"
            android:id="@+id/id_tv_context"
            android:textSize="15dp"
            android:paddingLeft="4dp"
            android:text="内容"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>

</LinearLayout>

2、取到服务器的Json转成JavaBean保存在List中当数据源

package com.kuxiao.tran.studyActivity;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.String;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ListView mListView;
    //访问服务器url
    private static final String url_news = "http://172.46.159.87:8080/News/NewsAction";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mListView = (ListView) findViewById(R.id.id_lv_news);
         new MyAsynctask().execute(url_news);

    }


     //利用异步线程访问服务取到数据源
    class MyAsynctask extends AsyncTask<String, Void, List<NewsBean>> {

        @Override
        protected List<NewsBean> doInBackground(String... params) {
            String url = params[0];

            return getNewsBean(url);
        }

        @Override
        protected void onPostExecute(List<NewsBean> newsBeans) {
                 MyAdapter  myAdapter = new MyAdapter(MainActivity.this,newsBeans);
                 mListView.setAdapter(myAdapter);

        }
    }

    //解析Json数据成NewsBean
    private List<NewsBean> getNewsBean(String url) {

        List<NewsBean> mList = new ArrayList<>();
        InputStream mIs = null;
        try {
            URL mUrl = new URL(url);
            mIs = mUrl.openStream();
            String json = getJsonFromInputStream(mIs);

            Log.i("text",json);
              JSONObject  jsonObject = new JSONObject(json);

            JSONArray  jsonArray  = jsonObject.getJSONArray("data");
            for (int i = 0; i <jsonArray.length();i++)
            {
                jsonObject = (JSONObject) jsonArray.get(i);
                NewsBean newsBean = new NewsBean();
                newsBean.setStr_context(jsonObject.getString("context"));
                newsBean.setStr_icon(jsonObject.getString("Str_icon"));
                newsBean.setStr_title(jsonObject.getString("title"));
                mList.add(newsBean);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return mList;
    }

    //将流读取成Json字符串
    private String getJsonFromInputStream(InputStream inputStream) {
        String json = "";
        String str;
        InputStreamReader mIsr = new InputStreamReader(inputStream);
        BufferedReader mBfr = new BufferedReader(mIsr);
        try {
            while (null != (str = mBfr.readLine())) {
                json += str;
            }
        } catch (IOException e) {

            e.printStackTrace();
        } finally {
            try {
                mBfr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
         return json;
    }


}

JavaBean代码

package com.kuxiao.tran.studyActivity;


public class NewsBean {

    private String Str_title;

    private String str_context;

    private String str_icon;

    public String getStr_title() {
        return Str_title;
    }

    public void setStr_title(String str_title) {
        Str_title = str_title;
    }

    public String getStr_icon() {
        return str_icon;
    }

    public void setStr_icon(String str_icon) {
        this.str_icon = str_icon;
    }

    public String getStr_context() {
        return str_context;
    }

    public void setStr_context(String str_context) {
        this.str_context = str_context;
    }
}




3、在适配器中把数据源对应显示在ListView上

package com.kuxiao.tran.studyActivity;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;


public class MyAdapter extends BaseAdapter {

    private List<NewsBean> mList;//数据源
    private LayoutInflater mInflater;//每一个item布局的转化
    private BitmapCache mBitmapCache = null;//缓存

    public MyAdapter(Context context, List<NewsBean> params) {
        mInflater = LayoutInflater.from(context);
        this.mList = params;
        mBitmapCache = new BitmapCache();

    }


    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public Object getItem(int position) {
        return mList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder mViewHolder;
        //ListView的缓存机制中判断convertView是否存在
        if (convertView == null) {
            mViewHolder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.item, null);
            mViewHolder.iv_icon = (ImageView) convertView.findViewById(R.id.id_iv_icon);
            mViewHolder.tv_title = (TextView) convertView.findViewById(R.id.id_tv_title);
            mViewHolder.tv_context = (TextView) convertView.findViewById(R.id.id_tv_context);
            convertView.setTag(mViewHolder);
        } else {
            mViewHolder = (ViewHolder) convertView.getTag();
        }
        //给对应的viewHolder对象保存的控件赋值
        mViewHolder.tv_context.setText(mList.get(position).getStr_context());
        mViewHolder.tv_title.setText(mList.get(position).getStr_title());

        new MyAsnyctask(mViewHolder.iv_icon, position,mBitmapCache).execute(mList.get(position).getStr_icon());

        return convertView;
    }

    //利用ViewHolder对象避免重复的findViewById寻找控件的操作
    class ViewHolder {
        ImageView iv_icon;
        TextView tv_context;
        TextView tv_title;
    }
}

4、在适配器显示图片时开启异步线程去服务器读取照片(第一种方式,利用Asynctask类)

在MyAdapter类中写一个内部类,代码如下

class MyAsnyctask extends AsyncTask<String, Void, Bitmap> {

        private ImageView imageView;
        private int position;
        private static final String url = "http://172.46.159.87:8080/News/NewsImage/";
        private BitmapCache mBitmapCache = null;

        public MyAsnyctask(ImageView imageView, int position,BitmapCache mBitmapCache) {
            this.imageView = imageView;
            this.position = position;
            imageView.setTag(this.position);
            this.mBitmapCache = mBitmapCache;
        }

        @Override
        protected Bitmap doInBackground(String... params) {

            Bitmap bitmap;

            if (mBitmapCache.getBitmap(this.position + "") == null) {
                String imageName = params[0];
                bitmap = getBitmap(imageName);
            } else {
                bitmap = mBitmapCache.getBitmap(position + "");

            }

            return bitmap;
        }


        //通过Url向服务器取图片
        private Bitmap getBitmap(String imageName) {
            Bitmap bitmap = null;
            InputStream mIs = null;
            try {
                URL url = new URL(MyAsnyctask.url + imageName);
                mIs = url.openStream();
                bitmap = BitmapFactory.decodeStream(mIs);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    mIs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return bitmap;
        }


        @Override
        protected void onPostExecute(Bitmap bitmap) {

            if (null != imageView && null != bitmap) {
                if (imageView.getTag() == position) {
                    imageView.setImageBitmap(bitmap);
                }
            }

        }

    }

5、另一种方式使用Handller+子线线程的方式实现异步加载,代码如下

package com.kuxiao.tran.studyActivity;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class ImageLoader extends Thread {

    private ImageView mImageView;

    private String mImageName;

    private int position;

    private static final String url = "http://172.46.130.144:8080/News/NewsImage/";

    public ImageLoader(ImageView mImageView, String imageName, int position) {
        this.mImageName = imageName;
        this.mImageView = mImageView;
        this.position = position;
    }

    Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {

            if (msg.what == 0) {

                if (mImageView.getTag() == ImageLoader.this.position) {
                    Bitmap bitmap = (Bitmap) msg.obj;
                    mImageView.setImageBitmap(bitmap);

                }
            }


        }
    };


    @Override
    public void run() {

        try {
            URL url1 = new URL(url + mImageName);
            HttpURLConnection urlConnection = (HttpURLConnection) url1.openConnection();
            if (urlConnection.getResponseCode() == 200) {
                InputStream  mIs = url1.openStream();
                Bitmap bitmap = BitmapFactory.decodeStream(mIs);
                this.mImageView.setTag(this.position);
                handler.obtainMessage(0, bitmap).sendToTarget();

            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }
}

6、利用BitmapCache类进行下缓存优化,代码如下

package com.kuxiao.tran.studyActivity;


import android.graphics.Bitmap;
import android.util.Log;
import android.util.LruCache;

public class BitmapCache {


    private LruCache<String, Bitmap> mLruCache;

    public BitmapCache() {
        //获取最大运行时的最大内存
        int max = (int) (Runtime.getRuntime().maxMemory() / 8);
        mLruCache = new LruCache<String, Bitmap>(max) {

            @Override
            protected int sizeOf(String key, Bitmap value) {
                //设置每一次缓存的大小
                return value.getByteCount();
            }
        };
    }


    //缓存一个Bitmap对象
    public void saveBitmap(String key, Bitmap value) {
        mLruCache.put(key, value);
    }

    //取出一个Bitmap对象
    public Bitmap getBitmap(String key) {
        return mLruCache.get(key);
    }

}

四、特别说明:本人大四的小白,自学的android编程,如有不妥之处,多谢指出,服务器端的代码我就不贴出来了,有需要的朋友可以联系我QQ:953751759,Json数据生成不懂的,可以看我博客中的Json数据生成。

上述中在给ImageView设置Tag的是用的ListView中的位置,并没有用照片的URL,是因为本人服务器生成的Json数据的照片的名字相同,图片只有一张,所以Url不适合设置成Tag,大家在练习的时候注意下。

posted @ 2016-12-13 17:23  杨威953  阅读(124)  评论(0编辑  收藏  举报