android listView 深入探讨

  先看下首页的效果图

 在一食堂中设置了listView的列表,这节内容将详细介绍listView的知识点。下面的思路是这样的,通过sql数据库把数据保存到sd卡上,然后在listView页面获取数据,填充到对应列表中。我在application中定义了sql脚本,用于写人数据,导入的是xutils包,实现的数据库的增删改查。


package com.example.wmk;

import android.app.Activity;
import android.app.Application;
import android.os.Build;
import android.os.Bundle;

import com.example.wmk.db.SqlScript;
import com.example.wmk.utils.ActivityManager;
import com.example.wmk.utils.CrashHandler;
import com.example.wmk.utils.ProjectUtils;
import com.example.wmk.utils.Utils;
import com.lidroid.xutils.util.LogUtils;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;

/**
 * Created by 老王 on 2016/12/1.
 */
public class WMKApplication extends Application {

    ActivityManager mActivityManager;

    @Override
    public void onCreate() {
        super.onCreate();

        //init ActivityManager
        mActivityManager = ActivityManager.getInstance();

        // 注册activity监听器
        registerActivityListener();

        if (ProjectUtils.init()) {

            //在这里为应用设置异常处理,然后程序才能获取未处理的异常
            CrashHandler crashHandler = CrashHandler.getInstance();
            crashHandler.init(this);

            //initScript
            new SqlScript(getApplicationContext());

            ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
                    //
                    .memoryCacheExtraOptions(Utils.getScreenWidth(getApplicationContext()),
                            Utils.getScreenHeight(getApplicationContext()))
                    //
                    .threadPoolSize(3)
                    //
                    .threadPriority(Thread.NORM_PRIORITY - 2)
                    //
                    .denyCacheImageMultipleSizesInMemory()
                    //
                    .imageDownloader(new BaseImageDownloader(getApplicationContext(), 5 * 1000, 30 * 1000))
                    //
                    .diskCacheFileNameGenerator(new Md5FileNameGenerator())
                    // 50 MB
                    .diskCacheSize(80 * 1024 * 1024)
                    //
                    .tasksProcessingOrder(QueueProcessingType.LIFO)
                    //
                    .writeDebugLogs()
                    //
                    .build();
            ImageLoader.getInstance().init(config);
        } else {
            mActivityManager.appExceptionExit();
        }
    }

    private void registerActivityListener() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                    /**
                     * 监听到 Activity创建事件 将该 Activity 加入list
                     */
                    mActivityManager.pushActivity(activity);
                    /**
                     * 栈顶元素名称
                     */
                    LogUtils.d("TopActivityName:" + mActivityManager.getTopActivityName());
                }

                @Override
                public void onActivityStarted(Activity activity) {

                }

                @Override
                public void onActivityResumed(Activity activity) {

                }

                @Override
                public void onActivityPaused(Activity activity) {

                }

                @Override
                public void onActivityStopped(Activity activity) {

                }

                @Override
                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

                }

                @Override
                public void onActivityDestroyed(Activity activity) {
                    if (null == mActivityManager.getActivitys() && mActivityManager.getActivitys().isEmpty()) {
                        return;
                    }
                    if (mActivityManager.getActivitys().contains(activity)) {
                        /**
                         * 监听到 Activity销毁事件 将该Activity list中移除
                         */
                        mActivityManager.popActivity(activity);
                    }
                }
            });
        }
    }
}

  上面主要使用这行代码 new SqlScript(getApplicationContext()); 进行数据库操作。以及上面引入了imageLoader的包,用于网络加载图片。下面来看下,我的sql脚本类SqlScript。代码如下:

package com.example.wmk.db;

import android.content.Context;

import com.example.wmk.bean.OnePiece;
import com.lidroid.xutils.DbUtils;
import com.lidroid.xutils.exception.DbException;

import java.util.LinkedList;
import java.util.List;

/**
 * sql脚本,用于存放整个工程的数据库
 */
public class SqlScript {

    private List<OnePiece> onePieceList = null;


    public SqlScript(Context mContext) {
        DbUtils db = DBUtils.getInstance(mContext);

        try {
            db.dropTable(OnePiece.class);
            // 1、建表
            db.createTableIfNotExist(OnePiece.class);
            //2、添加数据
            onePieceList = new LinkedList<OnePiece>();
            onePieceList.add(new OnePiece("路飞", "assets://image/op01.png", "八宝粥店铺", "tel:18033935860"));
            onePieceList.add(new OnePiece("索隆", "assets://image/op02.png", "面线糊店铺", "tel:18033935861"));
            onePieceList.add(new OnePiece("乌索普", "assets://image/op03.png", "北京大烧饼", "tel:18033935862"));
            onePieceList.add(new OnePiece("山治", "assets://image/op04.png", "台湾风味小吃", "tel:18033935863"));
            onePieceList.add(new OnePiece("娜美", "assets://image/op05.png", "沙县小吃", "tel:18033935864"));
            onePieceList.add(new OnePiece("乔巴", "assets://image/op06.png", "黄焖鸡米饭", "tel:18033935865"));
            onePieceList.add(new OnePiece("罗宾", "assets://image/op07.png", "三峡烤鱼", "tel:18033935866"));
            onePieceList.add(new OnePiece("弗兰奇", "assets://image/op08.png", "福鼎肉片", "tel:18033935867"));
            onePieceList.add(new OnePiece("布鲁克", "assets://image/op09.png", "武大郎烧饼", "tel:18033935868"));
            onePieceList.add(new OnePiece("艾斯", "assets://image/op10.png", "闽南风味屋", "tel:18033935869"));

            db.saveAll(onePieceList);

        } catch (DbException e) {
            e.printStackTrace();
        }
    }
}
上面自定义了一个DBUtils类,代码如下:

package com.example.wmk.db;

import android.content.Context;

import com.example.wmk.utils.ProjectUtils;
import com.lidroid.xutils.DbUtils;

/**
 * 数据库
 */
public class DBUtils {

    /**
     * 数据库工具类
     */
    private static DbUtils DB = null;

    /**
     * 数据库名称
     */
    public static final String DB_NAME = "wmk.db";

    /**
     * 单例实例化
     *
     * @param context Context
     * @return DbUtils
     */
    public static DbUtils getInstance(Context context) {
        if (DB == null) {
            DB = DbUtils.create(context, ProjectUtils.WMK_DB, DB_NAME, 1, null);
            // 开启事务
            DB.configAllowTransaction(true);
        }
        return DB;
    }
}
并且定义了一个bean用于存放数据。OnePiece类,代码如下:

package com.example.wmk.bean;

import android.os.Parcel;
import android.os.Parcelable;

import com.lidroid.xutils.db.annotation.Column;
import com.lidroid.xutils.db.annotation.Id;
import com.lidroid.xutils.db.annotation.Table;

/**
 * Created by 老王 on 2017/1/12.
 */
@Table(name = "wmk_onePieceBean")
public class OnePiece implements Parcelable {

    /**
     * ID(必填)
     */
    @Id(column = "id")
    private int id = 0;
    @Column(column = "name")
    private String name;
    @Column(column = "imgUrl")
    private String imgUrl;
    @Column(column = "detail")
    private String detail;
    @Column(column = "reward")
    private String reward;

    public OnePiece() {//必填s

    }

    /**
     * @param name   姓名
     * @param imgUrl 图片url
     * @param detail 详细描述
     * @param reward 赏金
     */
    public OnePiece(String name, String imgUrl, String detail, String reward) {
        this.name = name;
        this.imgUrl = imgUrl;
        this.detail = detail;
        this.reward = reward;
    }

    protected OnePiece(Parcel in) {
        id = in.readInt();
        name = in.readString();
        imgUrl = in.readString();
        detail = in.readString();
        reward = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeString(name);
        dest.writeString(imgUrl);
        dest.writeString(detail);
        dest.writeString(reward);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<OnePiece> CREATOR = new Creator<OnePiece>() {
        @Override
        public OnePiece createFromParcel(Parcel in) {
            return new OnePiece(in);
        }

        @Override
        public OnePiece[] newArray(int size) {
            return new OnePiece[size];
        }
    };

    public String getName() {
        return name;
    }

    public String getImgUrl() {
        return imgUrl;
    }

    public String getDetail() {
        return detail;
    }

    public String getReward() {
        return reward;
    }
}
对应bean有几点要注意的,第一个,必须要定义id,默认id是自增长的,第二必须定义空构造函数 public OnePiece() { } ,否则会报错。第三图片是通过assets包下面,最终通过imageLoader的dispaly();方法显示的。

通过以上代码就把数据写入了sd卡,在清单文件上加入权限。

<!-- 写人外部存储权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 读取外部存储权限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

这样就把数据写入到了sd卡中,效果如下:

通过sqlitestudio工具打开wmk.db的数据文件。数据如下:

 这样就就把数据写入到了sd卡中,下面要读取sd卡中的数据,把数据填入到对应的listView列表中。

上面的布局按钮比较简单就不再详细介绍了。点击一食堂按钮进入到CanteenFirstActivity中,代码如下:

package com.example.wmk.activity.homeActivity;

import android.os.Bundle;
import android.widget.ListView;

import com.example.wmk.R;
import com.example.wmk.activity.baseActivity.BaseActivity;
import com.example.wmk.adapter.OnePieceAdapter;
import com.example.wmk.bean.OnePiece;
import com.example.wmk.db.DBUtils;
import com.lidroid.xutils.exception.DbException;

import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

public class CanteenFirstActivity extends BaseActivity {

    @BindView(R.id.lstView_main)
    ListView lstViewMain;

    /**
     * 适配器
     */
    private OnePieceAdapter adapter;
    private List<OnePiece> mData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_canteen_first);

        ButterKnife.bind(this);

        try {
            mData = DBUtils.getInstance(this).findAll(OnePiece.class);
        } catch (DbException e) {
            e.printStackTrace();
        }

        //初始化数据适配器
        adapter = new OnePieceAdapter(this, mData);
        //设置适配器
        lstViewMain.setAdapter(adapter);
    }
}
OnePieceAdapter的代码如下:

package com.example.wmk.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.example.wmk.R;
import com.example.wmk.bean.OnePiece;
import com.nostra13.universalimageloader.core.ImageLoader;

import java.util.List;

/**
 * Created by 老王 on 2017/1/9.
 */
public class OnePieceAdapter extends BaseAdapter {

    private Context context;
    private LayoutInflater inflater;
    private List<OnePiece> mData;

    public OnePieceAdapter(Context context, List<OnePiece> mData) {
        this.context = context;
        inflater = LayoutInflater.from(context);
        this.mData = mData;
    }

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

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

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

    @Override
    public View getView(final int i, View view, ViewGroup viewGroup) {
        final ViewHolder holder;
        if (view == null) {
            holder = new ViewHolder();

            view = inflater.inflate(R.layout.one_piece, null);

            holder.txtViewName = (TextView) view.findViewById(R.id.txtView_name);
            holder.imgUrl = (ImageView) view.findViewById(R.id.img_url);
            holder.txtViewDetail = (TextView) view.findViewById(R.id.txtView_detail);
            holder.txtViewReward = (TextView) view.findViewById(R.id.txtView_reward);
            holder.rlOp = (RelativeLayout) view.findViewById(R.id.rl_op);

            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }

        final OnePiece item = mData.get(i);

        holder.txtViewName.setText(item.getName());
        ImageLoader.getInstance().displayImage(item.getImgUrl(), holder.imgUrl);
        holder.txtViewDetail.setText(item.getDetail());
        holder.txtViewReward.setText(item.getReward());

        return view;
    }

    public class ViewHolder {
        RelativeLayout rlOp;
        TextView txtViewName;
        ImageView imgUrl;
        TextView txtViewDetail;
        TextView txtViewReward;
    }
}
one_piece.xml的布局代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rl_op"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/img_url"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="15dp" />

    <TextView
        android:id="@+id/txtView_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/img_url"
        android:paddingTop="10dp" />

    <TextView
        android:id="@+id/txtView_detail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/img_url"
        android:layout_toRightOf="@id/img_url"
        android:paddingBottom="10dp" />

    <TextView
        android:id="@+id/txtView_reward"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:paddingRight="5dp"
        android:paddingTop="25dp"
        android:textSize="15dp" />

</RelativeLayout>
这样就实现了,listView的效果,效果图如下:


 最后,说明下本人对listView的理解,如果已经了解的看客,可以不再关注以下内容。对于OnePieceAdapter类中,最难理解的应该算getView()方法了,其他的方法比较简单,就不再做介绍。在OnePieceAdapter中,第一次执行getView()方法时,view==null返回true.holder = new ViewHolder();这样就获得到了一个ViewHolder类的对象。接着通过 view = inflater.inflate(R.layout.one_piece, null);来加载布局,通过ViewHolder对象把对应的数据存储起来。

            holder.txtViewName = (TextView) view.findViewById(R.id.txtView_name);
            holder.imgUrl = (ImageView) view.findViewById(R.id.img_url);
            holder.txtViewDetail = (TextView) view.findViewById(R.id.txtView_detail);
            holder.txtViewReward = (TextView) view.findViewById(R.id.txtView_reward);
            holder.rlOp = (RelativeLayout) view.findViewById(R.id.rl_op);

这行代码view.setTag(holder);把ViewHolder对象存储起来,把刚才存储起来的数据通过以下代码显示到对应的框中。

        final OnePiece item = mData.get(i);
        holder.txtViewName.setText(item.getName());
        ImageLoader.getInstance().displayImage(item.getImgUrl(), holder.imgUrl);
        holder.txtViewDetail.setText(item.getDetail());
        holder.txtViewReward.setText(item.getReward());

对应bean的存储数据应该是存放到磁盘或者硬盘中,通过get()方法,获取到了对应磁盘或者硬盘中的数据,并填写到指定的框中。以上代码实现了,对listView的第一条数据的加载,第二次,执行view==null返回false,因为已经加载过布局文件了,接着获取到 holder = (ViewHolder) view.getTag();已经存储起来的ViewHolder对象,这样就实现了加载多条数据,实际上,只产生一个ViewHolder对象进行数据操作的目的。当所有的数据都显示到指定的框中,在手机上就显示出listView加载的数据了。

猜你喜欢

转载自blog.csdn.net/qq_21200053/article/details/54571146