android 学习笔记 (for 黎活明讲师)

来源:互联网 发布:幸运牛抽奖软件注册码 编辑:程序博客网 时间:2024/05/22 15:10
android 笔记
    1.android UI布局方式:
        LinearLayout (线性布局)、AbsoluteLayout(绝对布局)、RelativeLayout(相对布局)、TableLayout(表格布局)、FrameLayout(帧布局)


    2.android 拨号器:

        2.1 manifest 配置拨号器权限:
            <manifest .......>
                    <uses-permission android:name="android.permission.CALL_PHONE"/>
            </manifest>
        2.2 拨号器代码:
            //获取手机号
            EditText editText = (EditText)findViewById(R.id.mobile);
            //新建一个拨号器意图对象
            Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+ editText.getText()));
            //启动拨号器
            DialerAction.this.startActivity(intent);

    3.短信发送器:
    
        3.1 manifest 配置短信发送器权限:
            <manifest .......>
                <uses-permission android:name="android.permission.SEND_SMS"/>
            </manifest>
        3.2 短信发送器代码:
            String mobile = mobileView.getText().toString();
            String content = contentView.getText().toString();
             SmsManager smsManager = SmsManager.getDefault();
             PendingIntent sentIntent = PendingIntent.getBroadcast(SMSSender.this, 0, new Intent(), 0);
            if(content.length()>70){//如果字数超过70,需拆分成多条短信发送
                        List<String> msgs = smsManager.divideMessage(content);
                      for(String msg : msgs){
                        smsManager.sendTextMessage(mobile, null, msg, sentIntent, null);
                     //最后二个参数为短信已发送的广播意图,最后一个参数为短信对方已收到短信的广播意图
                      }
            }else{                    
                       smsManager.sendTextMessage(mobile, null, content, sentIntent, null);
            }
            Toast.makeText(SMSSender.this, "短信发送完成", Toast.LENGTH_LONG).show();


    4.数据存储与访问:
    
        4.1 文件访问
            4.1.1 文件写入操作:
                FileOutputStream outStream = this.openFileOutput("文件名.txt", Context.MODE_PRIVATE);
                     outStream.write("内容".getBytes());
                     outStream.close();   
                
                //说明:
                //文件默认会保存的该应用的data/files/文件夹下。
                //openFileOutput()方法的第二参数用于指定操作模式,有四种模式,分别为: Context.MODE_PRIVATE    =  0
                //Context.MODE_APPEND    =  32768
                //Context.MODE_WORLD_READABLE =  1
                //Context.MODE_WORLD_WRITEABLE =  2
                //Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND
                //Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
                //Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。
                //MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
                //如果希望文件被其他应用读和写,可以传入:
                //openFileOutput("itcast.txt", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
                //android有一套自己的安全模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,当该应用要去访问其他资源比如文件的时候,就需要userid匹配。默认情况下,任何应用创建的文件,sharedpreferences,数据库都应该是私有的(位于/data/data/<package name>/files),其他程序无法访问。除非在创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE ,只有这样其他程序才能正确访问。

                
            4.1.2 文件读取:
                如果要打开存放在/data/data/<package name>/files目录应用私有的文件,可以使用Activity提供openFileInput()方法。
                FileInputStream inStream = this.getContext().openFileInput("test.txt");
                Log.i("FileTest", readInStream(inStream));
                readInStream()的方法请看本页下面备注。

                或者直接使用文件的绝对路径:
                File file = new File("/data/data/cn.li.water/files/test.txt");
                FileInputStream inStream = new FileInputStream(file);
                Log.i("FileTest", readInStream(inStream));
                注意:上面文件路径中的“cn.li.water”为应用所在包,当你在编写代码时应替换为你自己应用使用的包。
                对于私有文件只能被创建该文件的应用访问,如果希望文件能被其他应用读和写,可以在创建文件时,指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。

                Activity还提供了getCacheDir()和getFilesDir()方法:
                getCacheDir()方法用于获取/data/data/<package name>/cache目录
                getFilesDir()方法用于获取/data/data/<package name>/files目录

            4.1.3 把文件存放在SDCard
                
                使用Activity的openFileOutput()方法保存文件,文件是存放在手机空间上,一般手机的存储空间不是很大,存放些小文件还行,如果要存放像视频这样的大文件,是不可行的。对于像视频这样的大文件,我们可以把它存放在SDCard。 SDCard是干什么的?你可以把它看作是移动硬盘或U盘。

                在模拟器中使用SDCard,你需要先创建一张SDCard卡(当然不是真的SDCard,只是镜像文件)。创建SDCard可以在Eclipse创建模拟器时随同创建,也可以使用DOS命令进行创建,如下:
                在Dos窗口中进入android SDK安装路径的tools目录,输入以下命令创建一张容量为2G的SDCard,文件后缀可以随便取,建议使用.img:
                mksdcard 2048M D:\AndroidTool\sdcard.img

                在程序中访问SDCard,你需要申请访问SDCard的权限。
                在AndroidManifest.xml中加入访问SDCard的权限如下:
                <!-- 在SDCard中创建与删除文件权限 -->
                <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
                <!-- 往SDCard写入数据权限 -->
                <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

                要往SDCard存放文件,程序必须先判断手机是否装有SDCard,并且可以进行读写。
                注意:访问SDCard必须在AndroidManifest.xml中加入访问SDCard的权限
                if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                     File sdCardDir = Environment.getExternalStorageDirectory();//获取SDCard目录
                     File saveFile = new File(sdCardDir, “test.txt”);
                     FileOutputStream outStream = new FileOutputStream(saveFile);
                     outStream.write("内容".getBytes());
                     outStream.close();
                }
                Environment.getExternalStorageState()方法用于获取SDCard的状态,如果手机装有SDCard,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA_MOUNTED。
                Environment.getExternalStorageDirectory()方法用于获取SDCard的目录,当然要获取SDCard的目录,你也可以这样写:
                File sdCardDir = new File("/sdcard"); //获取SDCard目录
                File saveFile = new File(sdCardDir, "test.txt");
                //上面两句代码可以合成一句: File saveFile = new File("/sdcard/test.txt");
                FileOutputStream outStream = new FileOutputStream(saveFile);
                outStream.write("内容".getBytes());
                outStream.close();

            4.1.4 使用SAX或者DOM或者pull读取XML文件:
                文件名称:test.xml
                <?xml version="1.0" encoding="UTF-8"?>
                <persons>
                    <person id="1">
                        <name>张三</name>
                        <age>18</age>
                    </person>
                    <person id="2">
                        <name>李四</name>
                        <age>16</age>
                    </person>
                </persons>

                例子定义了一个javabean用于存放上面解析出来的xml内容, 这个javabean为Person,代码请见本页下面备注:
                
                SAX是一个解析速度快并且占用内存少的xml解析器,非常适合用于Android等移动设备。 SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口。下面是一些ContentHandler接口常用的方法:
                startDocument()
                当遇到文档的开头的时候,调用这个方法,可以在其中做一些预处理的工作。
                endDocument()
                和上面的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。
                startElement(String namespaceURI, String localName, String qName, Attributes atts)
                当读到一个开始标签的时候,会触发这个方法。namespaceURI就是命名空间,localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名。通过atts可以得到所有的属性名和相应的值。要注意的是SAX中一个重要的特点就是它的流式处理,当遇到一个标签的时候,它并不会纪录下以前所碰到的标签,也就是说,在startElement()方法中,所有你所知道的信息,就是标签的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元属等等其它与结构相关的信息,都是不得而知的,都需要你的程序来完成。这使得SAX在编程处理上没有DOM来得那么方便。
                endElement(String uri, String localName, String name)
                这个方法和上面的方法相对应,在遇到结束标签的时候,调用这个方法。
                characters(char[] ch, int start, int length)
                这个方法用来处理在XML文件中读到的内容,第一个参数用于存放文件的内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。

                只要为SAX提供实现ContentHandler接口的类,那么该类就可以得到通知事件(实际上就是SAX调用了该类中的回调方法)。因为ContentHandler是一个接口,在使用的时候可能会有些不方便,因此,SAX还为其制定了一个Helper类:DefaultHandler,它实现了这个接口,但是其所有的方法体都为空,在实现的时候,你只需要继承这个类,然后重载相应的方法即可。使用SAX解析itcast.xml的代码如下:
                public static List<Person> readXML(InputStream inStream) {
                   try {
                    SAXParserFactory spf = SAXParserFactory.newInstance();
                    SAXParser saxParser = spf.newSAXParser(); //创建解析器
                    //设置解析器的相关特性,http://xml.org/sax/features/namespaces = true 表示开启命名空间特性  
                    saxParser.setProperty("http://xml.org/sax/features/namespaces",true);
                    XMLContentHandler handler = new XMLContentHandler();
                    saxParser.parse(inStream, handler);
                    inStream.close();
                    return handler.getPersons();
                   } catch (Exception e) {
                    e.printStackTrace();
                   }
                  return null;
                }
                SAX 支持已内置到JDK1.5中,你无需添加任何的jar文件。关于XMLContentHandler的代码实现请看本页下面备注。
                

                使用Pull解析器生成一个与itcast.xml文件内容相同的myitcast.xml文件,代码在本页下方备注

                使用代码如下(生成XML文件):
                File xmlFile = new File("myitcast.xml");
                FileOutputStream outStream = new FileOutputStream(xmlFile);
                OutputStreamWriter outStreamWriter = new OutputStreamWriter(outStream, "UTF-8");
                BufferedWriter writer = new BufferedWriter(outStreamWriter);
                writeXML(persons, writer);
                writer.flush();
                writer.close();
                如果只想得到生成的xml内容,可以使用StringWriter:
                StringWriter writer = new StringWriter();
                writeXML(persons, writer);
                String content = writer.toString();

        4.2 轻量级的存储(SharedPreferences:类似于windows的 ini配置文件)
                很多时候我们开发的软件需要向用户提供软件参数设置功能,例如我们常用的QQ,用户可以设置是否允许陌生人添加自己为好友。对于软件配置参数的保存,如果是window软件通常我们会采用ini文件进行保存,如果是j2se应用,我们会采用properties属性文件进行保存。如果是Android应用,我们最适合采用什么方式保存软件配置参数呢?Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。使用SharedPreferences保存数据,其背后是用xml文件存放数据,文件存放在/data/data/<package name>/shared_prefs目录下:
                SharedPreferences sharedPreferences = getSharedPreferences("itcast", Context.MODE_PRIVATE);
                Editor editor = sharedPreferences.edit();//获取编辑器
                editor.putString("name", "传智播客");
                editor.putInt("age", 4);
                editor.commit();//提交修改
                生成的itcast.xml文件内容如下:
                <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
                <map>
                <string name="name">传智播客</string>
                <int name="age" value="4" />
                </map>
                因为SharedPreferences背后是使用xml文件保存数据,getSharedPreferences(name,mode)方法的第一个参数用于指定该文件的名称,名称不用带后缀,后缀会由Android自动加上。方法的第二个参数指定文件的操作模式,共有四种操作模式,这四种模式前面介绍使用文件方式保存数据时已经讲解过。如果希望SharedPreferences背后使用的xml文件能被其他应用读和写,可以指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。
                另外Activity还提供了另一个getPreferences(mode)方法操作SharedPreferences,这个方法默认使用当前类不带包名的类名作为文件的名称。

                访问SharedPreferences中的数据代码如下:
                SharedPreferences sharedPreferences = getSharedPreferences("itcast", Context.MODE_PRIVATE);
                //getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值
                String name = sharedPreferences.getString("name", "");
                int age = sharedPreferences.getInt("age", 1);

                如果访问其他应用中的Preference,前提条件是:该preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限。如:有个<package name>为cn.itcast.action的应用使用下面语句创建了preference。
                getSharedPreferences("itcast", Context.MODE_WORLD_READABLE);
                其他应用要访问上面应用的preference,首先需要创建上面应用的Context,然后通过Context 访问preference ,访问preference时会在应用所在包下的shared_prefs目录找到preference :
                Context otherAppsContext = createPackageContext("cn.itcast.action", Context.CONTEXT_IGNORE_SECURITY);
                SharedPreferences sharedPreferences = otherAppsContext.getSharedPreferences("itcast", Context.MODE_WORLD_READABLE);
                String name = sharedPreferences.getString("name", "");
                int age = sharedPreferences.getInt("age", 0);

                如果不通过创建Context访问其他应用的preference,可以以读取xml文件方式直接访问其他应用preference对应的xml文件,如:
                File xmlFile = new File(“/data/data/<package name>/shared_prefs/itcast.xml”);//<package name>应替换成应用的包名

            
        4.3 SQLite数据库:
            除了可以使用文件或SharedPreferences存储数据,还可以选择使用SQLite数据库存储数据。
            在Android平台上,集成了一个嵌入式关系型数据库—SQLite,SQLite3支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型虽然只有五种,但实际上sqlite3也接受varchar(n)、char(n)、decimal(p,s) 等数据类型,只不过在运算或保存时会转成对应的五种数据类型。 SQLite最大的特点是你可以保存任何类型的数据到任何字段中,无论这列声明的数据类型是什么。例如:可以在Integer字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符型字段中存放日期型值。 但有一种情况例外:定义为INTEGER PRIMARY KEY的字段只能存储64位整数, 当向这种字段中保存除整数以外的数据时,将会产生错误。 另外, SQLite 在解析CREATE TABLE 语句时,会忽略 CREATE TABLE 语句中跟在字段名后面的数据类型信息,如下面语句会忽略 name字段的类型信息:
            CREATE TABLE person (personid integer primary key autoincrement, name varchar(20))

            SQLite可以解析大部分标准SQL语句,如:
            查询语句:select * from 表名 where 条件子句 group by 分组字句 having ... order by 排序子句
            如:select * from person
                select * from person order by id desc
                select name from person group by name having count(*)>1
            分页SQL与mysql类似,下面SQL语句获取5条记录,跳过前面3条记录
            select * from Account limit 5 offset 3 或者 select * from Account limit 3,5
            插入语句:insert into 表名(字段列表) values(值列表)。如: insert into person(name, age) values(‘传智’,3)
            更新语句:update 表名 set 字段名=值 where 条件子句。如:update person set name=‘传智‘ where id=10
            删除语句:delete from 表名 where 条件子句。如:delete from person  where id=10
            
            Android提供了一个名为SQLiteDatabase的类,该类封装了一些操作数据库的API,使用该类可以完成对数据进行添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)操作(这些操作简称为CRUD)。对SQLiteDatabase的学习,我们应该重点掌握execSQL()和rawQuery()方法。 execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句; rawQuery()方法可以执行select语句。
            execSQL()方法的使用例子:
            SQLiteDatabase db = ....;
            db.execSQL("insert into person(name, age) values('传智播客', 4)");
            db.close();
            执行上面SQL语句会往person表中添加进一条记录,在实际应用中, 语句中的“传智播客”这些参数值应该由用户输入界面提供,如果把用户输入的内容原样组拼到上面的insert语句, 当用户输入的内容含有单引号时,组拼出来的SQL语句就会存在语法错误。要解决这个问题需要对单引号进行转义,也就是把单引号转换成两个单引号。有些时候用户往往还会输入像“ & ”这些特殊SQL符号,为保证组拼好的SQL语句语法正确,必须对SQL语句中的这些特殊SQL符号都进行转义,显然,对每条SQL语句都做这样的处理工作是比较烦琐的。 SQLiteDatabase类提供了一个重载后的execSQL(String sql, Object[] bindArgs)方法,使用这个方法可以解决前面提到的问题,因为这个方法支持使用占位符参数(?)。使用例子如下:
            SQLiteDatabase db = ....;
            db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"传智播客", 4});
            db.close();
            execSQL(String sql, Object[] bindArgs)方法的第一个参数为SQL语句,第二个参数为SQL语句中占位符参数的值,参数值在数组中的顺序要和占位符的位置对应。

            SQLiteDatabase的rawQuery() 用于执行select语句,使用例子如下: SQLiteDatabase db = ....;
            Cursor cursor = db.rawQuery(“select * from person”, null);
            while (cursor.moveToNext()) {
                int personid = cursor.getInt(0); //获取第一列的值,第一列的索引从0开始
                String name = cursor.getString(1);//获取第二列的值
                int age = cursor.getInt(2);//获取第三列的值
            }
            cursor.close();
            db.close();
            rawQuery()方法的第一个参数为select语句;第二个参数为select语句中占位符参数的值,如果select语句没有使用占位符,该参数可以设置为null。带占位符参数的select语句使用例子如下:
            Cursor cursor = db.rawQuery("select * from person where name like ? and age=?", new String[]{"%传智%", "4"});

            Cursor是结果集游标,用于对结果集进行随机访问,如果大家熟悉jdbc, 其实Cursor与JDBC中的ResultSet作用很相似。使用moveToNext()方法可以将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为false,否则为true。另外Cursor 还有常用的moveToPrevious()方法(用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否则为true )、moveToFirst()方法(用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否则为true )和moveToLast()方法(用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否则为true ) 。

            除了前面给大家介绍的execSQL()和rawQuery()方法, SQLiteDatabase还专门提供了对应于添加、删除、更新、查询的操作方法: insert()、delete()、update()和query() 。这些方法实际上是给那些不太了解SQL语法的菜鸟使用的,对于熟悉SQL语法的程序员而言,直接使用execSQL()和rawQuery()方法执行SQL语句就能完成数据的添加、删除、更新、查询操作。
            Insert()方法用于添加数据,各个字段的数据使用ContentValues进行存放。 ContentValues类似于MAP,相对于MAP,它提供了存取数据对应的put(String key, Xxx value)和getAsXxx(String key)方法,  key为字段名称,value为字段值,Xxx指的是各种常用的数据类型,如:String、Integer等。
            SQLiteDatabase db = databaseHelper.getWritableDatabase();
            ContentValues values = new ContentValues();
            values.put("name", "传智播客");
            values.put("age", 4);
            long rowid = db.insert(“person”, null, values);//返回新添记录的行号,与主键id无关
            不管第三个参数是否包含数据,执行Insert()方法必然会添加一条记录,如果第三个参数为空,会添加一条除主键之外其他字段值为Null的记录。Insert()方法内部实际上通过构造insert语句完成数据的添加,Insert()方法的第二个参数用于指定空值字段的名称,相信大家对此参数会感到疑惑,此参数的作用是干嘛的?是这样的:如果第三个参数values 为Null或者元素个数为0, Insert()方法必然要添加一条除了主键之外其它字段为Null值的记录,为了满足这条insert语句的语法, insert语句必须给定一个字段名,如:insert into person(name) values(NULL),倘若不给定字段名 , insert语句就成了这样: insert into person() values(),显然这不满足标准SQL的语法。对于字段名,建议使用主键之外的字段,如果使用了INTEGER类型的主键字段,执行类似insert into person(personid) values(NULL)的insert语句后,该主键字段值也不会为NULL。如果第三个参数values 不为Null并且元素的个数大于0 ,可以把第二个参数设置为null。

            delete()方法的使用:
            SQLiteDatabase db = databaseHelper.getWritableDatabase();
            db.delete("person", "personid<?", new String[]{"2"});
            db.close();
            上面代码用于从person表中删除personid小于2的记录。

            update()方法的使用:
            SQLiteDatabase db = databaseHelper.getWritableDatabase();
            ContentValues values = new ContentValues();
            values.put(“name”, “传智播客”);//key为字段名,value为值
            db.update("person", values, "personid=?", new String[]{"1"});
            db.close();
            
            query()方法实际上是把select语句拆分成了若干个组成部分,然后作为方法的输入参数:
            SQLiteDatabase db = databaseHelper.getWritableDatabase();
            Cursor cursor = db.query("person", new String[]{"personid,name,age"}, "name like ?", new String[]{"%传智%"}, null, null, "personid desc", "1,2");
            while (cursor.moveToNext()) {
                 int personid = cursor.getInt(0); //获取第一列的值,第一列的索引从0开始
                String name = cursor.getString(1);//获取第二列的值
                int age = cursor.getInt(2);//获取第三列的值
            }
            cursor.close();
            db.close();
            上面代码用于从person表中查找name字段含有“传智”的记录,匹配的记录按personid降序排序,对排序后的结果略过第一条记录,只获取2条记录。
            query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit)方法各参数的含义:
            table:表名。相当于select语句from关键字后面的部分。如果是多表联合查询,可以用逗号将两个表名分开。
            columns:要查询出来的列名。相当于select语句select关键字后面的部分。
            selection:查询条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符“?”
            selectionArgs:对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。
            groupBy:相当于select语句group by关键字后面的部分
            having:相当于select语句having关键字后面的部分
            orderBy:相当于select语句order by关键字后面的部分,如:personid desc, age asc;
            limit:指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分。
            
            如果应用使用到了SQLite数据库,在用户初次使用软件时,需要创建应用使用到的数据库表结构及添加一些初始化记录,另外在软件升级的时候,也需要对数据表结构进行更新。在Android系统,为我们提供了一个名为SQLiteOpenHelper的类,该类用于对数据库版本进行管理,该类是一个抽象类,必须继承它才能使用。 为了实现对数据库版本进行管理,SQLiteOpenHelper类有两种重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

            当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的需要,修改了数据库表的结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。

            getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。但getWritableDatabase() 方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用的是getWritableDatabase() 方法就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。
            
            public class DatabaseHelper extends SQLiteOpenHelper {
                //类没有实例化,是不能用作父类构造器的参数,必须声明为静态
                 private static final String name = "itcast"; //数据库名称
                 private static final int version = 1; //数据库版本
                 public DatabaseHelper(Context context) {
            //第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类
                    super(context, name, null, version);
                 }
                @Override public void onCreate(SQLiteDatabase db) {
                      db.execSQL("CREATE TABLE IF NOT EXISTS person (personid integer primary key autoincrement, name varchar(20), age INTEGER)");   
                 }
                @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
                       db.execSQL("DROP TABLE IF EXISTS person");
                       onCreate(db);
                 }
            }
            上面onUpgrade()方法在数据库版本每次发生变化时都会把用户手机上的数据库表删除,然后再重新创建。一般在实际项目中是不能这样做的,正确的做法是在更新数据库表结构时,还要考虑用户存放于数据库中的数据不会丢失。

            public class DatabaseHelper extends SQLiteOpenHelper {
                 private static final String name = "itcast"; //数据库名称
                 private static final int version = 1; //数据库版本
                 ......略
            }
            public class HelloActivity extends Activity {
                @Override public void onCreate(Bundle savedInstanceState) {
                ......
                Button button =(Button) this.findViewById(R.id.button);
                button.setOnClickListener(new View.OnClickListener(){
                public void onClick(View v) {
                    DatabaseHelper databaseHelper = new DatabaseHelper(HelloActivity.this);
                    SQLiteDatabase db = databaseHelper.getWritableDatabase();
                    db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"传智播客", 4});    
                    db.close();  
                }});        
                }
            }

            使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果为成功则提交事务,否则回滚事务。当应用需要提交事务,必须在程序执行到endTransaction()方法之前使用setTransactionSuccessful() 方法设置事务的标志为成功,如果不调用setTransactionSuccessful() 方法,默认会回滚事务。使用例子如下: SQLiteDatabase db = ....;
            db.beginTransaction();//开始事务
            try {
                db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"传智播客", 4});
                db.execSQL("update person set name=? where personid=?", new Object[]{"传智", 1});
                db.setTransactionSuccessful();//调用此方法会在执行到endTransaction() 时提交当前事务,如果不调用此方法会回滚事务
            } finally {
                db.endTransaction();//由事务的标志决定是提交事务,还是回滚事务
            }
            db.close();
            上面两条SQL语句在同一个事务中执行。



            第一次调用getWritableDatabase()或getReadableDatabase()方法后,SQLiteOpenHelper会缓存当前的SQLiteDatabase实例,SQLiteDatabase实例正常情况下会维持数据库的打开状态,所以在你不再需要SQLiteDatabase实例时,请及时调用close()方法释放资源。一旦SQLiteDatabase实例被缓存,多次调用getWritableDatabase()或getReadableDatabase()方法得到的都是同一实例。


        4.4 内容提供者(Content provider)
            
            当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
            当应用需要通过ContentProvider对外共享数据时,第一步需要继承ContentProvider并重写下面方法:
            public class PersonContentProvider extends ContentProvider{
               public boolean onCreate()
               public Uri insert(Uri uri, ContentValues values)
               public int delete(Uri uri, String selection, String[] selectionArgs)
               public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
               public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
               public String getType(Uri uri)}
            第二步需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider , ContentProvider 采用了authorities(主机名/域名)对它进行唯一标识,你可以把 ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities 就是他的域名:
            <manifest .... >
                <application android:icon="@drawable/icon" android:label="@string/app_name">
                <provider android:name=".PersonContentProvider" android:authorities="cn.itcast.provider.personprovider"/>
                </application>
            </manifest>
            注意:一旦应用继承了ContentProvider类,后面我们就会把这个应用称为ContentProvider(内容提供者)。
                
            Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider ,2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
            ContentProvider(内容提供者)的scheme已经由Android所规定, scheme为:content://
            主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
            路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
            要操作person表中id为10的记录,可以构建这样的路径:/person/10
            要操作person表中id为10的记录的name字段, person/10/name
            要操作person表中的所有记录,可以构建这样的路径:/person
            要操作xxx表中的记录,可以构建这样的路径:/xxx
            当然要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:
            要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
            如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
            Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
            
            UriMatcher类使用介绍:
            因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。
            UriMatcher类用于匹配Uri,它的用法如下:
            首先第一步把你需要匹配Uri路径全部给注册上,如下:
            //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
            UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            //如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1
            sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
            //如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2
            sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#号为通配符
            switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) {
               case 1
                break;
               case 2
                break;
               default://不匹配
                break;
            }
            注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://cn.itcast.provider.personprovider/person路径,返回的匹配码为1
            
            ContentUris类使用介绍:
            ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
            withAppendedId(uri, id)用于为路径加上ID部分:
            Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
            Uri resultUri = ContentUris.withAppendedId(uri, 10);
            //生成后的Uri为:content://cn.itcast.provider.personprovider/person/10

            parseId(uri)方法用于从路径中获取ID部分:
            Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10")
            long personid = ContentUris.parseId(uri);//获取的结果为:10
            
            使用ContentProvider共享数据:
            ContentProvider类主要方法的作用:
            public boolean onCreate()
            该方法在ContentProvider创建后就会被调用, Android在系统启动时就会创建ContentProvider 。
            public Uri insert(Uri uri, ContentValues values)
            该方法用于供外部应用往ContentProvider添加数据。
            public int delete(Uri uri, String selection, String[] selectionArgs)
            该方法用于供外部应用从ContentProvider删除数据。
            public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
            该方法用于供外部应用更新ContentProvider中的数据。
            public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
            该方法用于供外部应用从ContentProvider中获取数据。
            public String getType(Uri uri)
            该方法用于返回当前Url所代表数据的MIME类型。如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,例如:要得到所有person记录的Uri为content://cn.itcast.provider.personprovider/person,那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。如果要操作的数据属于单一数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,例如:得到id为10的person记录,Uri为content://cn.itcast.provider.personprovider/person/10,那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。

            使用ContentResolver操作ContentProvider中的数据:
            当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的四个方法:
            public Uri insert(Uri uri, ContentValues values)
            该方法用于往ContentProvider添加数据。
            public int delete(Uri uri, String selection, String[] selectionArgs)
            该方法用于从ContentProvider删除数据。
            public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
            该方法用于更新ContentProvider中的数据。
            public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
            该方法用于从ContentProvider中获取数据。

            这些方法的第一个参数为Uri,代表要操作的是哪个ContentProvider和对其中的什么数据进行操作,假设给定的是: Uri.parse(“content://cn.itcast.provider.personprovider/person/10”),那么将会对主机名为cn.itcast.provider.personprovider的ContentProvider进行操作,操作的数据为person表中id为10的记录。

            使用ContentResolver对ContentProvider中的数据进行添加、删除、修改和查询操作:
            ContentResolver resolver =  getContentResolver();
            Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person");
            //添加一条记录
            ContentValues values = new ContentValues();
            values.put("name", "itcast");
            values.put("age", 25);
            resolver.insert(uri, values);        
            //获取person表中所有记录
            Cursor cursor = resolver.query(uri, null, null, null, "personid desc");
            while(cursor.moveToNext()){
                Log.i("ContentTest", "personid="+ cursor.getInt(0)+ ",name="+ cursor.getString(1));
            }
            //把id为1的记录的name字段值更改新为liming
            ContentValues updateValues = new ContentValues();
            updateValues.put("name", "liming");
            Uri updateIdUri = ContentUris.withAppendedId(uri, 2);
            resolver.update(updateIdUri, updateValues, null, null);
            //删除id为2的记录
            Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);
            resolver.delete(deleteIdUri, null, null);

        4.5 网络


    5.android Activity 操作:

        5.1 为应用添加新的Activity:

            第一步:新建一个继承Activity的类,如:NewActivity
            public class NewActivity extends Activity {
                @Override protected void onCreate(Bundle savedInstanceState) {
                       super.onCreate(savedInstanceState);
                 //这里可以使用setContentView(R.layout.xxx)显示某个视图....
                 }
            }
            第二步:需要在功能清单AndroidManifest.xml文件中添加进上面Activity配置代码(红色部分):
            <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                  package="cn.itcast.action"
                  android:versionCode="1"
                  android:versionName="1.0">
                <application android:icon="@drawable/icon" android:label="@string/app_name">
                .....
                <activity android:name=".NewActivity" android:label="新activity的页面标题"/>
                </application>
                ...
            </manifest>
            android:name属性值的前面加了一个点表示NewActivity是当前包cn.itcast.action下的类,如果类在应用的当前包下,可以省略点符号,如果类在应用的子包下必须加点,如:NewActivity类在cn.itcast.action.user包下可以这样写:<activity android:name=“.user.NewActivity“ />


        5.2 打开新的Activity ,不传递参数:
            
            在一个Activity中可以使用系统提供的startActivity(Intent intent)方法打开新的Activity,在打开新的Activity前,你可以决定是否为新的Activity传递参数:

            第一种:打开新的Activity,不传递参数
            public class MainActivity extends Activity {
              @Override protected void onCreate(Bundle savedInstanceState) {
                .......
                Button button =(Button) this.findViewById(R.id.button);
                           button.setOnClickListener(new View.OnClickListener(){//点击该按钮会打开一个新的Activity
                    public void onClick(View v) {
                          //新建一个显式意图,第一个参数为当前Activity类对象,第二个参数为你要打开的Activity类
                        startActivity(new Intent(MainActivity.this, NewActivity.class));
                }});
                 }
            }

        5.3 打开新的Activity,并传递若干个参数给它:

            第二种:打开新的Activity,并传递若干个参数给它:
            public class MainActivity extends Activity {
              @Override protected void onCreate(Bundle savedInstanceState) {
                .......
                 button.setOnClickListener(new View.OnClickListener(){//点击该按钮会打开一个新的Activity
                      public void onClick(View v) {
                       Intent intent = new Intent(MainActivity.this, NewActivity.class)
            Bundle bundle = new Bundle();//该类用作携带数据
            bundle.putString("name", "传智播客");
            bundle.putInt("age", 4);
            intent.putExtras(bundle);//附带上额外的数据
            startActivity(intent);
                }}); }
            }
            在新的Activity中接收前面Activity传递过来的参数:
            public class NewActivity extends Activity {
                    @Override protected void onCreate(Bundle savedInstanceState) {
                     ........    
                     Bundle bundle = this.getIntent().getExtras();
                     String name = bundle.getString("name");
                         int age = bundle.getInt("age");
                    }
            }


        6.Bundle类的作用:
        
            Bundle类用作携带数据,它类似于Map,用于存放key-value名值对形式的值。相对于Map,它提供了各种常用类型的putXxx()/getXxx()方法,如:putString()/getString()和putInt()/getInt(),putXxx()用于往Bundle对象放入数据,getXxx()方法用于从Bundle对象里获取数据。Bundle的内部实际上是使用了HashMap<String, Object>类型的变量来存放putXxx()方法放入的值:
            public final class Bundle implements Parcelable, Cloneable {
                    ......
             Map<String, Object> mMap;
             public Bundle() {
                   mMap = new HashMap<String, Object>();
                ......
             }
             public void putString(String key, String value) {
                  mMap.put(key, value);
             }
            public String getString(String key) {
                   Object o = mMap.get(key);
                return (String) o;
                ........//类型转换失败后会返回null,这里省略了类型转换失败后的处理代码
            }
            }
            在调用Bundle对象的getXxx()方法时,方法内部会从该变量中获取数据,然后对数据进行类型转换,转换成什么类型由方法的Xxx决定,getXxx()方法会把转换后的值返回。

        
        7.为Intent附加数据的两种写法:
            
            第一种写法,用于批量添加数据到Intent:
            Intent intent = new Intent();
            Bundle bundle = new Bundle();//该类用作携带数据
            bundle.putString("name", "传智播客");
            intent.putExtras(bundle);//为意图追加额外的数据,意图原来已经具有的数据不会丢失,但key同名的数据会被替换
            第二种写法:这种写法的作用等价于上面的写法,只不过这种写法是把数据一个个地添加进Intent,这种写法使用起来比较方便,而且只需要编写少量的代码。
            Intent intent = new Intent();
            intent.putExtra("name", "传智播客");
            Intent提供了各种常用类型重载后的putExtra()方法,如: putExtra(String name, String value)、 putExtra(String name, long value),在putExtra()方法内部会判断当前Intent对象内部是否已经存在一个Bundle对象,如果不存在就会新建Bundle对象,以后调用putExtra()方法传入的值都会存放于该Bundle对象,下面是Intent的putExtra(String name, String value)方法代码片断:
            public class Intent implements Parcelable {
            private Bundle mExtras;
            public Intent putExtra(String name, String value) {
                if (mExtras == null) {
                    mExtras = new Bundle();
                }
                mExtras.putString(name, value);
                return this;
             }

        8.得到新打开Activity 关闭后返回的数据:

            如果你想在Activity中得到新打开Activity 关闭后返回的数据,你需要使用系统提供的startActivityForResult(Intent intent, int requestCode)方法打开新的Activity,新的Activity 关闭后会向前面的Activity 传回数据,为了得到传回的数据,你必须在前面的Activity中重写onActivityResult(int requestCode, int resultCode, Intent data)方法:
            public class MainActivity extends Activity {
                  @Override protected void onCreate(Bundle savedInstanceState) {
                .......
                Button button =(Button) this.findViewById(R.id.button);
                           button.setOnClickListener(new View.OnClickListener(){//点击该按钮会打开一个新的Activity
                    public void onClick(View v) {
                    //第二个参数为请求码,可以根据业务需求自己编号
                    startActivityForResult (new Intent(MainActivity.this, NewActivity.class),  1);
                }});
                 }
                //第一个参数为请求码,即调用startActivityForResult()传递过去的值
                //第二个参数为结果码,结果码用于标识返回数据来自哪个新Activity
               @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
                String result = data.getExtras().getString(“result”));//得到新Activity 关闭后返回的数据
                }
            }    当新Activity关闭后,新Activity返回的数据通过Intent进行传递,android平台会调用前面Activity 的onActivityResult()方法,把存放了返回数据的Intent作为第三个输入参数传入,在onActivityResult()方法中使用第三个输入参数可以取出新Activity返回的数据。
            
            使用startActivityForResult(Intent intent, int requestCode)方法打开新的Activity,新Activity关闭前需要向前面的Activity返回数据需要使用系统提供的setResult(int resultCode, Intent data)方法实现:
            public class NewActivity extends Activity {
                @Override protected void onCreate(Bundle savedInstanceState) {
                    ......
                    button.setOnClickListener(new View.OnClickListener(){
                    public void onClick(View v) {
                        Intent intent = new Intent();//数据是使用Intent返回
                        intent.putExtra(“result”, “传智播客的学生很可爱”);//把返回数据存入Intent
                         NewActivity.this.setResult(RESULT_OK, intent);//设置返回数据
                         NewActivity.this.finish();//关闭Activity
                    }});
                }
            }
            setResult()方法的第一个参数值可以根据业务需要自己定义,上面代码中使用到的RESULT_OK是系统Activity类定义的一个常量,值为-1,代码片断如下:
            public class android.app.Activity extends ......{
              public static final int RESULT_CANCELED = 0;
              public static final int RESULT_OK = -1;
              public static final int RESULT_FIRST_USER = 1;
            }


        9.请求码的作用:

            使用startActivityForResult(Intent intent, int requestCode)方法打开新的Activity,我们需要为startActivityForResult()方法传入一个请求码(第二个参数)。请求码的值是根据业务需要由自已设定,用于标识请求来源。例如:一个Activity有两个按钮,点击这两个按钮都会打开同一个Activity,不管是那个按钮打开新Activity,当这个新Activity关闭后,系统都会调用前面Activity的onActivityResult(int requestCode, int resultCode, Intent data)方法。在onActivityResult()方法如果需要知道新Activity是由那个按钮打开的,并且要做出相应的业务处理,这时可以这样做:
             @Override  public void onCreate(Bundle savedInstanceState) {
                ....
                button1.setOnClickListener(new View.OnClickListener(){
                  public void onClick(View v) {
                       startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 1);
                   }});
                button2.setOnClickListener(new View.OnClickListener(){
                  public void onClick(View v) {
                       startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 2);
                   }});
                   @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
                       switch(requestCode){
                       case 1:
                           //来自按钮1的请求,作相应业务处理
                       case 2:
                      //来自按钮2的请求,作相应业务处理
                    }
                  }
            }
        
        10.结果码的作用:

            在一个Activity中,可能会使用startActivityForResult()方法打开多个不同的Activity处理不同的业务,当这些新Activity关闭后,系统都会调用前面Activity的onActivityResult(int requestCode, int resultCode, Intent data)方法。为了知道返回的数据来自于哪个新Activity,在onActivityResult()方法中可以这样做(ResultActivity和NewActivity为要打开的新Activity):
            public class ResultActivity extends Activity {
                   .....
                   ResultActivity.this.setResult(1, intent);
                   ResultActivity.this.finish();
            }
            public class NewActivity extends Activity {
                   ......
                NewActivity.this.setResult(2, intent);
                NewActivity.this.finish();
            }
            public class MainActivity extends Activity { // 在该Activity会打开ResultActivity和NewActivity
                   @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
                       switch(resultCode){
                       case 1:
                           // ResultActivity的返回数据
                       case 2:
                     // NewActivity的返回数据
                    }
                  }
            }

        
        11.Intent(意图):
        
            Android基本的设计理念是鼓励减少组件间的耦合,因此Android提供了Intent (意图) ,Intent提供了一种通用的消息系统,它允许在你的应用程序与其它的应用程序间传递Intent来执行动作和产生事件。使用Intent可以激活Android应用的三个核心组件:活动、服务和广播接收器。
            Intent可以划分成显式意图和隐式意图。
            显式意图:调用Intent.setComponent()或Intent.setClass()方法指定了组件名或类对象的Intent为显式意图,显式意图明确指定了Intent应该传递给哪个组件。
            隐式意图:没有调用Intent.setComponent()或Intent.setClass()方法指定组件名或类对象的Intent为隐式意图。 Android系统会根据隐式意图中设置的动作(action)、类别(category)、数据(URI和数据类型)找到最合适的组件来处理这个意图。那么Android是怎样寻找到这个最合适的组件呢?记的前面我们在定义活动时,指定了一个intent-filter,Intent Filter(过滤器)其实就是用来匹配隐式Intent的,如果Intent Filter定义的动作、类别、数据(URI和数据类型)与Intent匹配,就会使用Intent Filter所在的组件来处理该Intent。想要接收使用startActivity()方法传递的隐式意图的活动必须在它们的意图过滤器中包含"android.intent.category.DEFAULT"


            
        12.Activity生命周期:
        
            Activity有三个状态:
            当它在屏幕前台时(位于当前任务堆栈的顶部),它是激活或运行状态。它就是响应用户操作的Activity。
            当它失去焦点但仍然对用户可见时(如右图),它处于暂停状态。即在它之上有另外一个Activity。这个Activity也许是透明的,或者没有完全覆盖全屏,所以被暂停的Activity仍对用户可见。暂停的Activity仍然是存活状态(它保留着所有的状态和成员信息并保持和窗口管理器的连接),但系统处于极低内存时仍然可以杀死这个Activity。
            完全被另一个Activity覆盖时则处于停止状态。它仍然保留所有的状态和成员信息。然而对用户是不可见的,所以它的窗口将被隐藏,如果其它地方需要内存,则系统经常会杀死这个Activity。
            当Activity从一种状态转变到另一种状态时,会调用以下保护方法来通知这种变化:
            void onCreate(Bundle savedInstanceState)
            void onStart()
            void onRestart()
            void onResume()
            void onPause()
            void onStop()
            void onDestroy()

        
            
        13.从Internet获取数据:

            利用HttpURLConnection对象,我们可以从网络中获取网页数据.
            URL url = new URL("http://www.sohu.com");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(6* 1000);//设置连接超时
            if (conn.getResponseCode() != 200) throw new RuntimeException("请求url失败");
            InputStream is = conn.getInputStream();//得到网络返回的输入流
            String result = readData(is, "GBK");
            conn.disconnect();
            System.out.println(result);
            //第一个参数为输入流,第二个参数为字符集编码
            public static String readData(InputStream inSream, String charsetName) throws Exception{
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len = -1;
                while( (len = inSream.read(buffer)) != -1 ){
                    outStream.write(buffer, 0, len);
                }
                byte[] data = outStream.toByteArray();
                outStream.close();
                inSream.close();
                return new String(data, charsetName);
            }

            利用HttpURLConnection对象,我们可以从网络中获取文件数据.
            URL url = new URL("http://photocdn.sohu.com/20100125/Img269812337.jpg");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(6* 1000);
            if (conn.getResponseCode() != 200) throw new RuntimeException("请求url失败");
            InputStream is = conn.getInputStream();
            readAsFile(is, "Img269812337.jpg");

            public static void readAsFile(InputStream inSream, File file) throws Exception{
                FileOutputStream outStream = new FileOutputStream(file);
                byte[] buffer = new byte[1024];
                int len = -1;
                while( (len = inSream.read(buffer)) != -1 ){
                    outStream.write(buffer, 0, len);
                }
                outStream.close();
                inSream.close();
            }

        14.向Internet发送请求参数:
            
            利用HttpURLConnection对象,我们可以向网络发送请求参数.
            String requestUrl = "http://localhost:8080/itcast/contanctmanage.do";
            Map<String, String> requestParams = new HashMap<String, String>();
            requestParams.put("age", "12");
            requestParams.put("name", "中国");
             StringBuilder params = new StringBuilder();
            for(Map.Entry<String, String> entry : requestParams.entrySet()){
                params.append(entry.getKey());
                params.append("=");
                params.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
                params.append("&");
            }
            if (params.length() > 0) params.deleteCharAt(params.length() - 1);
            byte[] data = params.toString().getBytes();
            URL realUrl = new URL(requestUrl);
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            conn.setDoOutput(true);//发送POST请求必须设置允许输出
            conn.setUseCaches(false);//不使用Cache
            conn.setRequestMethod("POST");            
            conn.setRequestProperty("Connection", "Keep-Alive");//维持长连接
            conn.setRequestProperty("Charset", "UTF-8");
            conn.setRequestProperty("Content-Length", String.valueOf(data.length));
            conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
            DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
            outStream.write(data);
            outStream.flush();
            outStream.flush();
            if( conn.getResponseCode() == 200 ){
                String result = readAsString(conn.getInputStream(), "UTF-8");
                outStream.close();
                System.out.println(result);
            }

    
      15.向Internet发送xml数据:

        利用HttpURLConnection对象,我们可以向网络发送xml数据.
        StringBuilder xml =  new StringBuilder();
        xml.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
        xml.append("<M1 V=10000>");
        xml.append("<U I=1 D=\"N73\">中国</U>");
        xml.append("</M1>");
        byte[] xmlbyte = xml.toString().getBytes("UTF-8");
        URL url = new URL("http://localhost:8080/itcast/contanctmanage.do?method=readxml");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(6* 1000);
        conn.setDoOutput(true);//允许输出
        conn.setUseCaches(false);//不使用Cache
        conn.setRequestMethod("POST");            
        conn.setRequestProperty("Connection", "Keep-Alive");//维持长连接
        conn.setRequestProperty("Charset", "UTF-8");
        conn.setRequestProperty("Content-Length", String.valueOf(xmlbyte.length));
        conn.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");
        DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
        outStream.write(xmlbyte);//发送xml数据
        outStream.flush();
        if (conn.getResponseCode() != 200) throw new RuntimeException("请求url失败");
        InputStream is = conn.getInputStream();//获取返回数据
        String result = readAsString(is, "UTF-8");
        outStream.close();    


    
    16.广播接收者--BroadcastReceiver:

        广播接收者(BroadcastReceiver)用于异步接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()或者Context.sendStickyBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收,广播接收者和JMS中的Topic消息接收者很相似。要实现一个广播接收者方法如下:
        第一步:继承BroadcastReceiver,并重写onReceive()方法。
        public class IncomingSMSReceiver extends BroadcastReceiver {
            @Override public void onReceive(Context context, Intent intent) {
            }
        }
        第二步:订阅感兴趣的广播Intent,订阅方法有两种:
        第一种:使用代码进行订阅
        IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
        IncomingSMSReceiver receiver = new IncomingSMSReceiver();
        registerReceiver(receiver, filter);
        第二种:在AndroidManifest.xml文件中的<application>节点里进行订阅:
        <receiver android:name=".IncomingSMSReceiver">
            <intent-filter>
             <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
            </intent-filter>
        </receiver>

    17.使用广播接收者窃听短信:

        如果你想窃听别人接收到的短信,达到你不可告人的目的,那么本节内容可以实现你的需求。
        当系统收到短信时,会发出一个action名称为android.provider.Telephony.SMS_RECEIVED的广播Intent,该Intent存放了接收到的短信内容,使用名称“pdus”即可从Intent中获取短信内容。
        public class IncomingSMSReceiver extends BroadcastReceiver {
        private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
        @Override public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(SMS_RECEIVED)) {
            SmsManager sms = SmsManager.getDefault();
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
            Object[] pdus = (Object[]) bundle.get("pdus");
            SmsMessage[] messages = new SmsMessage[pdus.length];
            for (int i = 0; i < pdus.length; i++) messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
                for (SmsMessage message : messages){
                    String msg = message.getMessageBody();
                    String to = message.getOriginatingAddress();
                    sms.sendTextMessage(to, null, msg, null, null);
        }}}}}
        在AndroidManifest.xml文件中的<application>节点里对接收到短信的广播Intent进行订阅:
        <receiver android:name=".IncomingSMSReceiver">
        <intent-filter><action android:name="android.provider.Telephony.SMS_RECEIVED"/></intent-filter></receiver>
        在AndroidManifest.xml文件中添加以下权限:
        <uses-permission android:name="android.permission.RECEIVE_SMS"/><!-- 接收短信权限 -->
        <uses-permission android:name="android.permission.SEND_SMS"/><!-- 发送短信权限 -->

    
    18.广播接收者:

        除了短信到来广播Intent,Android还有很多广播Intent,如:开机启动、电池电量变化、时间已经改变等广播Intent。
         接收电池电量变化广播Intent ,在AndroidManifest.xml文件中的<application>节点里订阅此Intent:
        <receiver android:name=".IncomingSMSReceiver">
            <intent-filter>
             <action android:name="android.intent.action.BATTERY_CHANGED"/>
            </intent-filter>
        </receiver>

         接收开机启动广播Intent,在AndroidManifest.xml文件中的<application>节点里订阅此Intent:
        <receiver android:name=".IncomingSMSReceiver">
            <intent-filter>
             <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
        并且要进行权限声明:
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
        
        通常一个BroadcastReceiver对象的生命周期不超过5秒,所以在BroadcastReceiver里不能做一些比较耗时的操作,如果需要完成一项比较耗时的工作,可以通过发送Intent给Activity或Service,由Activity或Service来完成。
        public class IncomingSMSReceiver extends BroadcastReceiver {
            @Override public void onReceive(Context context, Intent intent) {
                //发送Intent启动服务,由服务来完成比较耗时的操作
                Intent service = new Intent(context, XxxService.class);
                context.startService(service);
                //发送Intent启动Activity,由Activity来完成比较耗时的操作
                Intent newIntent = new Intent(context, XxxActivity.class);
                context.startActivity(newIntent);
            }
        }


    19.服务--Service

        Android中的服务和windows中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。服务的开发比较简单,如下:
        第一步:继承Service类
        public class SMSService extends Service { }
        第二步:在AndroidManifest.xml文件中的<application>节点里对服务进行配置:
        <service android:name=".SMSService" />
        服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
        如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。

        如果打算采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。

        服务常用生命周期回调方法如下:
        onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,服务也只被创建一次。
        onDestroy()该方法在服务被终止时调用。

         与采用Context.startService()方法启动服务有关的生命周期方法
        onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。

         与采用Context.bindService()方法启动服务有关的生命周期方法
        onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。
        onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。


        19.1 采用startService()启动服务:
            
            采用Context.startService()方法启动服务的代码如下:
            public class HelloActivity extends Activity {
                @Override
                public void onCreate(Bundle savedInstanceState) {
                ......
                Button button =(Button) this.findViewById(R.id.button);
                button.setOnClickListener(new View.OnClickListener(){
                public void onClick(View v) {
                    Intent intent = new Intent(HelloActivity.this, SMSService.class);
                    startService(intent);
                }});        
                }
            }
    
        19.2 采用bindService()启动服务:
            
            采用Context.startService()方法启动服务的代码如下:
            public class HelloActivity extends Activity {
                 ServiceConnection conn = new ServiceConnection() {
                public void onServiceConnected(ComponentName name, IBinder service) {
                }
                public void onServiceDisconnected(ComponentName name) {
                }
                 };
                @Override public void onCreate(Bundle savedInstanceState) {  
                Button button =(Button) this.findViewById(R.id.button);
                button.setOnClickListener(new View.OnClickListener(){
                public void onClick(View v) {
                    Intent intent = new Intent(HelloActivity.this, SMSService.class);
                    bindService(intent, conn, Context.BIND_AUTO_CREATE);
                    //unbindService(conn);//解除绑定
                }});        
                }
            }



    20.电话窃听器:

        要实现电话窃听,需要监听电话的状态,方法如下:
        /* 取得电话服务 */
        TelephonyManager telManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        PhoneStateListener listener = new PhoneStateListener(){    
            @Override  public void onCallStateChanged(int state, String incomingNumber) {
                  switch (state){
                case TelephonyManager.CALL_STATE_IDLE: /* 无任何状态时 */
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK: /* 接起电话时 */
                    break;    
                case TelephonyManager.CALL_STATE_RINGING: /* 电话进来时 */
                    break;
                default:
                break;
                  }
            super.onCallStateChanged(state, incomingNumber);
            }            
        };
        //监听电话的状态
        telManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
        在清单文件AndroidManifest.xml中添加权限:
        <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
        
    
    21.音频采集:
    
        你可以使用手机进行现场录音,实现步骤如下:
        第一步:在功能清单文件AndroidManifest.xml中添加音频刻录权限:
        <uses-permission android:name="android.permission.RECORD_AUDIO"/>
        第二步:编写音频刻录代码:
        MediaRecorder recorder = new MediaRecorder();
         recorder.setAudioSource(MediaRecorder.AudioSource.MIC);//从麦克风采集声音
         recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//内容输出格式
         recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//音频编码方式
         recorder.setOutputFile("/sdcard/itcast.amr");
         recorder.prepare();//预期准备
         recorder.start();   //开始刻录
         ...
         recorder.stop();//停止刻录
         recorder.reset();   //重设
         recorder.release(); //刻录完成一定要释放资源


    22.音乐播放:
        
        MediaPlayer mediaPlayer = new MediaPlayer();
        if (mediaPlayer.isPlaying()) {
           mediaPlayer.reset();//重置为初始状态
        }
        mediaPlayer.setDataSource("/sdcard/god.mp3");
        mediaPlayer.prepare();//缓冲                
        mediaPlayer.start();//开始或恢复播放
        mediaPlayer.pause();//暂停播放
        mediaPlayer.start();//恢复播放
        mediaPlayer.stop();//停止播放
        mediaPlayer.release();//释放资源
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {//播出完毕事件
            @Override public void onCompletion(MediaPlayer arg0) {
                mediaPlayer.release();
            }
        });
        mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {// 错误处理事件
             @Override public boolean onError(MediaPlayer player, int arg1, int arg2) {
            mediaPlayer.release();
            return false;
             }
        });


    23.音视频采集:

        第一步:在功能清单文件AndroidManifest.xml中添加音频刻录和照相机权限:
        <uses-permission android:name="android.permission.RECORD_AUDIO"/>
         <uses-permission android:name="android.permission.CAMERA"/>
        第二步:编写音频刻录代码:
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);//获取窗口服务
        Display display = wm.getDefaultDisplay();//获取屏幕信息
        recorder = new MediaRecorder();
        recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); //从照相机采集视频
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        recorder.setVideoSize(display.getWidth(), display.getHeight()); //大小为屏幕的宽和高
        recorder.setVideoFrameRate(3); //每秒3帧
        recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); //设置视频编码方式
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        recorder.setOutputFile("/sdcard/itcast.3gp");
         recorder.prepare();//预期准备
         recorder.start();   //开始刻录
         ...
         recorder.stop();//停止刻录
         recorder.reset();   //重设
         recorder.release(); //刻录完成一定要释放资源


    24.Android中的通知(Notification):

        如果需要查看消息,可以拖动状态栏到屏幕下方即可查看消息。
        发送消息的代码如下:
        //获取通知管理器
        NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        int icon = android.R.drawable.stat_notify_chat;
        long when = System.currentTimeMillis();
        //新建一个通知,指定其图标和标题
        Notification notification = new Notification(icon, null, when);//第一个参数为图标,第二个参数为标题,第三个为通知时间
        Intent openintent = new Intent(this, OtherActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, openintent, 0);//当点击消息时就会向系统发送openintent意图
        notification.setLatestEventInfo(this, “标题”, “我是内容", contentIntent);
        mNotificationManager.notify(0, notification);

    25.对应用进行单元测试:

        第一步:首先在AndroidManifest.xml中加入下面红色代码:
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="cn.itcast.action“ android:versionCode="1“  android:versionName="1.0">
         <application android:icon="@drawable/icon" android:label="@string/app_name">
            <uses-library android:name="android.test.runner" />
            ....
         </application>
         <uses-sdk android:minSdkVersion="6" />
         <instrumentation android:name="android.test.InstrumentationTestRunner"
          android:targetPackage="cn.itcast.action" android:label="Tests for My App" />
        </manifest>
        上面targetPackage指定的包要和应用的package相同。
        第二步:编写单元测试代码(选择要测试的方法,右键点击“Run As”--“Android Junit Test” ):
        import android.test.AndroidTestCase;
        import android.util.Log;
        public class XMLTest extends AndroidTestCase {
             public void testSomething() throws Throwable {
                Assert.assertTrue(1 + 1 == 3);
             }
        }


    26.安装外部程序:

        首先需要AndroidManifest.xml中加入安装程序权限:
         <!-- 安装程序权限 -->
        <uses-permission android:name="android.permission.INSTALL_PACKAGES"/>

        第二步把安装程序添加进SDCard(点击文件浏览器中的导入按钮进行导入外部程序)。如把文件名为” sogouinput_android_1.40_sweb.apk.zip”的sogou拼音输入法安装文件放进SDCard。可以点击下面按钮:

        第三步在程序中添加以下代码:
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(android.content.Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "sogouinput_android_1.40_sweb.apk.zip")),"application/vnd.android.package-archive");
        startActivity(intent);
        



    27.打开对话框:
    
        new AlertDialog.Builder(this).setTitle("传智播客").setMessage("浏览http://www.itcast.cn")
            .setPositiveButton("打开链接",
            new DialogInterface.OnClickListener(){
                public void onClick(DialogInterface dialoginterface, int i){
                Uri uri = Uri.parse("http://www.itcast.cn/");
                 Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                 startActivity(intent);
                 }
            }
            ).show();


    28.单选框(RadioButton):

        要完成单选框显示,我们需要使用到RadioGroup和RadioButton(单选框),RadioGroup用于对单选框进行分组,相同组内的单选框只有一个单选框能被选中。(例子代码请见下方备注栏)
         RadioGroup.check(R.id.dotNet);将id名为dotNet的单选框设置成选中状态。
        (RadioButton) findViewById(radioGroup.getCheckedRadioButtonId());//获取被选中的单选框。
        RadioButton.getText();//获取单选框的值
        调用setOnCheckedChangeListener()方法,处理单选框被选择事件,把RadioGroup.OnCheckedChangeListener实例作为参数传入
        

    29.多选框(CheckBox):
        
        每个多选框都是独立的,可以通过迭代所有多选框,然后根据其状态是否被选中再获取其值。
        CheckBox.setChecked(true);//设置成选中状态。
        CheckBox.getText();//获取多选框的值
        调用setOnCheckedChangeListener()方法,处理多选框被选择事件,把CompoundButton.OnCheckedChangeListener实例作为参数传入


    30.下拉列表框(Spinner):

        Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());获取下拉列表框的值
        调用setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入

    31.下拉列表框—采用javabean作为Adapter元素:

        很多时候显示在下拉列表框的值并不是希望得到的值,如果要做一个联系人下拉列表框,列表框列出的是联系人的姓名,因为姓名有可能相同,所以我们希望得到的值应该为该联系人的id,要实现这种需求我们需要自定义Adapter,当然自定义Adapter需要我们编写一小段代码,如果我们不想编写Adapter,又能实现我们的需求,那是最好不过的了。通过观察ArrayAdapter中getView(int position, View convertView, ViewGroup parent)的内部代码发现,如果为ArrayAdapter指定的实际泛型参数类型没有实现CharSequence(字符串)接口,将会调用该类型对象的toString()向下拉列表框输出显示值。利用这个特点我们可以重写javaBean的toString()向下拉列表框提供显示值。

    32.下拉列表框--自定义选项界面样式:
        Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());获取下拉列表框的值
        调用setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入
    
        
    33.拖动条(SeekBar):

        SeekBar.getProgress()获取拖动条当前值
        调用setOnSeekBarChangeListener()方法,处理拖动条值变化事件,把SeekBar.OnSeekBarChangeListener实例作为参数传入

    34.菜单(Menu):
    
        重写Activity的onCreateOptionsMenu(Menu menu)方法,该方法用于创建选项菜单,在用户按下手机的“Menu”按钮时就会显示创建好的菜单,在onCreateOptionsMenu(Menu menu)方法内部可以调用Menu.add()方法实现菜单的添加。
        重写Activity的onMenuItemSelected()方法,该方法用于处理菜单被选择事件

    35.进度对话框(ProgressDialog):
        使用代码ProgressDialog.show(ProgressDialogActivity.this, "请稍等", "数据正在加载中...", true);创建并显示一个进度对话框。
        调用setProgressStyle()方法设置进度对话框风格。有两种风格:
             ProgressDialog.STYLE_SPINNER 旋体进度条风格 (为默认风格)
             ProgressDialog.STYLE_HORIZONTAL 横向进度条风格
    
        35.1:创建进度条:
            在布局xml文件中添加进度条代码:
            <ProgressBar android:layout_width="fill_parent" android:layout_height="20px"
                style="?android:attr/progressBarStyleHorizontal"
                android:id="@+id/downloadbar"/>

            在代码中操作进度条:
            ProgressBar.setMax(100);//设置总长度为100
            ProgressBar.setProgress(0);//设置已经开启长度为0,假设设置为50,进度条将进行到一半

    36.android样式和主题(style&theme):

        android中的样式和CSS样式作用相似,都是用于为界面元素定义显示风格,它是一个包含一个或者多个view控件属性的集合。如:需要定义字体的颜色和大小。
        在CSS中是这样定义的:
        <style>
            .itcast{COLOR:#0000CC;font-size:18px;}
        </style>
        可以像这样使用上面的css样式:<div class="itcast">传智播客</div>
        在Android中可以这样定义样式:
        在res/values/styles.xml文件中添加以下内容
        <?xml version="1.0" encoding="utf-8"?>
        <resources>
            <style name=“itcast”> <!-- 为样式定义一个全局唯一的名字-->
            <item name="android:textSize">18px</item> <!-- name属性为样式要用在的View控件持有的属性 -->
            <item name="android:textColor">#0000CC</item>
            </style>
        </resources>
        在layout文件中可以像下面这样使用上面的android样式:
        <?xml version="1.0" encoding="utf-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" ....>
            <TextView style="@style/itcast"
            .....  />
        </LinearLayout>

           样式继承:
        <style>元素中有一个parent属性。这个属性可以让当前样式继承一个父样式,当前样式可以继承到父样式的值。当然,如果父样式的值不符合你的需求,你也可以对它进行修改,如下:
        <?xml version="1.0" encoding="utf-8"?>
        <resources>
            <style name="itcast">
            <item name="android:textSize">18px</item> <!-- name属性为样式要用在的View控件持有的属性 -->
            <item name="android:textColor">#0000CC</item>
            </style>
            <style name="subitcast" parent="@style/itcast">
            <item name="android:textColor">#FF0000</item>
            </style>
        </resources>

        android中主题也是用于为应用定义显示风格,它的定义和样式的定义相同,如下:
        <?xml version="1.0" encoding="utf-8"?>
        <resources>
        <style name=“itcastTheme">
            <item name=“android:windowNoTitle”>true</item> <!– 没标题 
            <item name=“android:windowFullscreen”>?android:windowNoTitle</item> <!– 全屏显示 
        </style>
        </resources>
        上面“?android:windowNoTitle”中的问号用于引用在当前主题中定义过的资源的值。下面代码显示在AndroidManifest.xml中如何为应用设置上面定义的主题:
        <application android:icon="@drawable/icon" android:label="@string/app_name"
             android:theme="@style/itcastTheme">
           ......
        </application>
        除了可以在AndroidManifest.xml中设置主题,同样也可以在代码中设置主题,如下:
        setTheme(R.style.itcastTheme);
        尽管在定义上,样式和主题基本相同,但是它们使用的地方不同。样式用在单独的View,如:EditText、TextView等;主题通过AndroidManifest.xml中的<application>和<activity>用在整个应用或者某个 Activity,主题对整个应用或某个Activity存在全局性影响。如果一个应用使用了主题,同时应用下的view也使用了样式,那么当主题与样式属性发生冲突时,样式的优先级高于主题。
        另外android系统也定义了一些主题,例如:<activity android:theme=“@android:style/Theme.Dialog”>,该主题可以让Activity看起来像一个对话框,如果需要查阅这些主题,可以在文档的referenceandroid-->R.style 中查看。
    
    37.Android中的显示单位:

         px (pixels)像素
             一般HVGA代表320x480像素,这个用的比较多。

         dip或dp (device independent pixels)设备独立像素
            这个和设备硬件有关,一般为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。

         sp (scaled pixels — best for text size)比例像素
            主要处理字体的大小,可以根据系统的字体自适应。

        下面几个不太常用:
         in (inches)英寸
         mm (millimeters)毫米  
         pt (points)点,1/72英寸

        为了适应不同分辨率,不同的像素密度,推荐使用dip ,文字使用sp。
    




Android:控件属性

控件属性:

android属性

Android功能强大,界面华丽,但是众多的布局属性就害苦了开发者,下面这篇文章结合了网上不少资料,

第一类:属性值为true或false
android:layout_centerHrizontal  水平居中
android:layout_centerVertical   垂直居中
android:layout_centerInparent    相对于父元素完全居中
android:layout_alignParentBottom 贴紧父元素的下边缘
android:layout_alignParentLeft   贴紧父元素的左边缘
android:layout_alignParentRight  贴紧父元素的右边缘
android:layout_alignParentTop    贴紧父元素的上边缘
android:layout_alignWithParentIfMissing  如果对应的兄弟元素找不到的话就以父元素做参照物
第二类:属性值必须为id的引用名“@id/id-name”
android:layout_below      在某元素的下方
android:layout_above      在某元素的的上方
android:layout_toLeftOf   在某元素的左边
android:layout_toRightOf  在某元素的右边
android:layout_alignTop   本元素的上边缘和某元素的的上边缘对齐
android:layout_alignLeft  本元素的左边缘和某元素的的左边缘对齐
android:layout_alignBottom 本元素的下边缘和某元素的的下边缘对齐
android:layout_alignRight  本元素的右边缘和某元素的的右边缘对齐 

第三类:属性值为具体的像素值,如30dip,40px
android:layout_marginBottom       离某元素底边缘的距离
android:layout_marginLeft         离某元素左边缘的距离
android:layout_marginRight        离某元素右边缘的距离
android:layout_marginTop          离某元素上边缘的距离

EditText的android:hint  设置EditText为空时输入框内的提示信息。
android:gravity 
android:gravity属性是对该view 内容的限定.比如一个button 上面的text.  你可以设置该text 在view的靠左,靠右等位置.以button为例,android:gravity="right"则button上面的文字靠右
android:layout_gravity
android:layout_gravity是用来设置该view相对与起父view 的位置.比如一个button 在linearlayout里,你想把该button放在靠左、靠右等位置就可以通过该属性设置.以button为例,android:layout_gravity="right"则button靠右
android:scaleType:
android:scaleType是控制图片如何resized/moved来匹对ImageView的size。ImageView.ScaleType / android:scaleType值的意义区别:
CENTER /center  按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示
CENTER_CROP / centerCrop  按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽)
CENTER_INSIDE / centerInside  将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽
FIT_CENTER / fitCenter  把图片按比例扩大/缩小到View的宽度,居中显示
FIT_END / fitEnd   把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置
FIT_START / fitStart  把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置
FIT_XY / fitXY  把图片不按比例扩大/缩小到View的大小显示
MATRIX / matrix 用矩阵来绘制,动态缩小放大图片来显示。
** 要注意一点,Drawable文件夹里面的图片命名是不能大写的。
-------------------------------------------------------------------------------------------------------------------------------------------------------------
android:id
为控件指定相应的ID
android:text
指定控件当中显示的文字,需要注意的是,这里尽量使用strings.xml文件当中的字符串
android:gravity
指定View组件的对齐方式,比如说居中,居右等位置 这里指的是控件中的文本位置并不是控件本身
android:layout_gravity
指定Container组件的对齐方式.比如一个button 在linearlayout里,你想把该button放在靠左、靠右等位置就可以通过该属性设置.以button为 例,android:layout_gravity="right"则button靠右
android:textSize
指定控件当中字体的大小
android:background
指定该控件所使用的背景色,RGB命名法
android:width
指定控件的宽度
android:height
指定控件的高度
android:layout_width
指定Container组件的宽度
android:layout_height
指定Container组件的高度
android:layout_weight
View中很重要的属性,按比例划分空间
android:padding*
指定控件的内边距,也就是说控件当中的内容
android:sigleLine
如果设置为真的话,则控件的内容在同一行中进行显示
android:scaleType
是控制图片如何resized/moved来匹对ImageView的siz
android:layout_centerHrizontal
水平居中
android:layout_centerVertical
垂直居中
android:layout_centerInparent
相对于父元素完全居中
android:layout_alignParentBottom
贴紧父元素的下边缘
android:layout_alignParentLeft
贴紧父元素的左边缘
android:layout_alignParentRight
贴紧父元素的右边缘
android:layout_alignParentTop
贴紧父元素的上边缘
android:layout_alignWithParentIfMissing
如果对应的兄弟元素找不到的话就以父元素做参照物
android:layout_below
在某元素的下方
android:layout_above
在某元素的的上方
android:layout_toLeftOf
在某元素的左边
android:layout_toRightOf
在某元素的右边
android:layout_alignTop
本元素的上边缘和某元素的的上边缘对齐
android:layout_alignLeft
本元素的左边缘和某元素的的左边缘对齐
android:layout_alignBottom
本元素的下边缘和某元素的的下边缘对齐
android:layout_alignRight
本元素的右边缘和某元素的的右边缘对齐
android:layout_marginBottom
离某元素底边缘的距离
android:layout_marginLeft
离某元素左边缘的距离
android:layout_marginRight
离某元素右边缘的距离
android:layout_marginTop
离某元素上边缘的距离
android:paddingLeft
本元素内容离本元素右边缘的距离
android:paddingRight
本元素内容离本元素上边缘的距离
android:hint
设置EditText为空时输入框内的提示信息
android:LinearLayout
它确定了LinearLayout的方向,其值可以为vertical, 表示垂直布局horizontal, 表示水平布局

-----------------------------------------------------------------------------------------------------------------------------------------------------
android:interpolator
可能有很多人不理解它的用法,文档里说的也不太清楚,其实很简单,看下面:interpolator定义一个动画的变化率(the rate of change)。这使得基本的动画效果(alpha, scale, translate, rotate)得以加速,减速,重复等。用通俗的一点的话理解就是:动画的进度使用 Interpolator 控制。interpolator 定义了动画的变化速度,可以实现匀速、正加速、负加速、无规则变加速等。Interpolator 是基类,封装了所有 Interpolator 的共同方法,它只有一个方法,即 getInterpolation (float input),该方法 maps a point on the timeline to a multiplier to be applied to the transformations of an animation。Android 提供了几个 Interpolator 子类,实现了不同的速度曲线,如下:
AccelerateDecelerateInterpolator        在动画开始与介绍的地方速率改变比较慢,在中间的时侯加速
AccelerateInterpolator        在动画开始的地方速率改变比较慢,然后开始加速
CycleInterpolator        动画循环播放特定的次数,速率改变沿着正弦曲线
DecelerateInterpolator        在动画开始的地方速率改变比较慢,然后开始减速
LinearInterpolator        在动画的以均匀的速率改变
对于 LinearInterpolator ,变化率是个常数,即 f (x) = x.
public float getInterpolation(float input) {
return input;
}
Interpolator其他的几个子类,也都是按照特定的算法,实现了对变化率。还可以定义自己的 Interpolator 子类,实现抛物线、自由落体等物理效果。 

 

 

 

TextView属性汇总

android:autoLink设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接。可选值(none/web/email/phone/map/all)

android:autoText如果设置,将自动执行输入值的拼写纠正。此处无效果,在显示输入法并输入的时候起作用。

android:bufferType指定getText()方式取得的文本类别。选项editable 类似于StringBuilder可追加字符,也就是说getText后可调用append方法设置文本内容。spannable 则可在给定的字符区域使用样式,参见这里1、这里2。

android:capitalize设置英文字母大写类型。此处无效果,需要弹出输入法才能看得到,参见EditView此属性说明。

android:cursorVisible设定光标为显示/隐藏,默认显示。

android:digits设置允许输入哪些字符。如“1234567890.+-*/% ()”

android:drawableBottom在text的下方输出一个drawable,如图片。如果指定一个颜色的话会把text的背景设为该颜色,并且同时和background使用时覆盖后者。

android:drawableLeft在text的左边输出一个drawable,如图片。

android:drawablePadding设置text与drawable(图片)的间隔,与drawableLeft、 drawableRight、drawableTop、drawableBottom一起使用,可设置为负数,单独使用没有效果。

android:drawableRight在text的右边输出一个drawable。

android:drawableTop在text的正上方输出一个drawable。

android:editable设置是否可编辑。

android:editorExtras设置文本的额外的输入数据。

android:ellipsize设置当文字过长时,该控件该如何显示。有如下值设置:”start”—-省略号显示在开头;”end” ——省略号显示在结尾;”middle”—-省略号显示在中间;”marquee” ——以跑马灯的方式显示(动画横向移动)

android:freezesText设置保存文本的内容以及光标的位置。

android:gravity设置文本位置,如设置成“center”,文本将居中显示。

android:hintText为空时显示的文字提示信息,可通过textColorHint设置提示信息的颜色。此属性在 EditView中使用,但是这里也可以用。

android:imeOptions附加功能,设置右下角IME动作与编辑框相关的动作,如actionDone右下角将显示一个“完成”,而不设置默认是一个回车符号。这个在EditView中再详细说明,此处无用。

android:imeActionId设置IME动作ID。

android:imeActionLabel设置IME动作标签。

android:includeFontPadding设置文本是否包含顶部和底部额外空白,默认为true。

android:inputMethod为文本指定输入法,需要完全限定名(完整的包名)。例如:com.google.android.inputmethod.pinyin,但是这里报错找不到。

android:inputType设置文本的类型,用于帮助输入法显示合适的键盘类型。在EditView中再详细说明,这里无效果。

android:linksClickable设置链接是否点击连接,即使设置了autoLink。

android:marqueeRepeatLimit在ellipsize指定marquee的情况下,设置重复滚动的次数,当设置为 marquee_forever时表示无限次。

android:ems设置TextView的宽度为N个字符的宽度。这里测试为一个汉字字符宽度

android:maxEms设置TextView的宽度为最长为N个字符的宽度。与ems同时使用时覆盖ems选项。

android:minEms设置TextView的宽度为最短为N个字符的宽度。与ems同时使用时覆盖ems选项。

android:maxLength限制显示的文本长度,超出部分不显示。

android:lines设置文本的行数,设置两行就显示两行,即使第二行没有数据。

android:maxLines设置文本的最大显示行数,与width或者layout_width结合使用,超出部分自动换行,超出行数将不显示。

android:minLines设置文本的最小行数,与lines类似。

android:lineSpacingExtra设置行间距。

android:lineSpacingMultiplier设置行间距的倍数。如”1.2”

android:numeric如果被设置,该TextView有一个数字输入法。此处无用,设置后唯一效果是TextView有点击效果,此属性在EdtiView将详细说明。

android:password以小点”.”显示文本

android:phoneNumber设置为电话号码的输入方式。

android:privateImeOptions设置输入法选项,此处无用,在EditText将进一步讨论。

android:scrollHorizontally设置文本超出TextView的宽度的情况下,是否出现横拉条。

android:selectAllOnFocus如果文本是可选择的,让他获取焦点而不是将光标移动为文本的开始位置或者末尾位置。 TextView中设置后无效果。

android:shadowColor指定文本阴影的颜色,需要与shadowRadius一起使用。

android:shadowDx设置阴影横向坐标开始位置。

android:shadowDy设置阴影纵向坐标开始位置。

android:shadowRadius设置阴影的半径。设置为0.1就变成字体的颜色了,一般设置为3.0的效果比较好。

android:singleLine设置单行显示。如果和layout_width一起使用,当文本不能全部显示时,后面用“…”来表示。如android:text="test_ singleLine "

android:singleLine="true" android:layout_width="20dp"将只显示“t…”。如果不设置singleLine或者设置为false,文本将自动换行

android:text设置显示文本.

android:textAppearance设置文字外观。如 “?android:attr/textAppearanceLargeInverse”这里引用的是系统自带的一个外观,?表示系统是否有这种外观,否则使用默认的外观。可textAppearanceButton/textAppearanceInverse/textAppearanceLarge/textAppearanceLargeInverse/textAppearanceMedium/textAppearanceMediumInverse/textAppearanceSmall/textAppearanceSmallInverse

android:textColor设置文本颜色

android:textColorHighlight被选中文字的底色,默认为蓝色

android:textColorHint设置提示信息文字的颜色,默认为灰色。与hint一起使用。

android:textColorLink文字链接的颜色.

android:textScaleX设置文字之间间隔,默认为1.0f。

android:textSize设置文字大小,推荐度量单位”sp”,如”15sp”

android:textStyle设置字形[bold(粗体) 0, italic(斜体) 1, bolditalic(又粗又斜) 2] 可以设置一个或多个,用“|”隔开

android:typeface设置文本字体,必须是以下常量值之一:normal 0, sans 1, serif 2, monospace(等宽字体) 3]

android:height设置文本区域的高度,支持度量单位:px(像素)/dp/sp/in/mm(毫米)

android:maxHeight设置文本区域的最大高度

android:minHeight设置文本区域的最小高度

android:width设置文本区域的宽度,支持度量单位:px(像素)/dp/sp/in/mm(毫米),与layout_width 的区别看这里。

android:maxWidth设置文本区域的最大宽度

android:minWidth设置文本区域的最小宽度

 

Android activity属性汇总

android:allowTaskReparenting

是否允许activity更换从属的任务,比如从短信息任务切换到浏览器任务。

android:alwaysRetainTaskState

是否保留状态不变, 比如切换回home, 再从新打开, activity处于最后的状态

android:clearTaskOnLanunch

比如 P 是 activity, Q 是被P 触发的 activity, 然后返回Home, 从新启动 P,是否显示 Q

android:configChanges

当配置list发生修改时,是否调用 onConfigurationChanged() 方法 比如 "locale|navigation|orientation".

android:enabled

activity 是否可以被实例化,

android:excludeFromRecents

是否可被显示在最近打开的activity列表里

android:exported

是否允许activity被其它程序调用

android:finishOnTaskLaunch

是否关闭已打开的activity当用户重新启动这个任务的时候

android.icon

android:label

android:launchMode

activity启动方式, "standard" "singleTop" "singleTask" "singleInstance"

其中前两个为一组, 后两个为一组

android:multiprocess

允许多进程

android:name

activity的类名, 必须指定

androidnHistory

是否需要移除这个activity当用户切换到其他屏幕时。这个属性是 API level 3 中引入的

android:permission

android:process

一 个activity运行时所在的进程名,所有程序组件运行在应用程序默认的进程中,这个进程名跟应用程序的包名一致。中的元素process属性能够为所有组件设定一个新的默认值。但是任何组件都可以覆盖这个默认值,允许你将你的程序放在多进程中运行。 如果这个属性被分配的名字以:开头,当这个activity运行时, 一个新的专属于这个程序的进程将会被创建。如果这个进程名以小写字母开头,这个activity将会运行在全局的进程中,被它的许可所提供。

android:screenOrientation

activity显示的模式, "unspecified" 默认值 "landscape" 风景画模式,宽度比高度大一些 "portrait" 肖像模式, 高度比宽度大。 "user" 用户的设置 "behind" "sensor" "nosensor"

android:stateNotNeeded

是否 activity被销毁和成功重启并不保存状态

android:taskAffinity

activity的亲属关系, 默认情况同一个应用程序下的activity有相同的关系

android:theme

activity的样式主题, 如果没有设置,则activity的主题样式从属于应用程序,参见元素的theme属性

android:windowSoftInputMode

activity主窗口与软键盘的交互模式, 自从API level 3 被引入

活动的主窗口如何与包含屏幕上的软键盘窗口交互。这个属性的设置将会影响两件事情:

1>     软键盘的状态——是否它是隐藏或显示——当活动(Activity)成为用户关注的焦点。

2>     活动的主窗口调整——是否减少活动主窗口大小以便腾出空间放软键盘或是否当活动窗口的部分被软键盘覆盖时它的内容的当前焦点是可见的。

它的设置必须是下面列表中的一个值,或一个”state…”值加一个”adjust…”值的组合。在任一组设置多个值——多个”state…”values,例如&mdash有未定义的结果。各个值之间用|分开。例如: <activity android:windowSoftInputMode="stateVisible|adjustResize" . . . >

在这设置的值(除"stateUnspecified"和"adjustUnspecified"以外)将覆盖在主题中设置的值

值 描述

 "stateUnspecified" 软键盘的状态(是否它是隐藏或可见)没有被指定。系统将选择一个合适的状态或依赖于主题的设置。这个是为了软件盘行为默认的设置。

 

"stateUnchanged" 软键盘被保持无论它上次是什么状态,是否可见或隐藏,当主窗口出现在前面时。

 "stateHidden" 当用户选择该Activity时,软键盘被隐藏——也就是,当用户确定导航到该Activity时,而不是返回到它由于离开另一个Activity。

 "stateAlwaysHidden" 软键盘总是被隐藏的,当该Activity主窗口获取焦点时。

 "stateVisible" 软键盘是可见的,当那个是正常合适的时(当用户导航到Activity主窗口时)。

 "stateAlwaysVisible" 当用户选择这个Activity时,软键盘是可见的——也就是,也就是,当用户确定导航到该Activity时,而不是返回到它由于离开另一个Activity。

 

"adjustUnspecified" 它不被指定是否该Activity主窗口调整大小以便留出软键盘的空间,或是否窗口上的内容得到屏幕上当前的焦点是可见的。系统将自动选择这些模式中一种主要依赖于是否窗口的内容有任何布局视图能够滚动他们的内容。如果有这样的一个视图,这个窗口将调整大小,这样的假设可以使滚动窗口的内容在一个较小的区域中可见的。这个是主窗口默认的行为设置。

 

"adjustResize" 该Activity主窗口总是被调整屏幕的大小以便留出软键盘的空间。

 

"adjustPan" 该Activity主窗口并不调整屏幕的大小以便留出软键盘的空间。相反,当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分。这个通常是不期望比调整大小,因为用户可能关闭软键盘以便获得与被覆盖内容的交互操作。

 

Android EditText 属性汇总

android:layout_gravity="center_vertical"

设置控件显示的位置:默认top,这里居中显示,还有bottom

android:hint="请输入数字!"

设置显示在空间上的提示信息

android:numeric="integer"

设置只能输入整数,如果是小数则是:decimal

android:singleLine="true"

设置单行输入,一旦设置为true,则文字不会自动换行。

android:password="true"

设置只能输入密码

android:textColor = "#ff8c00"

字体颜色

android:textStyle="bold"

字体,bold, italic, bolditalic

android:textSize="20dip"

大小

android:capitalize = "characters"

以大写字母写

android:textAlign="center"

EditText没有这个属性,但TextView有

android:textColorHighlight="#cccccc"

被选中文字的底色,默认为蓝色

android:textColorHint="#ffff00"

设置提示信息文字的颜色,默认为灰色

android:textScaleX="1.5"

控制字与字之间的间距

android:typeface="monospace"

字型,normal, sans, serif, monospace

android:background="@null"

空间背景,这里没有,指透明

android:layout_weight="1"

权重,控制控件之间的地位,在控制控件显示的大小时蛮有用的。

android:textAppearance="?android:attr/textAppearanceLargeInverse"

文字外观,这里引用的是系统自带的一个外观,?表示系统是否有这种外观,否则使用默认的外观。不知道这样理解对不对?

 

通过EditText的layout xml文件中的相关属性来实现: 

  1. 密码框属性 android:password="true"  这条可以让EditText显示的内容自动为星号,输入时内容会在1秒内变成*字样。

  2. 纯数字 android:numeric="true" 这条可以让输入法自动变为数字输入键盘,同时仅允许0-9的数字输入

  3. 仅允许 android:capitalize="cwj1987" 这样仅允许接受输入cwj1987,一般用于密码验证

  下面是一些扩展的风格属性

  android:editable="false" 设置EditText不可编辑

  android:singleLine="true" 强制输入的内容在单行

  android:ellipsize="end" 自动隐藏尾部溢出数据,一般用于文字内容过长一行无法全部显示时

 

 

RelativeLayout布局 

 

android:layout_marginTop="25dip" //顶部距离 

android:gravity="left" //空间布局位置 

android:layout_marginLeft="15dip //距离左边距 

 

// 相对于给定ID控件 

android:layout_above 将该控件的底部置于给定ID的控件之上; 

android:layout_below 将该控件的底部置于给定ID的控件之下; 

android:layout_toLeftOf    将该控件的右边缘与给定ID的控件左边缘对齐; 

android:layout_toRightOf  将该控件的左边缘与给定ID的控件右边缘对齐; 

android:layout_alignBaseline  将该控件的baseline与给定ID的baseline对齐; 

android:layout_alignTop        将该控件的顶部边缘与给定ID的顶部边缘对齐; 

android:layout_alignBottom   将该控件的底部边缘与给定ID的底部边缘对齐; 

android:layout_alignLeft        将该控件的左边缘与给定ID的左边缘对齐; 

android:layout_alignRight      将该控件的右边缘与给定ID的右边缘对齐; 

 

// 相对于父组件 

android:layout_alignParentTop      如果为true,将该控件的顶部与其父控件的顶部对齐; 

android:layout_alignParentBottom 如果为true,将该控件的底部与其父控件的底部对齐; 

android:layout_alignParentLeft      如果为true,将该控件的左部与其父控件的左部对齐; 

android:layout_alignParentRight    如果为true,将该控件的右部与其父控件的右部对齐; 

 

// 居中 

android:layout_centerHorizontal 如果为true,将该控件的置于水平居中; 

android:layout_centerVertical     如果为true,将该控件的置于垂直居中; 

android:layout_centerInParent   如果为true,将该控件的置于父控件的中央; 

 

// 指定移动像素 

android:layout_marginTop      上偏移的值; 

android:layout_marginBottom 下偏移的值; 

android:layout_marginLeft   左偏移的值; 

android:layout_marginRight   右偏移的值;

 

android:id  --- 为控件指定相应的ID 

android:text --- 指定控件当中显示的文字,需要注意的是,这里尽量使用strings.xml文件当中的字符串 

android:grivity --- 指定控件的基本位置,比如说居中,居右等位置这里指的是控件中的文本位置并不是控件本身。 

android:textSize --- 指定控件当中字体的大小 

android:background --- 指定该控件所使用的背景色,RGB命名法 

android:width --- 指定控件的宽度 

android:height --- 指定控件的高度 

android:padding* --- 指定控件的内边距,也就是说控件当中的内容 

android:sigleLine --- 如果设置为真的话,则控件的内容在同一行中进行显示 

 

下边是相对布局属性的说明:RelativeLayout 

 

android:layout_above 将该控件的底部至于给定ID控件之上 

android:layout_below 将该控件的顶部至于给定ID的控件之下 

android:layout_toLeftOf 将该控件的右边缘和给定ID的控件左边缘对齐 

android:layout_toRightOf 将该控件的左边缘和给定ID的控件的右边缘对齐 

 

android:layout_alignBaseline 该控件的baseline和给定ID的控件的baseline对齐 

android:layout_alignBottom 将该控件的底部边缘与给定ID控件的底部边缘对齐 

android:layout_alignLeft 将该控件的左边缘与给定ID控件的左边缘对齐 

android:layout_alignRight 将该控件的右边缘与给定ID控件的右边缘对齐 

android:layout_alignTop 将该控件的顶部边缘与给定ID控件的顶部对齐 

 

android:alignParentBottom 如果该值为true,则将该控件的底部和父控件的底部对齐 

android:layout_alignParentLeft 如果该值为true,则将该控件左边与父控件的左边对齐 

android:layout_alignParentRight 如果该值为true,则将该控件的右边与父控件的右边对齐 

android:layout_alignParentTop 如果该值为true,则将该控件的顶部与父控件的顶部对齐 

 

android:layout_centerHorizontal 如果为真,该控件将被至于水平方向的中央 

android:layout_centerInParent 如果为真,该控件将被至于父控件水平方向和垂直方向的中央 

android:layout_centerVertical 如果为真,该控件将被至于垂直方向的中央 

android:layout_marginLeft此属性用来设置控件之间的间隙(控件和控件之间和内边距不同) 

android:padding="3dip"说明了四边的内边距是3dip 

              

 

TableLayout 

 

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" 

    android:orientation="vertical" 

   android:layout_width="fill_parent" 

  android:layout_height="fill_parent" 

    android:stretchColumns="0" 

    ></TableLayout> 

 

android:stretchColumns="0"第一列作为拉伸列填满整行 

Java中修饰符总结:

 

1、访问控制修饰符

public的访问级别是最高的,其次是protected、默认和private

成员变量和成员方法可以处于4个访问级别中的一个:公开、受保护、默认或私有

顶层类可以处于公开或默认级别,顶层类不能被protected和private修饰

局部变量不能被访问控制修饰符修饰

2、abstract修饰符

抽象类不能被实例化

抽象类中可以没有抽象方法,但包含了抽象方法的类必须被定义为抽象方法

如果子类没有实现父类中所有的抽象方法,子类也必须定义为抽象类

抽象类不能被定义为private、final、和static类型

没有抽象的构造方法

抽象方法没有方法体

3、final修饰符

用final修饰的类不能被继承

用final修饰的方法不能被子类的方法覆盖

private类型的方法都默认为是final方法,因而不能被子类的方法覆盖

final变量必须被显式初始化,并且只能被赋值一次值

4、static修饰符

静态变量在内存中只有一个拷贝,在类的所有实例中共享

在静态方法中不能直接访问实例方法和实例变量

在静态方法中不能使用this和super关键字

静态方法不能被abstract修饰

静态方法和静态变量都可以通过类名直接访问

当类被加载时,静态代码块只能被执行一次。类中不同的静态方法代码块按他们在类中出现的顺序被依次执行

当多个修饰符连用时,修饰符的顺序可以颠倒,不过作为普遍遵守的编程规范,通常把访问控制修饰符放在首位,其次是static或abstact修饰符,接着就是其他的修饰符

5、以下修饰符连用是无意义的,会导致编译错误:

abstract与private

abstract与final

abstract与static