一、提要
这个实例整合了前面学过的一些组件(intent,handler,ListView...),也加入了一些新的东西(dialog,LayoutInflater),最主要的是在应用中整合了Sqlite。
应用的名字是Getting Things Done的缩写,类似于一个记事本,有拖延症的同学可以试用一下。listview用于显示条目,单击Item可以查看详细,menu中可以添加条目。
二、遇到的问题及解决方法
1.如何修改应用名称及应用图标
修改程序的图标,修改drawable文件夹的i→→c_launcher.png图标,把新的图标改名覆盖就可以了。
如果你要自己的名称,可以修改AndroidManifest.xml的这个节点,application android:icon="@drawable/ic_launcher",不需要加文件扩展名。
即使这么做了,真机调试的时候可能还是会有一些问题,比如图标没办法改变,这个时候就需要在Eclipse中新建一个不同名的项目,然后转移代码(有点小麻烦~_~!)。2.关于调试方法
调试的时候程序如果出错,一般是查看logcat,看error发生的地方,会提示在程序的第几行,然后去找就可以了。
但有些错误没办法定位,那就把日志输出成txt,然后去google,baidu吧。
3.Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
错误1:请求的字段在数据库的表中不存在,一般是大小写没写对;
错误2:编程的中途改变表的字段,实际字段并没有改变,解决方法是卸载当前版本,再安装调试。
4.android.content.res.Resources.loadXmlResourceParser
在传递string类做参数的地方传了int形变量。
5.android.content.res.Resources$NotFoundException
出现此类异常时,可以根据 Resource ID到资源类R中找相关的资源。比如0x7f030000,对应的是city_item布局文件,就可以将问题缩小到更小的范围。对于这类运行时找不到资源,但资源又确实存在的问题,可能的编译打包时出现问题,没有将该资源加入。可修改一下该资源,让编译器重新编译。
还有试一下Project ->Clean一下这个项目 也可以的。
三、代码清单
GDT.java
主Activity,显示列表,响应事件。
package com.example.gtd;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
public class GTD extends Activity {
private DBManager mgr;
private ListView myListView;
private SimpleAdapter myAdapter=null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gtd);
myListView=(ListView)findViewById(R.id.listView);
//初始化DBManager
mgr = new DBManager(this);
myListView.setOnItemClickListener(new OnItemClickListenerImpl());
//this.add(myListView);
this.query(myListView);
}
@Override
protected void onDestroy() {
super.onDestroy();
//应用的最后一个Activity关闭时应释放DB
mgr.closeDB();
}
public void add(View view) {
ArrayList<Thing> things = new ArrayList<Thing>();
Thing thing1 = new Thing("Eat","get some food");
Thing thing2 = new Thing("Play","play a game");
things.add(thing1);
things.add(thing2);
mgr.add(things);
System.out.print("Add done!");
}
public void query(View view) {
List<Thing> things = mgr.query();
ArrayList<Map<String, String>> mylist = new ArrayList<Map<String, String>>();
for (Thing thing : things) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("title", thing.title);
map.put("content", thing.content);
System.out.println(thing.title+thing.content);
mylist.add(map);
}
myAdapter= new SimpleAdapter(this, //没什么解释
mylist,//数据来源
R.layout.my_listitem,//ListItem的XML实现
//动态数组与ListItem对应的子项
new String[] {"title", "content"},
//ListItem的XML文件里面的两个TextView ID
new int[] {R.id.ItemTitle,R.id.ItemText});
//添加并且显示
myListView.setAdapter(myAdapter);
System.out.println("queryHere");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0,1,1,R.string.add);
menu.add(0,2,2,R.string.about);
menu.add(0,3,3,R.string.exit);
//getMenuInflater().inflate(R.menu.activity_gtd, menu);
return true;
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
// TODO Auto-generated method stub
if(item.getItemId()==1)showAddDialog();
if(item.getItemId()==2) new AlertDialog.Builder(this) .setTitle("About") .setMessage("Powerd By Empty.") .show();
if(item.getItemId()==3) finish();
return super.onMenuItemSelected(featureId, item);
}
public void updateList()
{
query(myListView);
}
protected void showAddDialog() {
LayoutInflater factory = LayoutInflater.from(this);
final View textEntryView = factory.inflate(R.layout.add_dialog, null);
final EditText editTextName = (EditText) textEntryView.findViewById(R.id.editTextName);
final EditText editTextNumEditText = (EditText)textEntryView.findViewById(R.id.editTextNum);
AlertDialog.Builder ad1 = new AlertDialog.Builder(GTD.this);
ad1.setTitle("Add a thing:");
ad1.setIcon(android.R.drawable.ic_dialog_alert);
ad1.setView(textEntryView);
ad1.setPositiveButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int i) {
}
});
ad1.setNegativeButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int i) {
Thing thing = new Thing(editTextName.getText().toString(),editTextNumEditText.getText().toString());
mgr.addOneThing(thing);
updateList();
}
});
ad1.show();// 显示对话框
}
private class OnItemClickListenerImpl implements OnItemClickListener {
@SuppressWarnings("unchecked")
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
//获得选中项的HashMap对象
HashMap<String,String> map=(HashMap<String,String>)myListView.getItemAtPosition(arg2);
String title=map.get("title");
String content=map.get("content");
System.out.println("ItemClick"+title+content);
final Thing tmpThing=new Thing(title,content);
//Toast.makeText(getApplicationContext(),
// "你选择了第"+arg2+"个Item,itemTitle的值是:"+title+"itemContent的值是:"+content,
// Toast.LENGTH_SHORT).show();
new AlertDialog.Builder(GTD.this)
.setTitle(tmpThing.title+"")//设置标题
.setMessage(tmpThing.content)//设置提示消息
/*
.setPositiveButton("Finished",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//do something
mgr.finishThing(tmpThing);
}
})*/
.setNegativeButton("Delete",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//do something
mgr.deleteThing(tmpThing);
updateList();
}
})
.setNeutralButton("Cancel",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//do something
}
})
.setCancelable(false)//设置按返回键是否响应返回,这是是不响应
.show();//显示
}
}
}
SplashScreen.java
最简单的闪屏类,这个就不多解释了,注意handler的用法。
package com.example.gtd;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ImageView;
import android.widget.TextView;
public class SplashScreen extends Activity {
private ImageView logoView;
private TextView rightView;
private final int SPLASH_DISPLAY_LENGHT = 3000; //延迟三秒
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen);
logoView=(ImageView)findViewById(R.id.imageView1);
rightView=(TextView)findViewById(R.id.textView1);
//logoView.setAlpha(alpha);
new Handler().postDelayed(new Runnable(){
@Override
public void run() {
Intent mainIntent = new Intent(SplashScreen.this, GTD.class);
SplashScreen.this.startActivity(mainIntent);
SplashScreen.this.finish();
}
}, SPLASH_DISPLAY_LENGHT);
//updateThread.run();
}
}
DBHelper.java
继承SQLiteOpenHelper,负责创建数据库,打开数据库。
package com.example.gtd;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "test.db";
private static final int DATABASE_VERSION = 1;
public DBHelper(Context context) {
//CursorFactory设置为null,使用默认值
super(context, DATABASE_NAME, null, DATABASE_VERSION);
System.out.println("New DBHelper!");
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
Log.d("DB", "New DB!");
System.out.println("New DB!");
db.execSQL("CREATE TABLE IF NOT EXISTS thing" +
"(_id INTEGER PRIMARY KEY AUTOINCREMENT, title VARCHAR, detail VARCHAR,isdone INTEGER)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("ALTER TABLE thing ADD COLUMN other STRING");
}
}
DBManager.java
对数据库的操作进行了封装。
package com.example.gtd;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class DBManager {
private DBHelper helper;
private SQLiteDatabase db;
public DBManager(Context context) {
helper = new DBHelper(context);
System.out.println("New DBManager!");
//因为getWritableDatabase内部调用了mContext.openOrCreateDatabase(mName, 0, mFactory);
//所以要确保context已初始化,我们可以把实例化DBManager的步骤放在Activity的onCreate里
db = helper.getWritableDatabase();
}
public void add(List<Thing> things) {
db.beginTransaction(); //开始事务
try {
for (Thing thing: things) {
db.execSQL("INSERT INTO thing VALUES(null, ?, ?, ?)", new Object[]{thing.title, thing.content, 0});
}
db.setTransactionSuccessful(); //设置事务成功完成
} finally {
db.endTransaction(); //结束事务
}
}
public void addOneThing(Thing thing)
{
db.execSQL("INSERT INTO thing VALUES(null, ?, ?, ?)", new Object[]{thing.title, thing.content, 0});
}
public void updateAge(Thing thing) {
ContentValues cv = new ContentValues();
cv.put("isdone", thing.isdone);
db.update("thing", cv, "title = ?", new String[]{thing.title});
}
public void finishThing(Thing thing)
{
ContentValues cv = new ContentValues();
cv.put("isdone", 1);
db.update("thing", cv, "title = ?", new String[]{thing.title});
}
public void deleteThing(Thing thing) {
db.delete("thing", "title= ?", new String[]{thing.title});
System.out.print("delete thing");
}
public List<Thing> query() {
ArrayList<Thing> things = new ArrayList<Thing>();
Cursor c = queryTheCursor();
if(c.moveToLast())
while (!c.isBeforeFirst()) {
Thing thing = new Thing();
thing._id = c.getInt(c.getColumnIndex("_id"));
thing.title = c.getString(c.getColumnIndex("title"));
//System.out.println("c.getColumnIndex(detail)"+c.getColumnIndex("detail"));
thing.content = c.getString(c.getColumnIndex("detail"));
thing.isdone = c.getInt(c.getColumnIndex("isdone"));
things.add(thing);
c.moveToPrevious();
}
c.close();
return things;
}
public Cursor queryTheCursor() {
Cursor c = db.rawQuery("SELECT * FROM thing", null);
return c;
}
/**
* close database
*/
public void closeDB() {
db.close();
}
}
Thing.java
待办事类,定义了成员和构造函数。
package com.example.gtd;
public class Thing {
public int _id;
public String title;
public String content;
public int isdone;
public Thing() {
}
public Thing(String title,String content) {
this.title = title;
this.content = content;
}
}
下面是布局文件
splash_screen.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:weightSum="1"
android:background="#FFFFFF">
<ImageView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:src="@drawable/logo"
android:id="@+id/imageView1"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_marginTop="150dp">
</ImageView>
<TextView android:text="@string/copyright"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:id="@+id/textView1"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="14dp">
</TextView>
</RelativeLayout>
activity_gtd.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
add_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title" />
<EditText
android:id="@+id/editTextName"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<requestFocus />
</EditText>
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Content" />
<EditText
android:id="@+id/editTextNum"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
my_listitem.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/myListItem"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="3dip"
android:paddingLeft="10dip" >
<TextView
android:id="@+id/ItemTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="30dip" >
</TextView>
<TextView
android:id="@+id/ItemText"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</TextView>
</LinearLayout>
参考资料:
常用的dialog:http://blog.csdn.net/chenlei1889/article/details/6267406
Android中SQLite应用详解:http://blog.csdn.net/liuhe688/article/details/6715983
Android 实例-个人理财工具:http://blog.csdn.net/untosil/article/details/3267086