简易新闻客户端(生成列表)

制作一个简易的新闻客户端,主要目的是学习网络数据解析及异步加载,目前只包括从网页获取数据生成列表功能,未添加点击列表显示新闻内容功能,

类文件


MainActivity

import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
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.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private ListView mListView;
    //初始化网址
    private static String urlString = "http://www.imooc.com/api/teacher?type=4&num=30";
    private Context mContext = this;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mListView = (ListView) findViewById(R.id.lv_main);
        new NewsAsyncTask().execute(urlString);
    }

    /**
     * 实现网络的异步访问
     */
    class NewsAsyncTask extends AsyncTask<String, Void, List<NewsBean>>{

        @Override
        protected List<NewsBean> doInBackground(String... strings) {
            //从网页获取数据
            return getJsonData(strings[0]);
        }

        @Override
        protected void onPostExecute(List<NewsBean> newsBeans) {
            super.onPostExecute(newsBeans);
            NewsAdapter mNewsAdapter = new NewsAdapter(mContext, newsBeans, mListView);
            mListView.setAdapter(mNewsAdapter);
        }
    }

    /**
     * 将url对应的JSON格式数据转化为NewsBean对象
     * @param url
     * @return
     */
    private List<NewsBean> getJsonData(String url) {

        List<NewsBean> newsBeanList = new ArrayList<>();
        try {
            String jsonString = readStream(new URL(url).openStream());
            JSONObject jsonObject;
            NewsBean newsBean;
            try {
                jsonObject = new JSONObject(jsonString);
                JSONArray jsonArray = jsonObject.getJSONArray("data");
                for (int i=0; i<jsonArray.length(); i++) {
                    jsonObject = jsonArray.getJSONObject(i);
                    newsBean = new NewsBean();
                    newsBean.newsIconUrl = jsonObject.getString("picSmall");
                    newsBean.newsTitle = jsonObject.getString("name");
                    newsBean.newsContent = jsonObject.getString("description");
                    newsBeanList.add(newsBean);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return newsBeanList;
    }

    /**
     * 通过inputstream解析网页返回的数据
     * @param is
     * @return
     */
    private String readStream(InputStream is){
        InputStreamReader isr;
        String result = "";

        try {
            String line = "";
            isr = new InputStreamReader(is, "utf-8");
            BufferedReader br = new BufferedReader(isr);
            while((line = br.readLine()) != null){
                result += line;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}

新闻实体类

public class NewsBean {
    public String newsIconUrl;
    public String newsTitle;
    public String newsContent;
}

列表适配器

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.util.List;

/**
 * Created by HPF on 2016/6/10.
 */
public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener{

    private Context mContext;
    private List<NewsBean> mList;
    private LayoutInflater mInflater;
    private ImageLoader mImageLoader;

    private int mStart, mEnd;
    public static String[] URLs;

    private boolean mFirstIn;

    /**
     * 构造函数
     * @param context
     * @param list
     * @param listView
     */
    public NewsAdapter(Context context, List<NewsBean> list, ListView listView) {
        mContext = context;
        mList = list;
        mInflater = LayoutInflater.from(mContext);
        //初始化图片加载器
        mImageLoader = new ImageLoader(listView);
        URLs = new String[list.size()];
        mFirstIn = true;

        for (int i=0; i<list.size(); i++){
            URLs[i] = list.get(i).newsIconUrl;
        }
        listView.setOnScrollListener(this);
    }

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

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

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

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder = null;
        if (view == null){
            view = mInflater.inflate(R.layout.item_layout, null);
            viewHolder = new ViewHolder(view);
            view.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) view.getTag();
        }
        viewHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);
        viewHolder.ivIcon.setTag(mList.get(i).newsIconUrl);
//        new ImageLoader().showImageByThread(viewHolder.ivIcon, mList.get(i).newsIconUrl);
        //异步加载图片
        mImageLoader.showImageByAsyncTask(viewHolder.ivIcon, mList.get(i).newsIconUrl);
        viewHolder.tvTitle.setText(mList.get(i).newsTitle);
        viewHolder.tvContent.setText(mList.get(i).newsContent);
        return view;
    }

    /**
     * 滑动停止时加载
     * @param absListView
     * @param i
     */
    @Override
    public void onScrollStateChanged(AbsListView absListView, int i) {
        if (i == SCROLL_STATE_IDLE) {
            mImageLoader.loadImage(mStart, mEnd);
        } else {
            mImageLoader.cancelAllTasks();
        }
    }

    /**
     * 只加载显示区域内的图片
     * @param absListView
     * @param i
     * @param i1
     * @param i2
     */
    @Override
    public void onScroll(AbsListView absListView, int i, int i1, int i2) {
        mStart = i;
        mEnd = i + i1;
        if (mFirstIn && i1>0) {
            mImageLoader.loadImage(mStart, mEnd);
            mFirstIn = false;
        }
    }

    class ViewHolder{
        public TextView tvTitle;
        public TextView tvContent;
        public ImageView ivIcon;
        public ViewHolder(View view) {
            tvTitle = (TextView) view.findViewById(R.id.tv_title);
            tvContent = (TextView) view.findViewById(R.id.tv_content);
            ivIcon = (ImageView) view.findViewById(R.id.imv_icon);
        }
    }
}

图片异步加载

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.LruCache;
import android.widget.ImageView;
import android.widget.ListView;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by HPF on 2016/6/10.
 */
public class ImageLoader {
    private ImageView mImageView;
    private String mUrl;
    private ListView mListView;
    private Set<NewsAsyncTask> mTask;
    private LruCache<String, Bitmap> mCaches;

    /**
     * 构造函数
     * @param listView
     */
    public ImageLoader(ListView listView) {
        //获取最大可用内存
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        int cacheSize = maxMemory/4;
        //初始化缓存
        mCaches = new LruCache<String, Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
        };
        mListView = listView;
        mTask = new HashSet<>();
    }

    /**
     * 从缓存获取图片
     * @param url
     * @return
     */
    private Bitmap getBitmapFromCache(String url) {
        return mCaches.get(url);
    }

    /**
     * 将图片加入到缓存
     * @param url
     * @param bitmap
     */
    private void addBitmapToCache(String url, Bitmap bitmap) {

        if (getBitmapFromCache(url)==null){
            mCaches.put(url, bitmap);
        }

    }

    /**
     * 从网络获取图片
     * @param urlString
     * @return
     * @throws IOException
     */
    public Bitmap getBitmapFromURL(String urlString) throws IOException {
        Bitmap bitmap = null;
        InputStream is = null;
        try {
            URL url =new URL(urlString);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            is = new BufferedInputStream(conn.getInputStream());
            bitmap = BitmapFactory.decodeStream(is);
            conn.disconnect();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            is.close();
        }
        return bitmap;
    }

    /**
     * 显示图片
     * @param imageView
     * @param url
     */
    public void showImageByAsyncTask(ImageView imageView, String url){

        Bitmap bitmap = getBitmapFromCache(url);
        if (bitmap == null) {
            imageView.setImageResource(R.mipmap.ic_launcher);
        } else {
            imageView.setImageBitmap(bitmap);
        }

    }

    public void cancelAllTasks() {
        if (mTask != null){
            for (NewsAsyncTask task:mTask){
                task.cancel(false);
            }
        }
    }

    private class NewsAsyncTask extends AsyncTask<String, Void, Bitmap>{
        private String mUrl;
        public NewsAsyncTask(String url) {
            this.mUrl = url;
        }
        Bitmap bitmap = null;

        @Override
        protected Bitmap doInBackground(String... strings) {
            try {
                bitmap = getBitmapFromURL(strings[0]);
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (bitmap != null) {
                addBitmapToCache(strings[0], bitmap);
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl);
            if (imageView!=null&&bitmap!=null){
                imageView.setImageBitmap(bitmap);
            }
            mTask.remove(this);

        }
    }

    public void loadImage(int start, int end) {
        for (int i=start; i<end; i++){
            String url = NewsAdapter.URLs[i];
            Bitmap bitmap = getBitmapFromCache(url);
            if (bitmap == null) {
                NewsAsyncTask task = new NewsAsyncTask(url);
                task.execute(url);
                mTask.add(task);
            } else {
                ImageView imageView = (ImageView) mListView.findViewWithTag(url);
                imageView.setImageBitmap(bitmap);
            }

        }
    }
}

布局文件

列表项布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/imv_icon"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:src = "@mipmap/ic_launcher"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingLeft="4dp"
        android:gravity="center_vertical">
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="15sp"
            android:maxLines="1"
            android:text="Title"/>
        <TextView
            android:id="@+id/tv_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="10sp"
            android:maxLines="3"
            android:text="Content"/>
    </LinearLayout>
</LinearLayout>

主布局

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context="com.example.hpf.newsdemo.MainActivity">
    <ListView
        android:id="@+id/lv_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello World!" />
</RelativeLayout>

根据慕课网教学视频制作

猜你喜欢

转载自blog.csdn.net/haopengfei91/article/details/51932358