事务:
银行转账
张三 给李四 200;
张三的账户 -200块钱
//sql语句
李四的账户 +200块钱
//sql语句
android下使用数据库的事务
1.打开数据库的事务
2.执行sql语句
3.设置事务的状态 (true)
4.提交数据 true 提交数据 false 回滚数据
if (db.isOpen()) {
try {
// 开启数据库的事务
db.beginTransaction();
..............................
db.setTransactionSuccessful();
}
// 显示的设置事务是否成功
catch (Exception e) {
} finally {
//放在这里确保事务能够正常的结束
db.endTransaction();
db.close();
}
}
ListView 一个重要的控件
把XML文件转换成一个View对象,安卓提供的有一个充气泵。
可以把某个扁的XML吹成一个饱满的View对象。
activity 是用来显示用户界面的,你可理解为是一个View容器。
布局转换成View对象?
inflater 是系统的一个服务 初始化服务
inflater = (LayoutInflater) this
.getSystemService(LAYOUT_INFLATER_SERVICE);
// BaseAdapter 是 google的工程师 给ListAdapter的默认实现,因为直接实现ListAdapter方法太多了,所以我们用继承
//这个抽象类的方法。这种方法是实现ListView适配器,最原始的方法。
private class MyAdapter extends BaseAdapter{
/**
* 返回当前listview有多少个条目
*/
public int getCount() {
return list.size();
}
/**
* 返回当前position位置对应的条目 的object对象
*/
public Object getItem(int position) {
return list.get(position);
}
/**
* 返回当前position位置 某个条目的id
*/
public long getItemId(int position) {
return position;
}
/**
* 返回每一个条目显示的具体内容
* 理论上讲有多少个条目就应该被调用多少次,其实是更多次。
* 因为首先它会计算当前这个界面会有多少个条目出现,根据下面的公式。
* 当滚屏的时间,每显示一次都需要调用一次getView的方法。
*
* 计算当前界面 会有多少个条目出现
* 1.得到每一个textview的高度
* 2.得到listview的高度
* 3. listview高度/textview高度 = 得到了一个屏幕显示的textview的个数
*
* listview的每一个条目的显示
* 都需要调用一次getview的方法
* 屏幕上有多个item显示 就会调用多少getview的方法,
* 而且每显示一次就调用一次。
*
* parent 代表的是 当前的这个listview
* convertView是listView对象的一个缓存。
*/
public View getView(int position, View convertView, ViewGroup parent) {
/*TextView tv = new TextView(DbActivity.this);
tv.setText("我是第"+position+"个");
Log.i("aaaaa", "我被调用 了"+position);
return tv;*/
/*TextView tv = new TextView(DbActivity.this);
Person person = list.get(position);
tv.setText(person.getName()+" | " + person.getAccount());
return tv;*/
View view = inflater.inflate(R.layout.item, null);
//接下来,我们就可以从这个view里面去寻找控件,因为我们之前是通过从当前的Acivity中找的空间。
Person person = list.get(position);
TextView name = (TextView) view.findViewById(R.id.name);
TextView phone = (TextView) view.findViewById(R.id.phone);
name.setText("姓名:"+person.getName());
phone.setText("手机:"+person.getAccount());
return view;
}}
点击事件
import android.widget.AdapterView.OnItemClickListener;
listView.setOnItemClickListener(new OnItemClickListener() {
/**
* 通过Debug我们知道了这几个参数的含义
* parent代表的是当前的ListView
* view代表当前被点击条目的View对象
* @param position The position of the view in the adapter.
* @param id The row id of the item that was clicked.
*/
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//方法一
/*TextView name = (TextView) view.findViewById(R.id.name);
TextView phone = (TextView) view.findViewById(R.id.phone);
Toast.makeText(DbActivity.this,name.getText().toString(), Toast.LENGTH_SHORT).show();*/
//方法二
Person person = list.get(position);
Toast.makeText(DbActivity.this,person.getAccount(), Toast.LENGTH_SHORT).show();
//方法三
Person p = (Person) parent.getItemAtPosition(position);
}
});
其实上面的那个方法已经是谷歌工程师采用的优化过的适配器,但是到了具体的业务
它又提出了更为精细的适配器,供我们方便的调用,如SimpleAdapter,ArrayAdaper,SimpleCursorAdapter。
其实还是自定义的Adapter比较强大。
SimpleAdapter其实还是继承了BaseAdapter类。实现的还是我们自定义的那些方法。一定要看源码,我们可以
直接知道它是怎么实现的,其实跟我们自定义实现是一样的。
在TextView中,android:text="phone",是当没有为这个东西赋值的时间会显示这具值,如果为其赋值后,就不再
显示这个值,相当于一个默认值 。
//SimpleAdpater
List<Map<String, String>> mylist = new ArrayList<Map<String,String>>();
for(Person p : list){
Map<String, String> maps = new HashMap<String, String>();
maps.put("姓名",p.getName());
maps.put("手机", p.getAccount());
mylist.add(maps);
}
listView.setAdapter(new SimpleAdapter(DbActivity.this, mylist, R.layout.item,
new String[]{"姓名","手机"}, new int[]{R.id.name,R.id.phone}));
//ArrayAdapter
String[] personsArr = new String[list.size()];
for (int i = 0; i < personsArr.length; i++) {
personsArr[i] = list.get(i).getName();
}
listView.setAdapter(new ArrayAdapter<String>(DbActivity.this, R.layout.item,
R.id.name,personsArr));
//SimpleCursorAdapter
Cursor c = personDao.getAllPersonsCursor();
listView.setAdapter(new SimpleCursorAdapter(this, R.layout.item, c,
new String[]{"name","account"}, new int[]{R.id.name,R.id.phone}));
/**
*有两大问题需要解决。
*第一、db和cursor都不需要关闭因为它将要使用SimpleCursorAdapter,这里面会自动维护。
*第二、SimpleCursorAdapter只识别_id的,如果在数据库中没有,那么可以用这种别名的方式
*来改变它。或者你在新建的时间就做了它。
*/
public Cursor getAllPersonsCursor(){
Cursor cursor = null;
SQLiteDatabase db = myDBHelper.getWritableDatabase();
if (db.isOpen()) {
cursor = db.rawQuery("select personid as _id ,name,account from person", null);
}
return cursor;
}
sqlite 数据库 标准:
要求我们数据库的主键 最好要以_id 作为名字
我们已经知道,数据库是私有的,不能被其它程序访问,
所以我们需要一个中间人,可以把一个应用程序私有的
数据暴露给另外一个程序,让它访问。
content://cn.itcast.db.provider/persons
// 代表获取数据库person表中的所有的内容
content://cn.itcast.db.provider/person/10
// 代表person表中第10个元素
content://cn.itcast.db.provider/haha
内容提供者的使用流程 (自定义内容提供者,详情见db项目。)
1.如果a应用想把自己的数据库暴露给别的应用程序使用
就必须实现contentprovider
创建一个类 继承系统的ContentProvider
一定要在清单文件里面配置
指定uri的主机名 cn.itcast.db.personprovider
2. 定义匹配规则
根据数据库的表结构 定义匹配规则
content://cn.itcast.db.provider/persons
content://cn.itcast.db.provider/person/10
也可以根据业务方法, 指定匹配规则
content://cn.itcast.db.provider/delete/10
3.在别的应用里面 获取contentResolver
contentResolver.query()
.delete()
.insert();
例如:新浪微博的分享功能就需要把自己的数据库给 暴露出来,这样才能让其它人访问。
应用:
1. 把自己应用的数据暴露给别的应用.(因为数据库是私有的。)
屏蔽数据库 底层操作的细节.
暴露uri 和要更改的数据.
2.可以给内容提供者注册一个观察者.
03-12 02:22:10.861: E/AndroidRuntime(25973): java.lang.SecurityException: Permission Denial: reading com.android.providers.telephony.SmsProvider uri content://sms/outbox from pid=25973, uid=10039 requires android.permission.READ_SMS
其实观察者(它就是内容改变的监听器)和监听器都是给某个方法注册一个回调函数,
然后在某个时间执行。
// 当数据发生改变的时候 就会通知baseuri
getContext().getContentResolver().notifyChange(baseuri, null);
然后我们在另外一个应用中去获得这个内容提供者的Uri,并且去实现一个类,
为ContentObserver,实现它的onchange回调方法,当改变的时间会调用这方法。
自定义内容提供者,并且监听它。
一、在内容提供者的程序中必须有一个继承ContentProvider的类,并且实现它的GRUD方法。
然后在这些GRUD方法中必须写这些东西
// 当数据发生改变的时候 ,会通知这个Uri.
getContext().getContentResolver().notifyChange(Uri.parse("content://cn.itcast.db.personprovider"), null);
二、然后在监听程序中,
// 注册了一个内容观察者
Uri uri = Uri.parse("content://cn.itcast.db.personprovider/");
getContentResolver().registerContentObserver(uri, true, new MyObserver(new Handler()));
public class MyObserver extends ContentObserver{
public MyObserver(Handler handler) {
super(handler);
}
/**
* 当内容观察者发现了数据发生改变的时候 调用的方法
*/
@Override
public void onChange(boolean selfChange) {
System.out.println("数据发生改变了。");
super.onChange(selfChange);
}
}
在这种情况下,当第一个程序中的数据发生改变的时间就会触发第二个事件方法。其实是因为第二个程序中给这个URI注册
了一个方法,当第一个程序发生改变的时间会回调这个方法。
那么我们也就不理解在短信发送过程中,其实在短信程序中,它自己也为外部提供了数据的内容提供者,供其它程序来访问,
可以得到其内容提供者的URI,然后为这个URI注册一个回调函数,在安卓中叫做观察者。所以当它改变的时间我们也可以
获得其数据。所以关键是得到其内容提供者的URI.
如:
//为短信的URI注册一个事件。当这个被调用的时间,我们会发现它,并且调用我们自己方法。
Uri uri = Uri.parse("content://sms/");
getContentResolver().registerContentObserver(uri, true, new SmsObserver(new Handler()));
public class SmsObserver extends ContentObserver{
public SmsObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
System.out.println("有新的短信产生 ");
Cursor cursor = getContentResolver().query(Uri.parse("content://sms/outbox"),null, null, null, null);
while(cursor.moveToNext()){
StringBuilder sb = new StringBuilder();
sb.append("_id=").append(cursor.getInt(cursor.getColumnIndex("_id")));
sb.append(";address=").append(cursor.getString(cursor.getColumnIndex("address")));
sb.append(";body=").append(cursor.getString(cursor.getColumnIndex("body")));
sb.append(";time=").append(cursor.getLong(cursor.getColumnIndex("date")));
System.out.println(sb.toString());
}
super.onChange(selfChange);
}
}
11-18 22:06:47.825: E/AndroidRuntime(31345):
java.lang.SecurityException:
Permission Denial:
reading com.android.providers.telephony.SmsProvider uri content://sms/outbox from pid=31345, uid=10044 requires android.permission.READ_SMS
根据上面报的错,我们知道,我们缺失权限,这是获得缺失权限的重要方法。
由于很多软件都会读取通讯录,所以这是一个非常重要的方法。
三个表要了解,其实就是根据内容提供者去获取它的内容。
视频最后的一点思路。
https://github.com/android(包含所有安卓的源代码)
==============================
关于安卓自带的GRUD,你看下底层其实实现非常简单用的是StringBuilder组拼的SQL
语句,
// Measurements show most sql lengths <= 152
StringBuilder sql = new StringBuilder(152);
为什么是152因为根据统计学上说,SQL语句一般不超过152个字符。
然后根据前台传输过来的集合,遍历它,组成一个正常的SQL语句,
你就会明白 ,其实非常简单。
SQLite是一个无类型的,其实都是按照字符串来的,所以你传参数的时间
可以都用new String[]{}.多看源码 。
事务:
安卓学习第三天
最新推荐文章于 2022-10-05 07:32:37 发布