Android Json数据的解析+ListView图文混排+缓存算法Lrucache 仿知乎

前几天心血来潮,打算根据看知乎的API自己做一个小知乎,定制的过程遇到ListView的优化问题及图片未缓存重加载等等许多问题,解决了以后打算和博友分享一下。

接口数据:http://api.kanzhihu.com/getpostanswers/20150925/archive

Android Json数据的解析+ListView图文混排+缓存算法Lrucache 仿知乎_第1张图片Android Json数据的解析+ListView图文混排+缓存算法Lrucache 仿知乎_第2张图片

首先,Json数据太常用,相信每一位开发者Json的解析都是必备的。我们要准备以下知识:

JavaBean,枚举你需要的元素,用来存储数据。

异步加载网络内容的必备途径,多线程加载+AsyncTask两种方式。

Json解析的常见方法,JsonObject和JsonArray;

ListView优化,使用Viewholder

下面上代码,侧边栏这里就不说了,相信大家都会。

layout_main.xml




    
        
        
    


图文混排ListView的item文件:

item_id_listview.xml



    
        
        
        
    
    
        
    
    
        
    
    
        
    

JsonBean.java  这儿是javabean,用来存储需要的数据对象

public class JsonBean {
    public String name;
    public String title;
    public String body;
    public String time;
    public String url;
}
CommentListView.java 重写ListView禁止滑动,避免与ScrollView发生冲突:

public class CommentListView extends ListView {
    public CommentListView(Context context) {
        super(context);
    }

    public CommentListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CommentListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CommentListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        int mExpandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, mExpandSpec);
    }
}
ListAdapter.java

import android.content.Context;
import android.content.Intent;
import android.util.Log;
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 com.ynu.commando.Imageloader;
import com.ynu.commando.JavaBean.JsonBean;
import com.ynu.commando.R;
import com.ynu.commando.UsingTest;

import java.util.List;

/**
 * Created by 江树金 on 2016/4/23.
 */
public class ListAdapter extends BaseAdapter {

    private List mlist;//JsonBean的list
    private LayoutInflater mInflater;
    private Imageloader mImageloader;
    private Context context;

    public void setContext(Context context) {
        this.context = context;
    }

    //将数据映射过来
    public ListAdapter(Context context, List data){
        mlist=data;
        mInflater= LayoutInflater.from(context);
        mImageloader=new Imageloader();
        this.context=context;
    }

    @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 viewHolder=null;
        if (viewHolder==null){
            viewHolder=new ViewHolder();
            convertView=mInflater.inflate(R.layout.item_id_listview,null);
            viewHolder.img= (ImageView) convertView.findViewById(R.id.img);
            viewHolder.img.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.i("========点击了头像========", "点击事件启动-------------- ");
                    context.startActivity(new Intent(context, UsingTest.class));
                }
            });
            viewHolder.title= (TextView) convertView.findViewById(R.id.title);
            viewHolder.body= (TextView) convertView.findViewById(R.id.body);
            viewHolder.name= (TextView) convertView.findViewById(R.id.name);
            viewHolder.time= (TextView) convertView.findViewById(R.id.time);
            convertView.setTag(viewHolder);
        }else {
            viewHolder= (ViewHolder) convertView.getTag();
        }
        String url=mlist.get(position).url;
        viewHolder.img.setTag(url);//进行绑定,为了在imageLoader中的语句,
        /*
        * @二选一进行图片加载
        * */
        /*mImageloader.showImagerByThread(viewHolder.img,mlist.get(position).url);//使用多线程的方法加载图片*/
        mImageloader.showImageByAsyncTask(viewHolder.img,url);//使用AsyncTask的方式加载
        viewHolder.title.setText(mlist.get(position).title);//从JsonBean中取出元素设置给viewholder的元素
        viewHolder.body.setText(mlist.get(position).body);
        viewHolder.name.setText(mlist.get(position).name);
        viewHolder.time.setText(mlist.get(position).time);
        return  convertView;
    }

    class ViewHolder{
        public TextView title;
        public TextView body;
        public TextView name;
        public TextView time;
        public ImageView img;
    }
}
Imageloader.java

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.nfc.Tag;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.util.LruCache;
import android.widget.ImageView;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by 江树金 on 2016/4/23.
 */
public class Imageloader {
    //注:异步加载图片可以使用①多线程加载 或者 ②AsyncTask去加载。[个人感觉多线程的加载速度大于AsyncTask]
    private ImageView mimageView;
    private String mUrl;
    //创建cache
    private LruCache mCache;

    public void showImagerByThread(ImageView imageView, final String url){
        mimageView=imageView;
        mUrl=url;
        new Thread(new Runnable() {//多线程加载
            @Override
            public void run() {
                Bitmap bitmap=getBitmapFromUrl(url);
                Message msg=Message.obtain();
                msg.obj=bitmap;
                handler.sendMessage(msg);
            }
        }).start();
    }

    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //在handler中处理UI
           //避免缓存的图片对正确图片的影响,viewholder会重新加载设定图片
            if (mimageView.getTag().equals(mUrl)){
                mimageView.setImageBitmap((Bitmap) msg.obj);//避免影响之后再去加载bitmap
            }
        }
    };

    /*
    * 公用方法 获取URL并存为bitMap类型 进行加载时可选择多线程或者AsyncTask进行加载
    * */
    public Bitmap getBitmapFromUrl(String UrlString){
        Bitmap bitmap;
        InputStream is;
        try {
            URL url=new URL(UrlString);
            HttpURLConnection connection= (HttpURLConnection) url.openConnection();
            is=new BufferedInputStream(connection.getInputStream());//获取InputStream对象
            bitmap= BitmapFactory.decodeStream(is);
            //资源释放,优化作用
            connection.disconnect();
            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public void showImageByAsyncTask(ImageView imageView,String url){
        //从缓存中取出对应的图片
        Bitmap bitmap=getBitmapFromCache(url);
        if (bitmap==null){
            //说明内存中没有该图片 只能从网络中获取图片
            new newAsyncTask(imageView,url).execute(url);//将url传递到newAsyncTask中处理。
        }else {
            //如果有就直接使用该图片
            imageView.setImageBitmap(bitmap);
        }
    }

    private class newAsyncTask extends AsyncTask{

        private ImageView mImageView;
        private String murl;

        @Override
        protected Bitmap doInBackground(String... params) {//完成异步加载任务
            //先进行下载,在判断缓存中有没有
            String url=params[0];
            Bitmap bitmap=getBitmapFromUrl(url);
            if (bitmap!=null){
                //加入缓存
                addBitmapToCache(url,bitmap);
            }
            return bitmap;
        }

        public newAsyncTask(ImageView imageView,String url){
            mImageView=imageView;
            murl=url;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            if (mImageView.getTag().equals(murl)){
                mImageView.setImageBitmap(bitmap);
            }
        }
    }

    public Imageloader(){
        /*
        *设定一部分内存转化为我们的缓存空间.Lru算法
        * */
        int MaxMemory= (int) Runtime.getRuntime().maxMemory();
        int cacheSize=MaxMemory/4;
        mCache=new LruCache(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                //返回实际大小
                return value.getByteCount();//在每次存入缓存的时候调用该方法,告诉当前系统存入的对象有多大
            }
        };
    }

    /*
    * 将url增加到缓存
    * 在增加之前校验缓存是否存在
    * */
    public void addBitmapToCache(String url,Bitmap bitmap){
        if (getBitmapFromCache(url)==null){
            mCache.put(url,bitmap);
        }
    }

    public Bitmap getBitmapFromCache(String url){//通过url去返回指定的cache
        return mCache.get(url);//LruCache 本质上就是map  可以直接获得
    }
}
MainActivity.java

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    private CommentListView mlistView;
    private String url="http://api.kanzhihu.com/getpostanswers/20150925/archive";//知乎API [ answers ]
    private SwipeRefreshLayout refreshLayout;
    private ListAdapter listAdapter;
    List mjsonBeen;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.setTitle("");
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);

        initView();
        mlistView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {
                switch (position){
                    case 0:
                        startActivity(new Intent(MainActivity.this,UsingTest.class));
                        break;
                }
            }
        });
        new asyncTask().execute(url);
        refreshLayout.setColorSchemeResources(R.color.swipeRefreshLayout,
                R.color.swipeRefreshLayout,
                R.color.swipeRefreshLayout,
                R.color.swipeRefreshLayout);
        refreshLayout.setProgressViewEndTarget(true, 100);
        refreshLayout.setProgressBackgroundColor(R.color.bg);
        refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(2000);
                            Message msg=Message.obtain();
                            msg.what=1;
                            handler.sendMessage(msg);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        });
    }

    private void initView() {
        mlistView= (CommentListView) findViewById(R.id.id_listView);
        refreshLayout= (SwipeRefreshLayout) findViewById(R.id.refreshLayout);
    }

    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what==1){
                Toast.makeText(MainActivity.this, "刷新马上就好,请稍等哒~", Toast.LENGTH_SHORT).show();
                refreshLayout.setRefreshing(false);
            }
        }
    };

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();
        /*
        * 侧边栏点击事件
        * */
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    /*
    * 实现网络的异步访问
    * */
    class  asyncTask extends AsyncTask>{

        @Override
        protected List doInBackground(String... params) {
            return getJsonData(params[0]);
        }

        @Override
        protected void onPostExecute(List jsonBeen) {
            super.onPostExecute(jsonBeen);
            listAdapter=new ListAdapter(MainActivity.this,jsonBeen);
            mlistView.setAdapter(listAdapter);
        }
    }

    /*
    * 将Url对应的json格式数据转化为我们所封装的JsonBean的对象
    * */
    private List getJsonData(String url) {//通过url获取data
        List jsonList=new ArrayList<>();
        try {
            String jsonString=readStream(new URL(url).openStream());//打开json的字符串接收
            JSONObject jsonObject;
            JsonBean jsonBean;
            jsonObject=new JSONObject(jsonString);//将获取到的json数据传入jsonObject;
            JSONArray jsonArray=jsonObject.getJSONArray("answers");//去除data
            for (int i=0;i
还差许多xml文件,博主没有贴上去,大部分是一些自定的样式和侧边栏。本篇博客旨在让博友们看懂如何进行异步处理网络数据和Lrucache是如何操作的。

Demo是Android Studio的,能够直接跑起来,最重要的是读者能够自己写一遍我相信肯定能掌握,编程在于多动手。

地址: http://download.csdn.net/detail/u013000304/9520878





你可能感兴趣的:(Android Json数据的解析+ListView图文混排+缓存算法Lrucache 仿知乎)