先看下首页的效果图
在一食堂中设置了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加载的数据了。