Android_03

  • 在导入工程时有时候会有@Override的错误,这个一般的编译器版本的问题

    可以右键工程-->Android Tools-->fix project properties

    第二种办法:

     右键工程-->java Compiler-->然后更改版本

     

    问readable 和 wirteable 有什么区别?

     

    不管是可读的数据库 还是 可写的数据库实际上返回的都是同一个数据库的实例.

    在返回可写数据库的时候 会对数据库进行加锁操作.

    多个线程不能同时写一个数据库.

    多个线程可以同时读数据库.

    最大限制80~100线程读数据库.

     

    google的api操作数据库替换sql语句,用了google的api操作不用关心数据库真正的找开,或者关闭

    添加

      db.insert("person", nullColumnHack,values);

    nullcolumnHack这个参数的意思是说

    Insert into persion(name,phone) value(?,?)这两个?必须要有值,否则会报错,如果指定"name"说明"name"这列会插入一个null的值,由于代码里的id是自动增长那么就可以写null;

    Values:这个是一个map的集合的一个类,值存列名跟值,可以new 一个ContentValues();

    Values.put("name",name);

    Value.put("number",number);

    上面的方法返回如果是-1那么就是执行失败了

     

     删除:

    Db.delete(表名, whereclause,whereargs)

    Whrerclause:这个是where的条件"name=?"在sql中表示where name=?,

    whereargs这个是所对应的条件事集合

    New String[]{name}

     

    更改:

    Db.update(table,values,whereClause,whereArgs)

    更新的返回值是影响的行数

     

    查询:

    Db.query(table,columns.selection.selectionArgs,groupBy,having,orderBy);

    Colusmns:这个要查询列,如果是null那么就是全部

    Selection:相当于where后面写name=?=>where name=?
    selectionArgs:对应的参数值

    groupBy:分组

    Having orderBy:这个排序

    返回的也是一个Cursor游标集

     

    命令行直接操作android的sql数据

    1.adb shell

    2.cd到目录,直到目录

    3.sqlite3 person.db打开数据库

    4.可以写sql语句操作数据库了

     

    数据库的事务:

    保证一个操作要么同时成功要么同时失败

    1.获取一个可写的数据库

    Helper.getWritableDatabase();

    2.开启事务

    Db.beginTransaction()

    3.数据操作,执行sql语句

    4.在关闭数据前一定要告诉数据库事务成功执行了

    Db.setTransactionSuccessful();

    5.关闭事务

    db.endTransaction();

    为了保证关装事务一定要执行,可以在开启事务后,在关闭事务前try{}catch{},关闭写在finally{}中

     

    listVeiw开发,是一个链表容器,可以理解成一个view的容器,

    1.在main.xml中添加<ListView>标签

    2.activity中设置listView,设置组件

    3.lv.setAdapter(ListAdapter接口);

    4.实现ListAdapter接口,可以用包装类baseAdapter

    5.里面的主要方法实现

    getCount()这个方法告诉组件里面有多少个item条目,

    getView()返回每一个条目对应的view对象

    第一个位置是从零开始,

    If(postion == 0)//第一个位置

    TextView tv = new TextView(DemoActivity.this)//这个一个textview组件

    Tv.setText("");添加文本

    Return tv;//在第一个位置添加一个textView的组件

    R.drawable.ic_launcher//这个是得到一个在R文件中定义的图片

     

    问题:getview的方法被调用了多少次

    答案:界面上能显示多少条目,这个方法就会被调用多少次,getView()这个方法会去判断界面能显示多少item,然后就调用多少个

     

    设置点击事件

    Lv.setOnItemClickListener();某一个条目被点击的事件

    public void onItemClick(AdapterView<?> parent, View view,int position, long id) {}

    parent代表是当前的ListView

    view代表当前条目的对象名称是textview,ImageView说明是条目对应的类型

    position这个是代表当前条目的位置(从零开始)

    id这个没有实现

     

    如果不知道一个方法只的参数是什么作用,可以用为断点调试去查看方法的参数

     

    判断是否是TextView

    If(view instanceof Textview)

     

    在创建textView 对象时可以设置标识

    Tv.setTag()

    在点击事件中,view代表TextView,可以用view的getTag()得到设置的标识

     

    textview实现左边图标,右边汉字

    1.指定线性布局

    Android:orientation="horizontal"指定对齐方向为水平方向

    Android:gravity="center_vertical"这个竖直方向居中

    在xml布局文件中引入图片用android:src="@drawable/in_nenu_allFriends"

    上面的drawable这个图片的文件夹后面加文件名

     

    2.xml转化成view对象,然后通过getview返回回去

    android系统给我们提供了一个服务是布局填充器(LayoutInflater)

    1).根据上下文得到系统服务,初始化系统布局填充器的服务

    LayoutInflater inflater =getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    2).在getView()方法中执行填充操作

    Inflater,inflate(resource,root);

    Resource:这个实例填充我布局R.layout.item

    Root:这个可选,挂载的父窗体,当前方法是返回一个view,会自动挂载到view,所以可以填null,生成一个view,然后返回这个view就可以了

    View.findviewByID();//这个是在当前的转化出来的view对象里面寻找组件

    ImageView这个组件设置图片是

    Iv.setImageResource(图片地址,R文件中的引用);

     

     在baseAdapter类的getItemId()这个方法主要用在当listView的getItemAtPostion方法的时候,这个方法返回的就这getItem()返回的值

     

    如果要在OnItemClickListener()的实现类中可以用系统方法得到上下文用getApplicationContext();

     

    Lv.getItemIdAtPostion(postion)这个其实调用getItemId(int position){}一般都是返回position的值

     

    让listView的条目循环显示:

    1.getcount()这个设置Integer.MAX_VALUE;

    2.在getView方法中定义一个值

    Int newPostion = position%5;//这里的5是显示的总条目数

    然后用newPostion替换以前psition的值

     

    采用listView展现数据库的数据

    在线性布局时,三个TextView平分一行可以以下操作:

    1.xml布局里<TextView>每个控件设置

    Android:layout_weight="1"//权重相同

    Android:layout_width="0dip"

    每个控件都如下设置就可以让以下几个控制都占用一样的比例

    Android:gravity="center_horizontal"水平居中

     

    layoutInflater这个系统也提供了一个方法的生成方法

    LayoutInflater inflater = LayoutInflater.from(this);//this.是上下文,这个方法底层包装了getSystemService(Context.LAYOUT_INFLATER_SERVICE);这个填充器

     

    还有一种生成layoutinflater这个类的方法,直接在getview方法中调用View的静态方法

    View.inflate(context.resource.root);底层是包装了LayoutInflater.from(this);

    Context:上下文getApplicationContext()方法得到

    Resource:这个要填充的xml布局R.layout.item

    Root:null这个可选,挂载的父窗体,当前方法是返回一个view,会自动挂载到view,所以可以填null,生成一个view,然后返回这个view就可以了

     

    系统提供的系统展现:

    Arrayadapter:

    Lv.setAdapter(new ArrayAdapter<String>(context,resource,textViewResourceId,Objects));

    Context:上下文

    Resource: 布局的资源R.layout,item

    textviewResourceid:textview的id,R.id.tv

    Objects:那个对象付给listView这个控件,即显示的String数组

    这个方法不能更换图标,图标都一致,xml默认的图标

     

    Simpleadapter:

    Lv.setAdapter(new SimpleAdapter(Context,data,resource,from,to));

    Context:这个是上下文

    data这个是list集合中存放 map集合,每个条目里面的内容都会被放在当前条目的map集合里,list就是listview里的条目数据集合

    List<Map<String,Object>> data = new ArrayList<Map<String,Object>>();

    private int[] icons = { R.drawable.ic_menu_allfriends,

    R.drawable.ic_menu_always_landscape_portrait,

    R.drawable.ic_menu_archive, R.drawable.ic_menu_attachment,

    R.drawable.ic_menu_back };

    private String[] names = { "我的好友", "屏幕旋转", "打开文件夹", "添加附件", "后退按钮" };

    Map<String, Object> map1 = new HashMap<String, Object>();

     map1.put("icon", icons[0]);

     map1.put("name", names[0]);

     data.add(map1);

     

    Resource:R.layout.item

    From:这个是上面map集合的健集合new String[]{"icon","name"}

     

    To:from数据绑定到那个控件上

    R.id.iv这个绑定室ImageView控件上

    R.id.tv 这个是绑定到Textview控件上

     

    CursorAdapter这是一个抽象类,一个有简单的适配器

    Lv.setAdapter(new SimpleCursorAdapter(context.layout,c,from,to));

    Context:this上下文

    Layout:这个是布局文件R.layout.item

    c:cousor数据库返回的cursor,返回注意一个问题返回的cursor不能关闭cursor,跟数据库

    From:数据库返回的列名集合,对应绑定的ui,new String[]{"name",number","accout"}

    To:绑定的关联的view对象new int[]{R.id.tv_name….}

    这个SimplecursorAdapter这个要求游标集合必须要"_id"

     

    内容提供者:

    数据存储跟访问方式的包装,作用是把一个程序的私有数据暴露给其他程序使用

    使用方法:

    1.创建一个类personProvider 继承系统的ContentProvider

    2.内容提供者是系统的组件之一,必须要在清单文件里配置

    <provider android:name=".provider.PersonProvider"  android:authorities="cn.itcat.db2">

    内容提供者前缀Content://主机名一般是包名(cn.itcat.db2/)

    上面的name是内容提供者的路径,前面的"."表示这个路径在系统的包下面,内容提供者是根据一个路径把数据暴露出来的

    3.定义URL的匹配器,接受一个参数代表的是如果路径不匹配返回的值

    UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH):

    4.static静态代码块里初始化值

    Static{

    //创建一个匹配的规则,如果发现一个uri的路径满足cn.itcat.db2/add会返回一个匹配码1

    Matcher.addURI(authority,path,code);

    Authority:URI的主机名,要跟配置文件里的主机名一致cn.itcat.db2

    Path:这个是匹配的地址,因为是添加就"find"

    Code:如果匹配这个路径返回的值例:1为了可读性可以定义一些常量值

    }

      5.继承ContentProvider的方法中都有一个uri参数,可以用matcher.match(uri)== 1判断是否是查找或者其他操作

     

    当包含有内容提供者的应用程序装到手机上的时候,系统 会自动把这个内容提供者发布出去

     

    6.创建一个新的应用,在这个应用中用内容解析者,解析发布的内容

    ContentResolver resolver = getContentResolver();

    7.现在就可以用resolver调用里面的方法了,在调用前要初始化一些参数

    Uri uri = Uri.parse("content://cn.itcat.db2/find");

    Resolver.query();

    8要想实现这个查询的方法就必须去继承的内容提供者的Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder)

    方法了创建一个sqlLiteDatabase 数据库实例,用继承了SQLiteOpenHelper的类去调用getReadableDatabase();

    如果是查询操作就调用db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);

    Table:是表名,columns这个是列名就是projection,selection这个是选择条件跟selectArgs这个是选择条件所对应的值这两个跟方法参数一样不变

    groupBy这个是否分组,having这个是条件,orderBy这个是排序,可以用上面的sortOrder,在内容提供者的方法里没有找到匹配的uri,那么可以抛出一个异常throw new IllegalArgumentException("uri不能被识别");

     

    9就可以得到结果集了然后用循环去得到数据

    While(cursor.moveToNext())//得到下一行结果

    {

    Cursor.getString(cursor.getColumnIndex("number"))//cursor.getString这个是得到某一列的值,cursor.getcolumnIndex("number")这个是得到number的列号

    }

     

    内容提供者的find()方法,如果listview中的数据很多的话会有问题,会提示数据库从来没有关闭

    我们可以以下操作,cursor得到以后,调用cursor.getCount();这个游标集向下移动一个位置,也会在游标工厂创建一个副本,然后我们在关闭数据库,这样仍然可以获取cursor游标集,这样就解决了find()操作数据没有关闭的问题,这也是google工程师设计这个方法的一个问题

     

    利用内容提供者获取系统数据库的联系人

     

    如果内容提供者只想对外实现查的功能,就只要提供查的方法就可以了

     

    利用内容提供者对A应用增删改查的时候,实际上激活了A应用,传递数据给A应用的内容提供者.内容提供者相当于A应用的代理人,只有通过内容提供者才能操作A应用发布的数据库

     

    系统内容提供者

     联系人的目录:data/data/com.android.providers.contacts/database/contacts2.db这个是系统联系人的目录

    如果一开始不知道这个数据库里的表对应关系,可以先添加一些数据看看这些表的变化

    表名:

    Raw_contacts:这个未经常压缩的联系人信息,这里有联系人的ID跟联系人的别名,姓名 _id,contact_id 联系人的id

    data表:mimetype_id这是关联到minetypes,data1这个是保存联系人的信息,raw_contact_id关联到raw_contact表

    Mimetypes:这里保存保存的类别

     

    找到联系人的内容提供者

    1.路径:,,/providers\ContactsProvider\AndroidManifest.xml

    <provider android:name="ContactsProvider2"          android:authorities="contacts;com.android.contacts"

    看到如上配置,就知道系统联系人的内容提供者的路径有两个

    然后就可以构建uri,但是添加记录的路径是多少就要看2.内容提供者的源代码

    源代码目录:../providers\ContactsProvider\src\com\android\providers\contacts\ContactsProvider2.java

    因为匹配就要定义一个UriMatcher所以在源代码里查找就找到了匹配规则

    就找了rwa_contacts字段就得到完整的uri路径

    3.得到cursor

    Cursor cursor  = getcontext().getcontentResolver().query(uri,new String[]{"display_name","contact_id"),null,null,null);

    4.遍历cursor

    5.加权限

    Android.permission.READ_CONTACTS

    Android.permission.WRITE_CONTACTS

    这两个权限在系统人的配置文件androidManifest.xml中定义了

     

    下面是data表的查询操作

    系统自动帮我把mimetype_id跟mimetypes进行了关联,所以两张表的数据都查询出来了,所以查询的参数直接写mimetype就行了不用写mimetype_id

    然后判断类型进行打印

     

    不知道curosr返回那些数据,就直接打印里面全部的列名

     

    插入一条联系人的信息

    1.向raw_contact表中添加一个id:

    1).得到uri

    3)new ContentValues      ContentValues values = new ContentValues();

    Values.put("contact_id",3);这里就直接指定三了,实际开发中要去数据库中找到最大的id,然后加1

    2).getContext().getcontentResolver().insert(uri,value);

     

    2.向data表中添加这个id对应的数据

    1.Uri

    2.new contentValues

    3.put("raw_contact_id",3)

        put("mimetype","vnd.android.cursor.item/name");

       put("data1","对应的数据这里是name");

    上面就指定了一个名字

    其他邮箱什么都一样步骤

    4.添加权限android.permission.WRITE_CONTACTS

     

    内容观察者

    观察某一个应用数据的内容什么时候改变了

    例:短信窃听器

    //监听系统的短信应用的数据库里面的内容变化

    1.查看短信的数据库

    Data/data/com.android.providers.telephony/databases/mmssms.db这个数据库是短信的

    还有一个telephony.db这个应该是电话的

    sms表 address这个是电话,data这个发件或收件的时间是用毫秒值表示,read这个短信的状态,是已读还是未读body这个正文,locked这个表示选中的短信是不会删除掉的

    2.内容提供者

    ../providers\TelephonyProvider\AndroidManifest.xml

    这里可以找到主机地址跟所需要的权限

    3.URI

    4.查询数据

    5.注册内容观察者

    getContentResoler().registercontentObserver(uri,notifyForDescendents,observer);

    Uri:观察的uri

    notifyForDescendents:如果是true就是开始部分是uri就观察,如果是false就是要满足完全匹配uri才观察,我们设置true;

    Observer:ContentObserver内容观察是抽象类

    复写onChange方法,这个方法是一旦观察到数据的改变就会调用这个方法

    然后在这里写我们需要的代码

     

    数据观察者的原理:

    基于消息机制,android有消息邮箱的这样的东西,就是一块共享的内存单元,当我们对数据库进行增删改掉的时候,需要通知消息邮箱,我对那个URI的内容发生了更更改,一旦对uri内容发生了更改,系统就会发送一个消息到消息邮箱里面,如果我们注册了一个观察者,观察这个URI的数据变化,也是注册一个消息到系统消息邮箱里,一旦有新的数据产生了,他就认为数据库的内容发生了改变,他就去告诉数据观察者数据改变了

     

    我们自己定义的内容观察者如果要实现消息邮箱的话我们要去通知系统的消息邮件,短信内容观察者已经实现了以下代码:

    getContext().getContentResolver().notifyChange(uri,observer);

    Uri:观察的地址

    Observer:数据观察者,不如果不想通知具体的数据观察者可以传一个null;

    上面的代码就把消息发送到了消息邮箱里了,别的程序就可以去监视他了.

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值