2017-04-25
初寫博客有很多地方都有不足,希望各位大神給點建議。
回歸主題,這次簡單的給大家介紹一下Android SQLite與ListView的簡單使用sqlite在上節中有介紹,所以在這里廢話不多說了,重點說一下listview的使用及優化
listView的概述:
在 Android 應用開發中,ListView 是最為常見的組件之一。它將數據以列表的形式展現出來,在我們平時的開發中也是很常見。一般而言,一個ListView 由以下三個元素組成:
①View:用來展示列表的 View,通常是一個 XML 文件所指定的。
②適配器:用來把數據映射到 ListView 上,可以理解為 ListView 界面和數據之間的紐帶和橋梁。
③數據:具體被映射的數據和資源,可以是字符串、圖片等。
接下來我們簡單介紹一下 ListView 加載數據的原理。有了這方面的了解后再說優化才行。ListView 針對每個 item(列表項)都要求 adapter(適配器)“返回一個視圖”(getView)。 ListView 在開始繪制的時候系統會首先調用 getCount()函數,根據它的返回值得到 ListView 的長度,然后根據這個長度,逐次調用 getView()方法一行一行的繪制ListView 的每一項。getCount()方法的返回值是幾就顯示幾行。 具體怎么繪制呢?當我們調用 getView()方法時首先會通過加載布局文件生成一個新的 View 對象(實際上是一 個 ViewGroup),然后通過該對象將布局文件中的各個組件實例化(也就是 findViewById()), 這樣便可將數據對應到各個組件上了。但是加載布局文件屬於 I/O 操作,是很耗時的,當我們的數據量非常龐大或者列表項非常多的時候,很容易導致 ANR(應用程序無響應)現象。
1.listview的優化方案之__復用歷史緩存
所謂的復用,就是循環反復的利用。假如說我們有一百條列表項,我們沒有必要一一為他們創建新的對象,我們只要創建三個或者五個 item 對象,之后對他們循環利用即可。 其實 Android 系統本身為我們考慮了 ListView 的優化問題。在 getView()方法中系統就為我們提供了一個復用 View 的歷史緩存對象 convertView,當顯示第一屏的時候,每一個 item都會新創建一個 View 對象,這些 View 都是可以被復用的。 此時 convertView 在 getView()中是空值。假如說是 item1 滾動出屏幕時會進入到一個叫 Recycler 的 Android構件中去填充 convertView 並緩存起來,當新的項目從屏幕底端上來時,ListView 調用getView()方法,convertView 此時不是空值了,它的值是 item1。 你只需要設置新的數據,然后返回 convertView,不必重新創建一個視圖
2.istview的優化方案之__緩存 item 條目的引用—ViewHolder
findViewById()這個方法是比較耗性能的操作。當我們通過加載布局文件來創建 View 對象的時候,一但該對象生成,其布局文件中子控件的 id 也就不會改變了,因此我們在第一次加載的時候,需要將把相關的數據保存起來,下次直接從緩存中讀取,從而減少findViewById()的次數,優化顯示效率。
①創建一個靜態ViewHolder 內部類(可以抽取)
②創建自定義的類 ViewHolder holder = null ;
③setTag: 在創建新的 ListView 的時候創建新的 ViewHolder 對象,然后通過 findViewById找到子控件並將其引用保存起來。而 View 中有一個方法 setTag,可用來保存一些數據結構。通過 convertView.setTag(holder)將 ViewHolder 對象的引用設置到 view 中。
④在復用 ListView 中條目的時候,再通過 convertView.getTag(holder)獲取 holder對象的引用,此時我們只需要去修改其對象中子控件的值即可,不用 findViewById()
先看一下實現的一個界面:
項目結構:
主要代碼:MainPage
1 package com.hb.system.activity; 2 3 import java.util.List; 4 5 import android.annotation.SuppressLint; 6 import android.app.Activity; 7 import android.graphics.Color; 8 import android.graphics.drawable.ColorDrawable; 9 import android.os.Bundle; 10 import android.text.TextUtils; 11 import android.view.Gravity; 12 import android.view.View; 13 import android.view.View.OnClickListener; 14 import android.view.ViewGroup; 15 import android.view.animation.Animation; 16 import android.view.animation.ScaleAnimation; 17 import android.widget.AbsListView; 18 import android.widget.AbsListView.OnScrollListener; 19 import android.widget.AdapterView; 20 import android.widget.AdapterView.OnItemClickListener; 21 import android.widget.BaseAdapter; 22 import android.widget.Button; 23 import android.widget.EditText; 24 import android.widget.ImageView; 25 import android.widget.ListView; 26 import android.widget.PopupWindow; 27 import android.widget.RadioButton; 28 import android.widget.RadioGroup; 29 import android.widget.RadioGroup.OnCheckedChangeListener; 30 import android.widget.TextView; 31 import android.widget.Toast; 32 33 import com.example.studentinformationsystem.R; 34 import com.hb.bean.Student; 35 import com.hb.dao.SqlDao; 36 37 public class MainPage extends Activity implements OnCheckedChangeListener { 38 private EditText et_name; 39 private Button bt_add; 40 private String name; 41 private RadioGroup rg_group; 42 private TextView tv_showsex; 43 private String showsex; 44 private SqlDao dao; 45 private Student stu; 46 private Student stu2; 47 private List<Student> list; 48 private MyAdapter adapter; 49 private ListView listView1; 50 private PopupWindow pw; 51 private TextView delete; 52 53 54 55 @Override 56 protected void onCreate(Bundle savedInstanceState) { 57 // TODO Auto-generated method stub 58 super.onCreate(savedInstanceState); 59 setContentView(R.layout.mainpage); 60 initView(); 61 initDate(); 62 63 } 64 //初始化視圖 65 private void initView() { 66 et_name=(EditText) findViewById(R.id.et_name); 67 bt_add=(Button) findViewById(R.id.bt_add); 68 rg_group=(RadioGroup) findViewById(R.id.rg_group); 69 tv_showsex=(TextView) findViewById(R.id.tv_showsex); 70 listView1=(ListView) findViewById(R.id.listView1); 71 } 72 //初始化數據 73 private void initDate() { 74 dao=new SqlDao(MainPage.this); 75 list=dao.findAll(); 76 adapter=new MyAdapter(); 77 listView1.setAdapter(adapter); 78 rg_group.setOnCheckedChangeListener(this); 79 bt_add.setOnClickListener(new OnClickListener() { 80 81 @Override 82 public void onClick(View v) { 83 name = et_name.getText().toString().trim(); 84 showsex = tv_showsex.getText().toString().trim(); 85 stu=new Student(name,showsex); 86 87 if(TextUtils.isEmpty(name) || TextUtils.isEmpty(showsex)){ 88 Toast.makeText(MainPage.this, "添加信息不能為空", Toast.LENGTH_LONG).show(); 89 90 }else{ 91 stu2=new Student(name); 92 Student findName = dao.findName(stu2); 93 if(name.equals(findName.getName())){ 94 Toast.makeText(MainPage.this, "添加的姓名不能一樣!", Toast.LENGTH_SHORT).show(); 95 96 }else{ 97 boolean add = dao.add(stu); 98 if(add){ 99 list=dao.findAll(); 100 adapter.notifyDataSetInvalidated(); 101 Toast.makeText(MainPage.this, "添加成功", Toast.LENGTH_SHORT).show(); 102 }else { 103 Toast.makeText(MainPage.this, "添加失敗", Toast.LENGTH_SHORT).show(); 104 } 105 } 106 } 107 } 108 }); 109 /** 110 * listview的條目點擊事件 111 */ 112 listView1.setOnItemClickListener(new OnItemClickListener() { 113 private String na; 114 115 @Override 116 public void onItemClick(AdapterView<?> parent, View view, 117 final int position, long id) { 118 na = list.get(position).getName(); 119 View v = View.inflate(MainPage.this, R.layout.adapter_popu_window, null); 120 if (pw != null) { 121 pw.dismiss();//讓彈出的PopupWindow消失 122 pw = null; 123 } 124 pw = new PopupWindow(v, -2, -2); 125 int [] location=new int[2]; 126 view.getLocationInWindow(location); 127 pw.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 128 pw.showAtLocation(parent,Gravity.RIGHT+ Gravity.TOP, 20,location[1]-5 );//設置顯示的位置 129 ScaleAnimation animation = new ScaleAnimation(0.3f, 1f, 0.3f, 1f, Animation.RELATIVE_TO_SELF, 130 Animation.RELATIVE_TO_SELF);//彈出的動畫 131 animation.setDuration(400);//設置動畫時間 132 v.startAnimation(animation);//開啟動畫 133 delete = (TextView)v.findViewById(R.id.tv_delete); 134 /** 135 * 刪除每一個item上的數據 136 */ 137 delete.setOnClickListener(new OnClickListener() { 138 139 @Override 140 public void onClick(View v) { 141 dao.delete(na); 142 list.remove(position);//移除item的條目 143 list=dao.findAll();//調用查詢所有重新再查找一遍 144 adapter.notifyDataSetChanged();//更新適配器 145 } 146 }); 147 } 148 }); 149 150 /** 151 * listview的滑動監聽 152 * 當鼠標上下滑動的時候讓PopupWindow消失 153 */ 154 listView1.setOnScrollListener(new OnScrollListener() { 155 156 @Override 157 public void onScrollStateChanged(AbsListView view, int scrollState) { 158 } 159 @Override 160 public void onScroll(AbsListView view, int firstVisibleItem, 161 int visibleItemCount, int totalItemCount) { 162 if(pw!=null){ 163 pw.dismiss(); 164 pw=null; 165 } 166 } 167 }); 168 } 169 170 //按鈕組的點擊事件 171 @Override 172 public void onCheckedChanged(RadioGroup group, int checkedId) { 173 174 //獲取變更后的選中項的ID 175 int radioButtonId = group.getCheckedRadioButtonId(); 176 RadioButton rb = (RadioButton)MainPage.this.findViewById(radioButtonId); 177 //更新文本內容,以符合選中項 178 tv_showsex.setText(rb.getText()); 179 } 180 class MyAdapter extends BaseAdapter{ 181 182 private String sex2; 183 private View view; 184 private String name2; 185 @SuppressLint("ViewHolder") @Override 186 public View getView(int position, View convertView, ViewGroup parent) { 187 ViewHolder holder=null ;//設置靜態類使其初始化 188 if(convertView==null){ 189 190 holder = new ViewHolder();//創建holder對象 191 view = View.inflate(MainPage.this, R.layout.item,null ); 192 193 holder.iv_head = (ImageView) view.findViewById(R.id.iv_head); 194 holder.tv_name = (TextView) view.findViewById(R.id.tv_n); 195 holder.tv_sex = (TextView) view.findViewById(R.id.tv_s); 196 197 view.setTag(holder);//用來保存一些數據結構。 198 }else{ 199 view=convertView;//復用歷史緩存 200 holder=(ViewHolder) view.getTag(); 201 202 } 203 name2 = list.get(position).getName(); 204 sex2 = list.get(position).getSex(); 205 if("男".equals(sex2)){ //區分性別 206 holder.iv_head.setImageResource(R.drawable.nan); 207 }else{ 208 holder.iv_head.setImageResource(R.drawable.nv); 209 } 210 holder.tv_name.setText(name2); 211 holder.tv_sex.setText(sex2); 212 return view; 213 } 214 @Override 215 public int getCount() { 216 return list.size(); //返回list集合中的數據個數 217 } 218 219 @Override 220 public Object getItem(int position) { 221 222 return null; 223 } 224 225 @Override 226 public long getItemId(int position) { 227 228 return 0; 229 } 230 231 232 233 } 234 //ViewHolder靜態類 235 static class ViewHolder{ 236 ImageView iv_head; 237 TextView tv_name; 238 TextView tv_sex; 239 } 240 241 }
Student
1 package com.hb.bean; 2 3 public class Student { 4 private String name; 5 private String sex; 6 public Student(){ 7 } 8 public Student(String name){ 9 this.name = name; 10 } 11 public Student(String name, String sex) { 12 super(); 13 this.name = name; 14 this.sex = sex; 15 } 16 17 public String getName() { 18 return name; 19 } 20 public void setName(String name) { 21 this.name = name; 22 } 23 public String getSex() { 24 return sex; 25 } 26 public void setSex(String sex) { 27 this.sex = sex; 28 } 29 30 }
sqlDao
1 package com.hb.dao; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import android.content.ContentValues; 7 import android.content.Context; 8 import android.database.Cursor; 9 import android.database.sqlite.SQLiteDatabase; 10 11 import com.hb.bean.Student; 12 import com.hb.helper.OpenHelper; 13 14 public class SqlDao { 15 16 private OpenHelper helper; 17 public SqlDao(Context context) { 18 helper=new OpenHelper(context); 19 } 20 /** 21 * 添加 22 * @param stu 23 * @return 24 */ 25 public boolean add(Student stu){ 26 SQLiteDatabase db = helper.getWritableDatabase(); 27 ContentValues values = new ContentValues(); 28 values.put("name", stu.getName().toString()); 29 values.put("sex", stu.getSex().toString()); 30 long insert = db.insert("student", null, values); 31 db.close(); 32 if(insert !=-1){ 33 return true; 34 }else{ 35 return false; 36 } 37 } 38 /** 39 * 刪除 40 * @param name 41 */ 42 public void delete(String name){ 43 SQLiteDatabase db = helper.getWritableDatabase(); 44 // db.execSQL("delete student where name =?",new String[]{name}); 45 db.delete("student", "name=?", new String[]{name}); 46 db.close(); 47 } 48 /** 49 * 修改 50 * @param name 51 * @param newsex 52 */ 53 public void update(String name, String newsex){ 54 SQLiteDatabase db = helper.getWritableDatabase(); 55 db.execSQL("update student set sex=? where name=?",new Object[]{name,newsex}); 56 db.close(); 57 } 58 /** 59 *查找學生姓名 60 * @param stu 61 * @return 62 */ 63 public Student findName(Student stu2 ){ 64 SQLiteDatabase db = helper.getReadableDatabase(); 65 Cursor cursor = db.rawQuery("select * from student where name=?", new String[]{stu2.getName()}); 66 Student s = new Student(); 67 while(cursor.moveToNext()){ 68 // String name = cursor.getString(1); 69 s.setName(stu2.getName()); 70 } 71 cursor.close(); 72 db.close(); 73 return s; 74 } 75 //查詢所有學生 76 public List<Student> findAll(){ 77 SQLiteDatabase db = helper.getReadableDatabase(); 78 List<Student> list =new ArrayList<Student>(); 79 Cursor cursor = db.query("student", null, null, null, null, null, null); 80 while(cursor.moveToNext()){ 81 //創建學生對象 82 Student s = new Student(); 83 String name = cursor.getString(1); 84 String sex = cursor.getString(2); 85 //添加到學生bean里面 86 s.setName(name); 87 s.setSex(sex); 88 list.add(s); 89 } 90 db.close(); 91 cursor.close(); 92 return list; 93 94 } 95 }
OpenHelper
1 package com.hb.helper; 2 3 import android.content.Context; 4 import android.database.sqlite.SQLiteDatabase; 5 import android.database.sqlite.SQLiteOpenHelper; 6 7 public class OpenHelper extends SQLiteOpenHelper { 8 9 public OpenHelper(Context context) { 10 super(context, "db.student", null, 1); 11 } 12 13 14 @Override 15 public void onCreate(SQLiteDatabase db) { 16 db.execSQL("create table student (_id integer primary key autoincrement,name varchar(20),sex varchar(3))"); 17 } 18 19 @Override 20 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 21 22 } 23 24 }
MainActivity
1 package com.hb.system.activity; 2 3 import com.example.studentinformationsystem.R; 4 5 import android.app.Activity; 6 import android.content.Intent; 7 import android.os.Bundle; 8 import android.view.View; 9 import android.view.View.OnClickListener; 10 import android.widget.Button; 11 import android.widget.EditText; 12 import android.widget.Toast; 13 14 15 public class MainActivity extends Activity { 16 private Button bt_login; 17 private EditText et_name; 18 private EditText et_pw; 19 private String name; 20 private String pw; 21 @Override 22 protected void onCreate(Bundle savedInstanceState) { 23 super.onCreate(savedInstanceState); 24 setContentView(R.layout.activity_main); 25 26 bt_login=(Button) findViewById(R.id.bt_login); 27 et_name=(EditText) findViewById(R.id.et_name); 28 et_pw=(EditText) findViewById(R.id.et_pw); 29 30 31 bt_login.setOnClickListener(new OnClickListener() { 32 @Override 33 public void onClick(View v) { 34 name = et_name.getText().toString().trim(); 35 pw = et_pw.getText().toString().trim(); 36 if(("123").equals(name) && ("123").equals(pw)){ 37 startActivity(new Intent(MainActivity.this, MainPage.class)); 38 }else{ 39 Toast.makeText(MainActivity.this, "密碼或賬號錯誤!", Toast.LENGTH_SHORT).show(); 40 } 41 } 42 }); 43 } 44 }
下面的是一些布局代碼
activity_main.xml
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 android:padding="15dp" > 7 8 <ImageView 9 android:id="@+id/iv_head" 10 android:layout_width="80dp" 11 android:layout_height="80dp" 12 android:layout_gravity="center" 13 android:background="@drawable/head" /> 14 15 <LinearLayout 16 android:layout_width="match_parent" 17 android:layout_height="wrap_content" 18 android:orientation="horizontal" > 19 20 <TextView 21 android:id="@+id/tv_name" 22 android:layout_width="wrap_content" 23 android:layout_height="wrap_content" 24 android:text="學號 :" 25 android:textSize="25sp" /> 26 27 <EditText 28 android:id="@+id/et_name" 29 android:layout_width="match_parent" 30 android:layout_height="wrap_content" 31 android:textSize="20sp" /> 32 </LinearLayout> 33 34 <LinearLayout 35 android:layout_width="match_parent" 36 android:layout_height="wrap_content" 37 android:orientation="horizontal" > 38 39 <TextView 40 android:id="@+id/tv_pw" 41 android:layout_width="wrap_content" 42 android:layout_height="wrap_content" 43 android:text="密碼 :" 44 android:textSize="25sp" /> 45 46 <EditText 47 android:id="@+id/et_pw" 48 android:layout_width="match_parent" 49 android:layout_height="wrap_content" 50 android:inputType="textPassword" 51 android:textSize="20sp" /> 52 </LinearLayout> 53 54 <Button 55 android:id="@+id/bt_login" 56 android:layout_width="match_parent" 57 android:layout_height="wrap_content" 58 android:layout_gravity="center" 59 android:layout_marginTop="50dp" 60 android:text="登錄" /> 61 62 </LinearLayout>
adapter_popu_window.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" 5 android:background="@drawable/local_popup_bg" 6 android:gravity="center_vertical" 7 android:orientation="horizontal" > 8 9 <TextView 10 android:id="@+id/tv_delete" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="刪除" 14 android:textColor="@android:color/holo_red_light" 15 android:textSize="15dip" /> 16 17 </LinearLayout>
item.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="horizontal" 6 android:padding="10dp" 7 android:gravity="center"> 8 9 <ImageView 10 android:layout_gravity="center" 11 android:id="@+id/iv_head" 12 android:layout_width="30dp" 13 android:layout_height="30dp" 14 android:layout_weight="1" 15 /> 16 17 <TextView 18 19 android:id="@+id/tv_n" 20 android:layout_weight="1" 21 android:layout_width="0dp" 22 android:textSize="25dp" 23 android:layout_height="wrap_content" 24 android:text="張三" 25 /> 26 27 <TextView 28 android:gravity="center" 29 android:id="@+id/tv_s" 30 android:layout_weight="1" 31 android:layout_width="0dp" 32 android:textSize="25dp" 33 android:layout_height="wrap_content" 34 android:text="男" 35 /> 36 37 </LinearLayout>
mainpage.xml

1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 xmlns:android1="http://schemas.android.com/apk/res/android" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:orientation="vertical" 7 android:padding="10dp" > 8 9 <LinearLayout 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:layout_marginTop="25dp" 13 android:orientation="horizontal" > 14 15 <TextView 16 android:id="@+id/tv" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:text="姓名 :" 20 android:textSize="25sp" /> 21 22 <EditText 23 android:id="@+id/et_name" 24 android:layout_width="match_parent" 25 android:layout_height="wrap_content" 26 android:textSize="20sp" /> 27 </LinearLayout> 28 29 <LinearLayout 30 android:layout_width="match_parent" 31 android:layout_height="wrap_content" 32 android1:layout_marginTop="25dp" 33 android:gravity="center" 34 android1:orientation="horizontal" > 35 36 <TextView 37 android1:id="@+id/tv_sex" 38 android1:layout_width="0dp" 39 android1:layout_height="wrap_content" 40 android1:layout_weight="1" 41 android1:text="性別 :" 42 android1:textSize="25sp" /> 43 44 <RadioGroup 45 android1:id="@+id/rg_group" 46 android1:layout_width="0dp" 47 android1:layout_height="wrap_content" 48 android1:layout_weight="1" 49 android:gravity="center" 50 android1:orientation="horizontal" > 51 52 <RadioButton 53 android1:id="@+id/boy" 54 android1:layout_width="wrap_content" 55 android1:layout_height="wrap_content" 56 android1:checked="true" 57 android1:text="男" /> 58 59 <RadioButton 60 android1:id="@+id/girl" 61 android1:layout_width="wrap_content" 62 android1:layout_height="wrap_content" 63 android1:text="女" /> 64 </RadioGroup> 65 66 <TextView 67 android1:id="@+id/tv_showsex" 68 android1:layout_width="0dp" 69 android1:layout_height="wrap_content" 70 android1:layout_weight="1" 71 android:gravity="center" 72 android1:text="男" /> 73 </LinearLayout> 74 75 <Button 76 android1:id="@+id/bt_add" 77 android1:layout_width="fill_parent" 78 android1:layout_height="wrap_content" 79 android1:layout_marginTop="20dp" 80 android1:text="增 加" /> 81 82 <LinearLayout 83 android:layout_width="match_parent" 84 android:layout_height="wrap_content" > 85 86 <TextView 87 android1:id="@+id/stu_head" 88 android1:layout_width="wrap_content" 89 android1:layout_height="wrap_content" 90 android1:layout_weight="1" 91 android1:gravity="center" 92 android1:text="頭像" 93 android1:textSize="25sp" /> 94 <TextView 95 android1:id="@+id/stu_name" 96 android1:layout_width="wrap_content" 97 android1:layout_height="wrap_content" 98 android1:layout_weight="1" 99 android1:gravity="center" 100 android1:text="姓名" 101 android1:textSize="25sp" /> 102 103 <TextView 104 android:id="@+id/stu_sex" 105 android:layout_width="wrap_content" 106 android:layout_height="wrap_content" 107 android:layout_weight="1" 108 android:gravity="center" 109 android:text="性別" 110 android:textSize="25sp" /> 111 </LinearLayout> 112 113 <ListView 114 android1:id="@+id/listView1" 115 android1:layout_width="match_parent" 116 android1:layout_height="wrap_content" > 117 </ListView> 118 119 </LinearLayout>
項目源碼:http://pan.baidu.com/s/1i4ZXUCl