Android中的SQLite、ListView、ContextMenu使用学习

jopen 12年前
     <p><strong><big>通过CursorAdapter在ListView中的数据呈现</big></strong></p>    <p style="margin-top:15px;margin-bottom:15px;">在上一个例子中,我们可以对SQLite中的数据库进行增删改查,将数据读到游标Cursor中,然后一一读出。在Android中可以通过CursorAdapter直接将数据映射到ListView中,如下处理:</p>    <p style="border-bottom:#ffbcbc thin dashed;border-left:#ffbcbc thin dashed;padding-bottom:5pt;line-height:140%;background-color:#ffffea;padding-left:5pt;padding-right:5pt;font-family:微软雅黑;margin-left:10pt;font-size:9pt;border-top:#ffbcbc thin dashed;border-right:#ffbcbc thin dashed;padding-top:5pt;"><img style="width:233px;height:381px;" alt="Android中的SQLite、ListView、ContextMenu使用学习 " align="right" src="https://simg.open-open.com/show/bccbe47ab01f206b4b8c845be3dfbc7b.png" /><span style="color:#999999;">public class Chapter22Test1 extends ListActivity{</span><br /> <span style="color:#999999;">    private SQLiteDatabase  db = null;<br />     private Cursor cursor = null;    </span><br />    <span style="color:#999999;"> private <span style="color:#333333;"><strong>SimpleCursorAdapter</strong></span> adapter = null;</span><br /> <br />     protected void onCreate(Bundle savedInstanceState) {<br />          <span style="color:#999999;">super.onCreate(savedInstanceState);</span><br />         db= (new Chapter22Db (getApplicationContext())).getWritableDatabase();    <br />         cursor =db.rawQuery("SELECT _id,Name,Weight from mytable ORDER BY Weight", null);<br /> <span style="color:#3366ff;">        //layout/chapter_22_test1.xml的Android XML文件定义了ListView中每个单元的排列方式,每个单元R.id.c22_name和R.id.c22_gravity都是TextView,分列左右</span><br />         adapter = new <strong>SimpleCursorAdapter</strong>(this,<br />                 R.layout.chapter_22_test1, <br />                 cursor, <br />                 new String[]{"<span style="color:#666666;"><em>Name</em></span>","<em><span style="color:#666666;">Weight</span></em>"},<span style="color:#3366ff;">//游标数据的名称,实际是Table列名字</span><br />                 new int[]{<strong>R.id.c22_name</strong>,<strong> R.id.c22_gravity</strong>});<span style="color:#3366ff;">//对应的UI微件的id</span><br />         setListAdapter(adapter);<br />     }<br /> <br />     protected void onDestroy() {<br /> <span style="color:#999999;">        super.onDestroy();</span><br />         <strong>cursor.close();</strong> <span style="color:#3366ff;"> //我们在onCreate()中没有关闭游标,因为需要和ListView进行数据关联,关闭curosr,会导致List无数据,故在最后释放资源</span><br />         <strong>db.close();</strong> <span style="color:#3366ff;">//断开和数据库的连接,释放相关资源</span><br />     }<br /> }</p>    <p style="margin-top:18px;margin-bottom:18px;"><strong><big>更新数据(以增加为例)</big></strong></p>    <p style="margin-top:15px;margin-bottom:15px;">我们要实现:通过Menu弹出菜单,有一个为增加,按之,弹出一个Dialog,可以在当中填入数据,按Dialog的确定按键,在SQLite数据库的表格mytable中加入相关的数据,并且同步ListView的显示。</p>    <p style="margin-top:15px;margin-bottom:15px;">第一步:建立OptionsMenu,里面有菜单“Add”,按键后,触发执行add()的操作。<a href="/misc/goto?guid=4959517975759585508"></a></p>    <p style="margin-top:15px;margin-bottom:15px;">第二步:在add()中,要完成弹出指定格式的 Dialog,采用AlertDialog的方式,Dialog的格式在xml中给出。处理方式之前都学过,但是没有合并使用的例子,包括Dialog的 格式,同ListView中自定义元素的格式一样,采用LayoutInflater。具体如下:</p>    <p style="border-bottom:#ffbcbc thin dashed;border-left:#ffbcbc thin dashed;padding-bottom:5pt;line-height:140%;background-color:#ffffea;padding-left:5pt;padding-right:5pt;font-family:微软雅黑;margin-left:10pt;font-size:9pt;border-top:#ffbcbc thin dashed;border-right:#ffbcbc thin dashed;padding-top:5pt;"><img style="width:212px;height:351px;" alt="Android中的SQLite、ListView、ContextMenu使用学习 " align="right" src="https://simg.open-open.com/show/8dd04ed0ad48c060f52b12ae92ad43fe.png" />private void add(){<br />    <span style="color:#3366ff;"> //步骤2.1:通过LayoutInflater从Android的XML文件中生成View</span><br />     LayoutInflater inflater = LayoutInflater.from(this);<br />     <strong>final</strong> View addView = inflater.inflate(R.layout.add_dialgo,null);<br /> <br />     <span style="color:#3366ff;">//步骤2.2:通过AlertDialog弹出对话框,并且在第一个button,即PositiveButton监听事件,触发操作</span><br />     new <strong>AlertDialog.Builder</strong>(this)<br />     .setTitle("添加框")<br />     .setView(addView)<br />     .setPositiveButton("确定", new DialogInterface.OnClickListener() {<br /> <span style="color:#3366ff;">        //我们希望得到addView中的数据,但是这个inner class,只能获取final的值,所以之前将addView设置为final,也就是所有addView的地址是固定的,而不是动态生成。</span><br />         public void onClick(DialogInterface dialog, int which) {<br /> <span style="color:#999999;">            EditText nameView = (EditText)addView.findViewById(R.id.c22_name);<br />             EditText weigthView = (EditText)addView.findViewById(R.id.c22_weight);</span><br />            <span style="color:#3366ff;"> // addData是下面步骤三,实现SQLite的数据更新和ListView的显示同步add(name,weight);</span><br />             addData(<span style="color:#999999;">nameView.getText().toString(), new Float(weigthView.getText().toString()).floatValue()</span>);<br />         }<br />     })<br />     .setNegativeButton("取消",null)<br />     .show();<br /> }</p>    <p style="margin-top:15px;margin-bottom:15px;">第三步:更新数据库和同步ListView,具体如下:</p>    <p style="border-bottom:#ffbcbc thin dashed;border-left:#ffbcbc thin dashed;padding-bottom:5pt;line-height:140%;background-color:#ffffea;padding-left:5pt;padding-right:5pt;font-family:微软雅黑;margin-left:10pt;font-size:9pt;border-top:#ffbcbc thin dashed;border-right:#ffbcbc thin dashed;padding-top:5pt;"><img style="width:308px;height:164px;" alt="Android中的SQLite、ListView、ContextMenu使用学习 " align="right" src="https://simg.open-open.com/show/42f6d290e75ac91fe0e31d83202dfbcf.png" />    private void addData(String name ,float weight){<br />        <span style="color:#993300;"> <span style="color:#9999ff;">/* 略去数据的判断,例如如果name一样,采用update的方式等等*/</span></span><span style="color:#3366ff;"><br />         //步骤3.1 在数据库表格中添加数据</span><br />         ContentValues values = new ContentValues(2);<br />         values.put("Name",name);<br />         values.put("Weight",weight);<br />         db.insert("mytable","Name",values);<br />         <span style="color:#3366ff;">//步骤3.2 同步ListView,更新游标的信息</span><br />         cursor.<span style="color:#330000;"><strong>requery</strong></span>();<br />     }</p>    <p style="margin-top:15px;margin-bottom:15px;"><strong><big>异步后台同步数据</big></strong></p>    <p style="margin-top:15px;margin-bottom:15px;">在上面的例子,貌似可以,而且的确是可以,但是在Android的API文档中,Cursor的方法requery()这样写道:<em>This method is deprecated.Don't use this. Just request a new cursor, so you can do this asynchronously and update your list view once the new cursor comes back.</em> 这提示我们风险的存在,如果数据量大,会导致重写读取的事件长(也就是requery()的执行时间)。虽然手机是人手操作,互动频率较低,在数据库数据 少的时候,例如上面的例子,我们仍然可以安全地使用requery。但是对于具有大量数据时,我们就需要修改上面的程序。</p>    <p style="margin-top:15px;margin-bottom:15px;">修订的方式步骤如下:1,通过后台线程来读取数据库;2、通过更换cursor来更新ListView,具体如下:</p>    <p style="border-bottom:#ffbcbc thin dashed;border-left:#ffbcbc thin dashed;padding-bottom:5pt;line-height:140%;background-color:#ffffea;padding-left:5pt;padding-right:5pt;font-family:微软雅黑;margin-left:10pt;font-size:9pt;border-top:#ffbcbc thin dashed;border-right:#ffbcbc thin dashed;padding-top:5pt;"><span style="color:#3366ff;">//步骤1:通过后台线程AsyncTask来读取数据库,放入更换Cursor</span><br /> private class RefreshList extends <strong>AsyncTask</strong>     <void, ,cursor="" void="">      {      <br />          <span style="color:#3366ff;">//步骤1.1:在后台线程中从数据库读取,返回新的游标newCursor</span>      <br />     protected Cursor doInBackground(Void... params) {      <br />              <span style="color:#999999;"> Cursor newCursor =  db.rawQuery("SELECT _id,Name,Weight from mytable ORDER BY Weight", null);</span>      <br />         return newCursor;      <br />     }      <br />          <span style="color:#3366ff;"> //步骤1.2:线程最后执行步骤,更换adapter的游标,并奖原游标关闭,释放资源  </span>      <br />     protected void onPostExecute(Cursor newCursor) {      <br />         adapter.      <span style="color:#cc0000;"><strong>changeCursor</strong></span>(      <em>newCursor</em>);      <span style="color:#3366ff;">//网上看到很多问如何更新ListView的信息,采用CusorApater其实很简单,换cursor就可以</span>      <br />         cursor.close();      <br />         cursor = newCursor;      <br />     }              <br /> }      <br />      <span style="color:#3366ff;">//步骤2:取缔requrey的方式,采用后台线程更新形式</span>      <br /> private void addData(String name ,float weight){      <br />         <span style="color:#990000;">   ... ...</span>      <br />          <span style="color:#999999;"> //cursor.requery();</span>      <br />     new RefreshList().execute();      <br /> }     </void,></p>    <p style="margin-top:15px;margin-bottom:15px;"><strong><big>通过ContextMenu来删除ListView的数据</big></strong></p>    <p style="margin-top:15px;margin-bottom:15px;">ContextMenu用户手指长按某个View触发的菜单。这里通过这个例子详细展开。实现场景:用户长按某个List元素,则弹出ContextMenu,选择菜单“Delete”,按下后,弹出AlertDialog,请用户再去确定是否删除,确定后将数据从SQLite中删除,并更新ListView的显示。具体如下:</p>    <div style="border-bottom:#ffbcbc thin dashed;border-left:#ffbcbc thin dashed;padding-bottom:5pt;line-height:140%;background-color:#ffffea;padding-left:5pt;padding-right:5pt;font-family:微软雅黑;margin-left:10pt;font-size:9pt;border-top:#ffbcbc thin dashed;border-right:#ffbcbc thin dashed;padding-top:5pt;">     <table class="ke-zeroborder" border="0" align="right">      <tbody>       <tr>        <td><img style="width:145px;height:235px;" alt="Android中的SQLite、ListView、ContextMenu使用学习 " src="https://simg.open-open.com/show/4353e7e8d264359bb32b51c729815fe5.png" /><br /> <br /> <img style="width:156px;height:252px;" alt="Android中的SQLite、ListView、ContextMenu使用学习 " src="https://simg.open-open.com/show/3e653da74c46eae493d9b4983095fdad.png" /><br /> <br /> <img style="width:156px;height:242px;" alt="Android中的SQLite、ListView、ContextMenu使用学习 " src="https://simg.open-open.com/show/9884c49cdc4dc36b262927bcdc3f8a9e.png" /></td>       </tr>      </tbody>     </table>     protected void onCreate(Bundle savedInstanceState) {     <br />         ... ...     <br />             <span style="color:#3366ff;">//步骤1:向ListView注册Context Menu,当系统检测到用户长按某单元是,触发Context Menu弹出</span>     <br />             <strong>registerForContextMenu</strong>(getListView());     <br />     }     <br />     <span style="color:#3366ff;"><br />     // 步骤2:创建ContextMenu同OptionMenu,用户长按元素后,会弹出菜单</span>     <br />     public void     <strong>onCreateContextMenu</strong>(ContextMenu menu, View v,  ContextMenuInfo menuInfo) {     <br />         menu.add(Menu.NONE,DELETE_ID,Menu.NONE,"Delete");     <br />            <span style="color:#999999;"> super.onCreateContextMenu(menu, v, menuInfo);</span>     <br />     }     <br />     <br />     <span style="color:#3366ff;">    //步骤 3: ContextMenu的触发操作,例子将触发delete()</span>     <br />     public boolean     <strong>onContextItemSelected</strong>(MenuItem item) {     <br />         switch(item.getItemId()){     <br />         case DELETE_ID:     <span style="color:#3366ff;"><br />             /* 在此处,我们关键引入 AdapterView.AdapterContextMenuInfo来获取单元的信息。在有三个重要的信息。 1、id:The row id of the item for which the context menu is being displayed ,在cursorAdaptor中,实际就是表格的_id序号; 2、position 是list的元素的顺序;3、view就可以获得list中点击元素的View,通过view可以获取里面的显示的信息   */</span>     <br />             AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();     <br />             delete(info.id);     <br />     <span style="color:#999999;">            return true;<br />         default:<br />             break;</span>     <br />         }     <br />              <span style="color:#999999;">return super.onContextItemSelected(item);</span>     <br />     }     <br />     <br />         <span style="color:#3366ff;">//步骤4: 对触发弹框,和Add的相似,确定后,更新数据库和更新ListView的显示,其中getNameById是通过id查名字的方法,上次学习已有相类的例子,不再重复。值得注意的是,为了内部类中使用,delete的参数采用来final的形式。</span>     <br />     private void delete(final long  rowId){     <br />         if(rowId>0){     <br />             new     <strong>AlertDialog.Builder</strong>(this)     <br />     <span style="color:#999999;">            .setTitle("删除" + getNameById(rowId))<br />             .setPositiveButton("确定", new DialogInterface.OnClickListener() {<br />                 public void onClick(DialogInterface dialog, int which) {<br />                       <span style="color:#333333;">deleteData</span>(rowId);<br />                 }<br />             })<br />             .setNegativeButton("取消", null)<br />             .show();</span>     <br />         }     <br />     }     <br />          <br />     private void deleteData(long rowId){     <br />     <span style="color:#999999;">        String[] str = {String.valueOf(rowId)};<br />         db.<span style="color:#333333;"><strong>delete</strong></span>("mytable","_id=?",str);</span>     <br />         new RefreshList().execute();      <span style="color:#3366ff;">//采用后台方式,当然也可以用crusor.requery()来处理。</span>     <br />     }     <br />    </div>    <p style="margin-top:15px;margin-bottom:15px;"><strong><big>通过模拟器的Console进行数据库操作</big></strong></p> 通过android-sdk-linux_x86/platform-tools目录下面有adb命令,使用adb shell,可提供模拟器的console窗口。数据库文件存放的位置为/data/data/    <span style="font-style:italic;">your.app.package</span>/databases/    <span style="font-style:italic;">your-db-name</span>,进入相关的目录,可以使用#sqlite3 your-db-name,进入相关的数据库,可以在里面执行SQL语句,例如在整个例子中,通过#.schema来查看表格的格式,通过#select * from mytable;可以显示数据库的内容。    <br />    <br /> 来自:http://blog.csdn.net/flowingflying/article/details/6846991