无废屁Android 系列教程36 -2 [listview的工作原理及使用&测试]
无废话Android 系列教程36 -2 [listview的工作原理及使用&测试]
![无废屁Android 系列教程36 -2 [listview的工作原理及使用&测试] 无废屁Android 系列教程36 -2 [listview的工作原理及使用&测试]](/default/index/img?u=aHR0cDovL3d3dy5teWV4Y2VwdGlvbnMubmV0L2ltZy8yMDE1LzEwLzExLzA4NTQxNjM4NS5qcGc=)
1. listview 工作原理: 先需要定义一个线性布局,布局里面只保留屏幕内可显示条数的View 对象
(的引 用),当在屏幕向上拖动一个条目(数据)时,它就移除最上面的View 对象, 将它丢掉。
当在屏幕向下拖动一个条目(数据)时,它就新new出一个View对象,将它显示到页面(屏幕)上。
这样就不需要new 出50/100W个view对象!只需要new出屏幕内能最多显示对象的数目就可以了,如:
屏幕只能最多显示9条数据,这样就需要new出9个View对象即可!
注: 如果使用[模仿listview]的方法来显示5000条数据还没有问题,当数据库里有100W条记录需要显示时,
就需要在LinearLayout线性布局里面 new 出100W个TextView ,这样肯定不行的,系统会崩溃!
所以此时listview 就是绝佳的选择!
2. listview实现模式: 典型MVC模式
M mode 数据模型 获取的List<Person> 集合
V view 视图 listview 对象
C controller 控制器 实现Listadapter接口或继承BaseAdapter抽象类 ( 数据适配器)
3. com.andy.listview1 包下类
MainActivity.java
package com.andy.listview1; import java.util.List; import com.andy.listview1.R; import android.app.Activity; import android.content.res.ColorStateList; import android.database.DataSetObserver; import android.graphics.Color; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; import com.andy.listview1.dao.PersonDao2; import com.andy.listview1.domain.Person; /** * 这是一个模仿listview 的类 * @author huiqinbo * */ public class MainActivity extends Activity { private ListView lv; private List<Person> persons; private static final String TAG = MainActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PersonDao2 dao = new PersonDao2(this); persons = dao.findAllPerson(); lv = (ListView)findViewById(R.id.lv); lv.setAdapter(new MyAdapter()); } // private class MyAdapter implements ListAdapter{ // // @Override // public void registerDataSetObserver(DataSetObserver observer) { // // TODO Auto-generated method stub // // } // // @Override // public void unregisterDataSetObserver(DataSetObserver observer) { // // TODO Auto-generated method stub // // } // // /** // * // * listview里面总共有多个条目 // * // */ // @Override // public int getCount() { // // TODO Auto-generated method stub // int size = persons.size(); // return size; // } // // @Override // public Object getItem(int position) { // // TODO Auto-generated method stub // return null; // } // // @Override // public long getItemId(int position) { // // TODO Auto-generated method stub // return 0; // } // // @Override // public boolean hasStableIds() { // // TODO Auto-generated method stub // return false; // } // // /** // * @param position 是 // */ // @Override // public View getView(int position, View convertView, ViewGroup parent) { // TextView tv = new TextView(getApplicationContext()); // Person p = persons.get(position); // tv.setText(p.toString()); // tv.setTextColor(Color.GREEN); // tv.setTextSize(10); // return tv; // } // // @Override // public int getItemViewType(int position) { // // TODO Auto-generated method stub // return 0; // } // // @Override // public int getViewTypeCount() { // // TODO Auto-generated method stub // return 0; // } // // @Override // public boolean isEmpty() { // // TODO Auto-generated method stub // return false; // } // // @Override // public boolean areAllItemsEnabled() { // // TODO Auto-generated method stub // return false; // } // // @Override // public boolean isEnabled(int position) { // // TODO Auto-generated method stub // return false; // } // // } private class MyAdapter extends BaseAdapter{ @Override public int getCount() { // TODO Auto-generated method stub return persons.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } /** * 这个方法是:展现屏幕指定位置的数据,(展现数据集合某一位置所对应的数据); 初次打开时 创建屏幕内所容纳数量的view对象,并将它显示出来了 * *特别提示:初次打开时位置是从0开始 至 屏幕所能显示条目的数量!如0-8条,等向上或向下滚动时都是在这8条减少或增加! * @param position 当前数据在集合中的位置 */ @Override public View getView(int position, View convertView, ViewGroup parent) { Log.i(TAG, "返回View对象,位置:"+position); TextView tv = new TextView(getApplicationContext()); //得到某个位置对应的person数据 Person p = persons.get(position); tv.setText(p.toString()); tv.setTextColor(Color.BLACK); tv.setTextSize(13); return tv; } } }
PersonSQLiteOpenHelper.java
package com.andy.listview1; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; /** * 创建PersonSQLiteOpenHelper类 继承SQLiteOpenHelper抽象类,此时必须创建构造方法 * @author huiqinbo * */ public class PersonSQLiteOpenHelper extends SQLiteOpenHelper { //通过getSimpleName()方法获取到值为"PersonSQLiteOpenHelper" private static final String tag = PersonSQLiteOpenHelper.class.getSimpleName(); /** * 数据库的构造方法, 用来定义数据库的名称/数据库的查询结果集/数据库的版本号 * * 当版本号发生变化时才可以调用onUpgrade方法; 如版本号从1 →2 * @param context * @param name * @param factory * @param version */ public PersonSQLiteOpenHelper(Context context) { // super(context, "person.db", null, 1); super(context, "person.db", null, 4); // TODO Auto-generated constructor stub } /** * 数据库第一次被创建的时候调用的方法 * @param db 被创建的数据库 */ @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table person (id integer primary key autoincrement, name varchar(20), number varchar(20))"); } /** * sqlite中ALTER TABLE语句不支持DROP COLUMN,只有RENAME 和ADD 语句. */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub Log.i(tag, "数据库的版本发生变化了"); db.execSQL("alter table person add account varchar(20)"); } }
4. com.andy.listview1.dao
package com.andy.listview1.dao; import java.util.ArrayList; import java.util.List; import com.andy.listview1.PersonSQLiteOpenHelper; import com.andy.listview1.domain.Person; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; public class PersonDao2 { private PersonSQLiteOpenHelper helper; public PersonDao2(Context context){ helper = new PersonSQLiteOpenHelper(context); } /* * 插入用户名和手机号到SQLite数据库 * * the row ID of the newly inserted row, or -1 if an error occurred */ public long addPerson(String name, String number,int account){ //此时就获取到了数据库 SQLiteDatabase db = helper.getWritableDatabase(); //db.execSQL("insert into person (name,number) values (?,?)", new Object[]{name,number}); ContentValues values = new ContentValues(); values.put("name", name); values.put("number", number); values.put("account", account); long row_id = db.insert("person", null, values); db.close(); return row_id; } /** * 删除一条数据,按用户名的条件 * @param name * * WhereClause :the optional WHERE clause to apply when deleting. Passing null will delete all rows. */ public int deletePerson(String name){ SQLiteDatabase db = helper.getWritableDatabase(); // db.execSQL("delete from person where name =?", new Object[]{name}); int row_id = db.delete("person", "name=?", new String[]{name}); db.close(); return row_id; } /** * 修改一条数据,按用户名的条件 * @param name * @param number */ public int updatePerson(String name, String number){ SQLiteDatabase db = helper.getWritableDatabase(); // db.execSQL("update person set number = ? where name = ?", new Object[]{name,number} ); ContentValues values = new ContentValues(); values.put("number", number); int row_id = db.update("person", values, "name=?", new String[]{name}); db.close(); return row_id; } /** * 查询一条数据,按用户名的条件 * @param name * @param number * selection : A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given table. * selectionArgs: You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings. */ public boolean findPerson(String name){ SQLiteDatabase db = helper.getWritableDatabase(); // Cursor cursor = db.rawQuery("select * from person where name=?", new String[]{name}); Cursor cursor = db.query("person", new String[]{"id", "name", "number"}, "name=?", new String[]{name}, null, null, null); boolean result = cursor.moveToNext(); cursor.close(); db.close(); return result; } public List<Person> findAllPerson(){ SQLiteDatabase db = helper.getWritableDatabase(); // Cursor cursor = db.rawQuery("select * from person", null); Cursor cursor = db.query("person", new String[]{"id","name","number"}, null, null, null, null, null); List<Person> persons = new ArrayList<Person>(); Person person; while(cursor.moveToNext()){ int id = cursor.getInt(cursor.getColumnIndex("id")); String name = cursor.getString(cursor.getColumnIndex("name")); String number = cursor.getString(cursor.getColumnIndex("number")); person = new Person(id,name,number); persons.add(person); } cursor.close(); db.close(); return persons; } }
5. com.andy.listview1.domain 包下的Person.ajva
package com.andy.listview1.domain; public class Person { private int id; private String name; private String number; public Person(int id, String name, String number){ this.id = id; this.name= name; this.number = number; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", number=" + number + "]"; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } }
6. com.andy.listview1.test 包下的TestPersonListView.java
package com.andy.listview1.test; import java.util.List; import java.util.Random; import com.andy.listview1.PersonSQLiteOpenHelper; import com.andy.listview1.dao.PersonDao2; import com.andy.listview1.domain.Person; import android.database.sqlite.SQLiteDatabase; import android.test.AndroidTestCase; import android.util.Log; /** * * @author huiqinbo * */ public class TestPersonListView extends AndroidTestCase { private static final String tag = TestPersonListView.class.getSimpleName(); public PersonDao2 pd; /** * getContext() 是测试框架给提供的上下文件 来源:android.test.AndroidTestCase.getContext() * * 第一次执行时调用PersonSQLiteOpenHelper.java 内的onCreate方法, * 当版本号发生变化时,会调用PersonSQLiteOpenHelper.java 内的onUpgrade方法. */ public void testCreatePersonDb() { PersonSQLiteOpenHelper db = new PersonSQLiteOpenHelper(getContext()); // 打开或创建一个可写的数据库 db.getWritableDatabase(); } public void testAddPerson() { pd = new PersonDao2(getContext()); Random random = new Random(); for(int i=0; i<50; i++){ pd.addPerson("ZhangSan"+i, "138001380"+i, random.nextInt(10000)); } } //注:查询数据表的结构SQL语句: //select * from sqlite_master where type="table" and name="person"; }
7. layout 下的 activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/ll_root" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.andy.listview1.MainActivity" tools:ignore="MergeRootFrame" > <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent" > </ListView> </LinearLayout>
这段xml代码的效果如下:
8. 项目部署后的效果:
9. 项目源代码参照附件