Android系列:四大组件、五大存储、六大布局

Android 之 四大组件、六大布局、五大存储 Android 之四大组件、六大布局、五大存储:https://blog.youkuaiyun.com/shenggaofei/article/details/52450668 Android 四大组件、五大存储、六大布局:https://blog.youkuaiyun.com/xiankog/article/details/81702119 Android四大基本组件介绍... 阅读详情
AI摘要

本文围绕Android开发展开,介绍了四大组件(Activity、Service、Content Provider、Broadcast Receiver)的注册、激活和关闭,以及Activity栈的相关知识;阐述了六大界面布局(线性、表格、帧、相对、网格、绝对布局)的特点和优化方法;还讲解了五大存储方式(SharedPreferences、文件、SQLite数据库、内容提供器、网络存储)的实现。

一、四大组件

Android 四大组件分别为activity、service、content provider、broadcast receiver。

1、activity

(1)一个Activity通常就是一个单独的屏幕(窗口)。

(2)Activity之间通过Intent进行通信。

(3)android应用中每一个Activity都必须要在AndroidManifest.xml配置文件中声明,否则系统将不识别也不执行该Activity。

2、service

  • service用于在后台完成用户指定的操作。service分为两种:

    • started(启动):当应用程序组件(如activity)调用startService()方法启动服务时,服务处于started状态。
    • bound(绑定):当应用程序组件调用bindService()方法绑定到服务时,服务处于bound状态。
  • startService()与bindService()区别:

    • started service(启动服务)是由其他组件调用startService()方法启动的,这导致服务的onStartCommand()方法被调用。当服务是started状态时,其生命周期与启动它的组件无关,并且可以在后台无限期运行,即使启动服务的组件已经被销毁。因此,服务需要在完成任务后调用stopSelf()方法停止,或者由其他组件调用stopService()方法停止。
    • 使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
  • 开发人员需要在应用程序配置文件中声明全部的service,使用标签。

  • Service通常位于后台运行,它一般不需要与用户交互,因此Service组件没有图形用户界面。Service组件需要继承Service基类。Service组件通常用于为其他组件提供后台服务或监控其他组件的运行状态。

3、content provider

  • android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。其他应用可以通过ContentResolver类从该内容提供者中获取或存入数据。

  • 只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。它的好处是统一数据访问方式。

  • ContentProvider实现数据共享。ContentProvider用于保存和获取数据,并使其对所有应用程序可见。这是不同应用程序间共享数据的唯一方式,因为android没有提供所有应用共同访问的公共存储区。

  • 开发人员不会直接使用ContentProvider类的对象,大多数是通过ContentResolver对象实现对ContentProvider的操作。

  • ContentProvider使用URI来唯一标识其数据集,这里的URI以content://作为前缀,表示该数据由ContentProvider来管理。

4、broadcast receiver

  • 你的应用可以使用它对外部事件进行过滤,只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个activity或serice来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力,例如闪动背灯、震动、播放声音等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。

  • 广播接收者的注册有两种方法,分别是程序动态注册和AndroidManifest文件中进行静态注册。

  • 动态注册广播接收器特点是当用来注册的Activity关掉后,广播也就失效了。静态注册无需担忧广播接收器是否被关闭,只要设备是开启状态,广播接收器也是打开着的。也就是说哪怕app本身未启动,该app订阅的广播在触发时也会对它起作用。

android四大组件总结

(1)4大组件的注册

4大基本组件都需要注册才能使用,每个Activity、service、Content Provider都需要在AndroidManifest文件中进行配置。AndroidManifest文件中未进行声明的activity、服务以及内容提供者将不为系统所见,从而也就不可用。而broadcast receiver广播接收者的注册分静态注册(在AndroidManifest文件中进行配置)和通过代码动态创建并以调用Context.registerReceiver()的方式注册至系统。需要注意的是在AndroidManifest文件中进行配置的广播接收者会随系统的启动而一直处于活跃状态,只要接收到感兴趣的广播就会触发(即使程序未运行)。

(2)4大组件的激活

内容提供者的激活:当接收到ContentResolver发出的请求后,内容提供者被激活。而其它三种组件activity、服务和广播接收器被一种叫做intent的异步消息所激活。

(3)4大组件的关闭

内容提供者仅在响应ContentResolver提出请求的时候激活。而一个广播接收器仅在响应广播信息的时候激活。所以,没有必要去显式的关闭这些组件。Activity关闭:可以通过调用它的finish()方法来关闭一个activity。服务关闭:对于通过startService()方法启动的服务要调用Context.stopService()方法关闭服务,使用bindService()方法启动的服务要调用Contex.unbindService()方法关闭服务。

(4)android中的任务(activity栈)

(a)任务其实就是activity的栈,它由一个或多个Activity组成,共同完成一个完整的用户体验。栈底的是启动整个任务的Activity,栈顶的是当前运行的用户可以交互的Activity,当一个activity启动另外一个的时候,新的activity就被压入栈,并成为当前运行的activity。而前一个activity仍保持在栈之中。当用户按下BACK键的时候,当前activity出栈,而前一个恢复为当前运行的activity。栈中保存的其实是对象,栈中的Activity永远不会重排,只会压入或弹出。

(b)任务中的所有activity是作为一个整体进行移动的。整个的任务(即activity栈)可以移到前台,或退至后台。

(c)Android系统是一个多任务(Multi-Task)的操作系统,可以在用手机听音乐的同时,也执行其他多个程序。每多执行一个应用程序,就会多耗费一些系统内存,当同时执行的程序过多,或是关闭的程序没有正确释放掉内存,系统就会觉得越来越慢,甚至不稳定。为了解决这个问题,Android引入了一个新的机制,即生命周期(Life Cycle)。

二、六大界面布局:

声明Android程序布局有两种方式:

  • 使用XML文件描述界面布局;

  • 在 Java 代码中通过调用方法进行控制。

我们既可以使用任何一种声明界面布局的方式,也可以同时使用两种方式。

使用XML文件声明有以下3个特点:

  • 将程序的表现层和控制层分离;
  • 在后期修改用户界面时,无须更改程序的源程序;
  • 可通过WYSIWYG可视化工具直接看到所设计的用户界面,有利于加快界面设计的过程。

建议尽量采用XML文件声明界面元素布局。在程序运行时动态添加界面布局会大大降低应用响应速度,但依然可以在必要时动态改变屏幕内容。

六大界面布局方式包括: 线性布局(LinearLayout)、框架布局(FrameLayout)、表格布局(TableLayout)、相对布局(RelativeLayout)、绝对布局(AbsoluteLayout)和网格布局(GridLayout) 。

1. LinearLayout线性布局

LinearLayout容器中的组件一个挨一个排列,通过控制android:orientation属性,可控制各组件是横向排列还是纵向排列。

LinearLayout的常用XML属性及相关方法
XML属性相关方法说明
android:gravitysetGravity(int)设置布局管理器内组件的对齐方式
android:orientationsetOrientation(int)设置布局管理器内组件的排列方式,可以设置为horizontal、vertical两个值之一

其中,gravity属性支持top, left, right, center_vertical, fill_vertical, center_horizontal, fill_horizontal, center, fill, clip_vertical, clip_horizontal。也可以同时指定多种对齐方式的组合。

LinearLayout子元素支持的常用XML属性及方法
XML属性说明
android:layout_gravity指定该子元素在LinearLayout中的对齐方式
android:layout_weight指定子元素在LinearLayout中所占的权重

2. TableLayout表格布局

TableLayout继承自Linearout,本质上仍然是线性布局管理器。表格布局采用行、列的形式来管理UI组件,并不需要明确地声明包含多少行、多少列,而是通过添加TableRow、其他组件来控制表格的行数和列数。

每向TableLayout中添加一个TableRow就代表一行;

每向TableRow中添加一个一个子组件就表示一列;

如果直接向TableLayout添加组件,那么该组件将直接占用一行;

在表格布局中,可以为单元格设置如下三种行为方式:

  • Shrinkable:该列的所有单元格的宽度可以被收缩,以保证该表格能适应父容器的宽度;
  • Strentchable:该列所有单元格的宽度可以被拉伸,以保证组件能完全填满表格空余空间;
  • Collapsed:如果该列被设置为Collapsed,那么该列的所有单元格会被隐藏;
TableLayout的常用XML属性及方法
XML属性相关方法说明
android:collapseColumnssetColumns(int, boolean)设置需要被隐藏的列的序号,多个序号间用逗号分隔
android:shrinkColumnssetShrinkAllColumns(boolean)设置需要被收缩的列的序号
android:stretchColumnssetStretchAllColumns(boolean)设置允许被拉伸的列的序号

3. FrameLayout帧布局

FrameLayout直接继承自ViewGroup组件。帧布局为每个加入其中的组件创建一个空白的区域(称为一帧),每个子组件占据一帧,这些帧会根据gravity属性执行自动对齐。

FrameLayout的常用XM了属性及方法
XML属性相关方法说明
android:foregroundsetForeground(Drawable)设置该帧布局容器的前景图像
android:foregroundGravitysetForeGroundGraity(int)定义绘制前景图像的gravity属性

4. RelativeLayout相对布局

RelativeLayout的XML属性及相关方法说明
XML属性相关方法说明
android:gravitysetGravity(int)
android:ignoreGravitysetIgnoreGravity(int)设置哪个组件不受gravity属性的影响

为了控制该布局容器的各子组件的布局分布,RelativeLayout提供了一个内部类:RelativeLayout.LayoutParams。

RelativeLayout.LayoutParams里只能设为boolean的XML属性
XML属性说明
android:layout_centerHorizontal设置该子组件是否位于布局容器的水平居中
android:layout_centerVertical
android:layout_centerParent
android:layout_alignParentBottom
android:layout_alignParentLeft
android:layout_alignParentRight
android:layout_alignParentTop
RelativeLayout.LayoutParams里属性值为其他UI组件ID的XML属性
XML属性说明
android:layout_toRightOf控制该子组件位于给出ID组件的右侧
android:layout_toLeftOf
android:layout_above
android:layout_below
android:layout_alignTop
android:layout_alignBottom
android:layout_alignRight
android:layout_alignLeft

5. Android 4.0新增的网格布局GridLayout

GridLayout是Android4.0增加的网格布局控件,与之前的TableLayout有些相似,它把整个容器划分为rows × columns个网格,每个网格可以放置一个组件。性能及功能都要比tablelayout好,比如GridLayout布局中的单元格可以跨越多行,而tablelayout则不行,此外,其渲染速度也比tablelayout要快。

GridLayout提供了setRowCount(int)和setColumnCount(int)方法来控制该网格的行和列的数量。

GridLayout常用的XML属性和方法说明
XML属性相关方法说明
android:alignmentModesetAlignmentMode(int)设置该布局管理器采用的对齐模式
android:columnCountsetColumnCount(int)设置该网格的列数量
android:columnOrderPreservedsetColumnOrderPreserved(boolean)设置该网格容器是否保留序列号
android:roeCountsetRowCount(int)设置该网格的行数量
android:rowOrderPreservedsetRowOrderPreserved(boolean)设置该网格容器是否保留行序号
android:useDefaultMarginssetUseDefaultMargins(boolean)设置该布局管理器是否使用默认的页边距

为了控制GridLayout布局容器中各子组件的布局分布,GridLayout提供了一个内部类:GridLayout.LayoutParams,来控制Gridlayout布局容器中子组件的布局分布。

GridLayout.LayoutParams常用的XML属性和方法说明
XML属性说明
android:layout_column设置该组件在GridLayout的第几列
android:layout_columnSpan设置该子组件在GridLayout横向上跨几列
android:layout_gravity设置该子组件采用何种方式占据该网格的空间
android:layout_row设置该子组件在GridLayout的第几行
android:layout_rowSpan设置该子组件在GridLayout纵向上跨几行

6. AbsoluteLayout绝对布局

即Android不提供任何布局控制,而是由开发人员自己通过X坐标、Y坐标来控制组件的位置。每个组件都可指定如下两个XML属性:

  • layour_x;
  • layout_y;

绝对布局已经过时,不应使用或少使用。

界面布局类型的选择和性能优化

首先得明确,界面布局类型的嵌套越多越深越复杂,会使布局实例化变慢,使Activity的展开时间延长。建议尽量减少布局嵌套,尽量减少创建View对象的数量。

1 . 减少布局层次,可考虑用RelativeLayout来代替LinearLayout。通过Relative的相对其他元素的位置来布局,可减少块状嵌套;

2 . 另一种减少布局层次的技巧是使用 <merge /> 标签来合并布局;

3 . 重用布局。Android支持在XML中使用 <include /> 标签, <include /> 通过指定android:layout属性来指定要包含的另一个XML布局。

如:

<include android:id="@+id/id1" android:layout="@layout/mylayout">
<include android:id="@+id/id2" android:layout="@layout/mylayout">
<include android:id="@+id/id3" android:layout="@layout/mylayout">

三.五大存储:

在 Android 中,可供选择的存储方式有SharedPreferences、文件存储、SQLite 数据库方式、内容提供器(Content provider)和网络。

一.SharedPreferences方式

​ Android提供用来存储一些简单的配置信息的一种机制,例如,一些默认欢迎语、登录的用户名和密码等。其以键值对的方式存储,

使得我们可以很方便的读取和存入.

​ 1)程序要实现的功能:
​ 我们在Name文本框中输入wangwu,在Password文本框中输入123456,然后退出这个应用。我们在应用程序列表中找到这个应用,重新启动,可以看到其使用了前面输入的Name和Password

​ 2)实现的代码

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    >  
    <TextView    
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
        android:text="SharedPreferences demo"  
    />  
      
    <TextView  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="name"  
        >  
    </TextView>  
      
    <EditText  
        android:id="@+id/name"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text=""  
        >  
    </EditText>  
      
    <TextView  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="password"  
        >  
    </TextView>  
      
    <EditText  
        android:id="@+id/password"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:password="true"  
        android:text=""  
        >  
    </EditText>  
</LinearLayout>  
<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    >  
    <TextView    
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
        android:text="SharedPreferences demo"  
    />  
      
    <TextView  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="name"  
        >  
    </TextView>  
      
    <EditText  
        android:id="@+id/name"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text=""  
        >  
    </EditText>  
      
    <TextView  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="password"  
        >  
    </TextView>  
      
    <EditText  
        android:id="@+id/password"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:password="true"  
        android:text=""  
        >  
    </EditText>  
</LinearLayout>  

主要实现代码

package com.demo;  
  
import android.app.Activity;  
import android.content.SharedPreferences;  
import android.os.Bundle;  
import android.widget.EditText;  
  
public class SharedPreferencesDemo extends Activity {  
      
    public static final String SETTING_INFOS = "SETTING_Infos";   
    public static final String NAME = "NAME";   
    public static final String PASSWORD = "PASSWORD";   
    private EditText field_name;  //接收用户名的组件   
    private EditText filed_pass;  //接收密码的组件   
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
          
        //Find VIew    
        field_name = (EditText) findViewById(R.id.name);  //首先获取用来输入用户名的组件   
        filed_pass = (EditText) findViewById(R.id.password); //同时也需要获取输入密码的组件   
  
        // Restore preferences   
        SharedPreferences settings = getSharedPreferences(SETTING_INFOS, 0); //获取一个SharedPreferences对象   
        String name = settings.getString(NAME, "");  //取出保存的NAME   
        String password = settings.getString(PASSWORD, ""); //取出保存的PASSWORD   
  
        //Set value   
        field_name.setText(name);  //将取出来的用户名赋予field_name   
        filed_pass.setText(password);  //将取出来的密码赋予filed_pass   
    }  
      
    @Override   
    protected void onStop(){   
        super.onStop();   
          
        SharedPreferences settings = getSharedPreferences(SETTING_INFOS, 0); //首先获取一个SharedPreferences对象   
        settings.edit()   
                .putString(NAME, field_name.getText().toString())   
                .putString(PASSWORD, filed_pass.getText().toString())   
                .commit();   
    } //将用户名和密码保存进去   
  
}  
package com.demo;  
  
import android.app.Activity;  
import android.content.SharedPreferences;  
import android.os.Bundle;  
import android.widget.EditText;  
  
public class SharedPreferencesDemo extends Activity {  
      
    public static final String SETTING_INFOS = "SETTING_Infos";   
    public static final String NAME = "NAME";   
    public static final String PASSWORD = "PASSWORD";   
    private EditText field_name;  //接收用户名的组件  
    private EditText filed_pass;  //接收密码的组件  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
          
        //Find VIew   
        field_name = (EditText) findViewById(R.id.name);  //首先获取用来输入用户名的组件  
        filed_pass = (EditText) findViewById(R.id.password); //同时也需要获取输入密码的组件  
  
        // Restore preferences  
        SharedPreferences settings = getSharedPreferences(SETTING_INFOS, 0); //获取一个SharedPreferences对象  
        String name = settings.getString(NAME, "");  //取出保存的NAME  
        String password = settings.getString(PASSWORD, ""); //取出保存的PASSWORD  
  
        //Set value  
        field_name.setText(name);  //将取出来的用户名赋予field_name  
        filed_pass.setText(password);  //将取出来的密码赋予filed_pass  
    }  
      
    @Override   
    protected void onStop(){   
        super.onStop();   
          
        SharedPreferences settings = getSharedPreferences(SETTING_INFOS, 0); //首先获取一个SharedPreferences对象  
        settings.edit()   
                .putString(NAME, field_name.getText().toString())   
                .putString(PASSWORD, filed_pass.getText().toString())   
                .commit();   
    } //将用户名和密码保存进去  
}  

SharedPreferences保存到哪里去了?

SharedPreferences是以XML的格式以文件的方式自动保存的,在DDMS中的File Explorer中展开到/data/data/<package

name>/shared_prefs下,以上面这个为例,可以看到一个叫做SETTING_Infos.xml的文件

注意:Preferences只能在同一个包内使用,不能在不同的包之间使用。

二.文件存储方式

​ 在Android中,其提供了openFileInput 和 openFileOuput 方法读取设备上的文件,下面看个例子代码,具体如下所示:
java String FILE_NAME = "tempfile.tmp"; //确定要操作文件的文件名 FileOutputStream fos = openFileOutput(FILE_NAME, Context.MODE_PRIVATE); //初始化 FileInputStream fis = openFileInput(FILE_NAME); //创建写入流

​ 上述代码中两个方法只支持读取该应用目录下的文件,读取非其自身目录下的文件将会抛出异常。需要提醒的是,如果调用

FileOutputStream 时指定的文件不存在,Android 会自动创建它。另外,在默认情况下,写入的时候会覆盖原文件内容,如果想把

新写入的内容附加到原文件内容后,则可以指定其模式为Context.MODE_APPEND。

三.SQLite 数据库方式

SQLite是Android所带的一个标准的数据库,它支持SQL语句,它是一个轻量级的嵌入式数据库。
1)实现的功能

​ 在这个例子里边,我们在程序的主界面有一些按钮,通过这些按钮可以对数据库进行标准的增、删、改、查。

2)实现代码

​ 所用到的字符文件

<?xml version="1.0" encoding="utf-8"?>  
<resources>  
    <string name="app_name">SQLite数据库操作实例</string>  
    <string name="button1">建立数据库表</string>  
    <string name="button2">删除数据库表</string>  
    <string name="button3">插入两条记录</string>  
    <string name="button4">删除一条记录</string>  
    <string name="button5">查看数据库表</string>  
</resources>  
<?xml version="1.0" encoding="utf-8"?>  
<resources>  
    <string name="app_name">SQLite数据库操作实例</string>  
    <string name="button1">建立数据库表</string>  
    <string name="button2">删除数据库表</string>  
    <string name="button3">插入两条记录</string>  
    <string name="button4">删除一条记录</string>  
    <string name="button5">查看数据库表</string>  
</resources>  

布局代码

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    >  
      
    <TextView    
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
        android:text="@string/app_name"  
    />  
    <Button   
        android:text="@string/button1"   
        android:id="@+id/button1"   
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"  
        ></Button>  
    <Button   
        android:text="@string/button2"   
        android:id="@+id/button2"   
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"  
        ></Button>  
    <Button   
        android:text="@string/button3"   
        android:id="@+id/button3"   
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"  
        ></Button>  
    <Button   
        android:text="@string/button4"   
        android:id="@+id/button4"   
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"  
        ></Button>  
    <Button   
        android:text="@string/button5"   
        android:id="@+id/button5"   
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"  
        ></Button>  
  
</LinearLayout>  
<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    >  
      
    <TextView    
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
        android:text="@string/app_name"  
    />  
    <Button   
        android:text="@string/button1"   
        android:id="@+id/button1"   
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"  
        ></Button>  
    <Button   
        android:text="@string/button2"   
        android:id="@+id/button2"   
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"  
        ></Button>  
    <Button   
        android:text="@string/button3"   
        android:id="@+id/button3"   
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"  
        ></Button>  
    <Button   
        android:text="@string/button4"   
        android:id="@+id/button4"   
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"  
        ></Button>  
    <Button   
        android:text="@string/button5"   
        android:id="@+id/button5"   
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"  
        ></Button>  
  
</LinearLayout> 

主要代码

package com.sqlite;  
  
import android.app.Activity;  
import android.content.Context;  
import android.database.Cursor;  
import android.database.SQLException;  
import android.database.sqlite.SQLiteDatabase;  
import android.database.sqlite.SQLiteOpenHelper;  
import android.os.Bundle;  
import android.util.Log;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
  
/* 
 * 什么是SQLiteDatabase? 
 * 一个SQLiteDatabase的实例代表了一个SQLite的数据库,通过SQLiteDatabase实例的一些方法,我们可以执行SQL语句, 
 * 对数据库进行增、删、查、改的操作。需要注意的是,数据库对于一个应用来说是私有的,并且在一个应用当中,数据库的名字也是惟一的。  
 */  
  
/* 
 * 什么是SQLiteOpenHelper ?  
 * 这个类主要生成一个数据库,并对数据库的版本进行管理。 
 * 当在程序当中调用这个类的方法getWritableDatabase()或者getReadableDatabase()方法的时候,如果当时没有数据,那么Android系统就会自动生成一个数据库。 
 * SQLiteOpenHelper 是一个抽象类,我们通常需要继承它,并且实现里边的3个函数, 
 *     onCreate(SQLiteDatabase):在数据库第一次生成的时候会调用这个方法,一般我们在这个方法里边生成数据库表。 
 *     onUpgrade(SQLiteDatabase, int, int):当数据库需要升级的时候,Android系统会主动的调用这个方法。一般我们在这个方法里边删除数据表,并建立新的数据表,当然是否还需要做其他的操作,完全取决于应用的需求。 
 *     onOpen(SQLiteDatabase):这是当打开数据库时的回调函数,一般也不会用到。  
 */  
  
public class SQLiteDemo extends Activity {  
      
    OnClickListener listener1 = null;  
    OnClickListener listener2 = null;  
    OnClickListener listener3 = null;  
    OnClickListener listener4 = null;  
    OnClickListener listener5 = null;  
  
    Button button1;  
    Button button2;  
    Button button3;  
    Button button4;  
    Button button5;  
  
    DatabaseHelper mOpenHelper;  
  
    private static final String DATABASE_NAME = "dbForTest.db";  
    private static final int DATABASE_VERSION = 1;  
    private static final String TABLE_NAME = "diary";  
    private static final String TITLE = "title";  
    private static final String BODY = "body";  
  
    //建立一个内部类,主要生成一个数据库   
    private static class DatabaseHelper extends SQLiteOpenHelper {  
          
        DatabaseHelper(Context context) {  
            super(context, DATABASE_NAME, null, DATABASE_VERSION);  
        }  
  
        //在数据库第一次生成的时候会调用这个方法,一般我们在这个方法里边生成数据库表。   
        @Override  
        public void onCreate(SQLiteDatabase db) {  
  
            String sql = "CREATE TABLE " + TABLE_NAME + " (" + TITLE  
                    + " text not null, " + BODY + " text not null " + ");";  
            Log.i("haiyang:createDB=", sql);  
            db.execSQL(sql);  
        }  
  
        @Override  
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
        }  
    }  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        prepareListener();  
        initLayout();  
        mOpenHelper = new DatabaseHelper(this);  
  
    }  
  
    private void initLayout() {  
        button1 = (Button) findViewById(R.id.button1);  
        button1.setOnClickListener(listener1);  
  
        button2 = (Button) findViewById(R.id.button2);  
        button2.setOnClickListener(listener2);  
  
        button3 = (Button) findViewById(R.id.button3);  
        button3.setOnClickListener(listener3);  
          
        button4 = (Button) findViewById(R.id.button4);  
        button4.setOnClickListener(listener4);  
  
        button5 = (Button) findViewById(R.id.button5);  
        button5.setOnClickListener(listener5);  
  
    }  
  
    private void prepareListener() {  
        listener1 = new OnClickListener() {  
            public void onClick(View v) {  
                CreateTable();  
            }  
        };  
        listener2 = new OnClickListener() {  
            public void onClick(View v) {  
                dropTable();  
            }  
        };  
        listener3 = new OnClickListener() {  
            public void onClick(View v) {  
                insertItem();  
            }  
        };  
        listener4 = new OnClickListener() {  
            public void onClick(View v) {  
                deleteItem();  
            }  
        };  
        listener5 = new OnClickListener() {  
            public void onClick(View v) {  
                showItems();  
            }  
        };  
    }  
  
    /* 
     * 重新建立数据表 
     */  
    private void CreateTable() {  
        //mOpenHelper.getWritableDatabase()语句负责得到一个可写的SQLite数据库,如果这个数据库还没有建立,   
        //那么mOpenHelper辅助类负责建立这个数据库。如果数据库已经建立,那么直接返回一个可写的数据库。   
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
        String sql = "CREATE TABLE " + TABLE_NAME + " (" + TITLE  
                + " text not null, " + BODY + " text not null " + ");";  
        Log.i("haiyang:createDB=", sql);  
  
        try {  
            db.execSQL("DROP TABLE IF EXISTS diary");  
            db.execSQL(sql);  
            setTitle("数据表成功重建");  
        } catch (SQLException e) {  
            setTitle("数据表重建错误");  
        }  
    }  
  
    /* 
     * 删除数据表 
     */  
    private void dropTable() {  
        //mOpenHelper.getWritableDatabase()语句负责得到一个可写的SQLite数据库,如果这个数据库还没有建立,   
        //那么mOpenHelper辅助类负责建立这个数据库。如果数据库已经建立,那么直接返回一个可写的数据库。   
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
        String sql = "drop table " + TABLE_NAME;  
        try {  
            db.execSQL(sql);  
            setTitle("数据表成功删除:" + sql);  
        } catch (SQLException e) {  
            setTitle("数据表删除错误");  
        }  
    }  
  
    /* 
     * 插入两条数据 
     */  
    private void insertItem() {  
        //mOpenHelper.getWritableDatabase()语句负责得到一个可写的SQLite数据库,如果这个数据库还没有建立,   
        //那么mOpenHelper辅助类负责建立这个数据库。如果数据库已经建立,那么直接返回一个可写的数据库。   
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
        String sql1 = "insert into " + TABLE_NAME + " (" + TITLE + ", " + BODY  
                + ") values('haiyang', 'android的发展真是迅速啊');";  
        String sql2 = "insert into " + TABLE_NAME + " (" + TITLE + ", " + BODY  
                + ") values('icesky', 'android的发展真是迅速啊');";  
        try {  
            // Log.i()会将参数内容打印到日志当中,并且打印级别是Info级别   
            // Android支持5种打印级别,分别是Verbose、Debug、Info、Warning、Error,当然我们在程序当中一般用到的是Info级别   
            Log.i("haiyang:sql1=", sql1);  
            Log.i("haiyang:sql2=", sql2);  
            db.execSQL(sql1);  
            db.execSQL(sql2);  
            setTitle("插入两条数据成功");  
        } catch (SQLException e) {  
            setTitle("插入两条数据失败");  
        }  
    }  
  
    /* 
     * 删除其中的一条数据 
     */  
    private void deleteItem() {  
        try {  
            //mOpenHelper.getWritableDatabase()语句负责得到一个可写的SQLite数据库,如果这个数据库还没有建立,   
            //那么mOpenHelper辅助类负责建立这个数据库。如果数据库已经建立,那么直接返回一个可写的数据库。   
            SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
            //第一个参数是数据库表名,在这里是TABLE_NAME,也就是diary。    
            //第二个参数,相当于SQL语句当中的where部分,也就是描述了删除的条件。   
            //如果在第二个参数当中有“?”符号,那么第三个参数中的字符串会依次替换在第二个参数当中出现的“?”符号。    
            db.delete(TABLE_NAME, " title = 'haiyang'", null);  
            setTitle("删除title为haiyang的一条记录");  
        } catch (SQLException e) {  
  
        }  
  
    }  
  
    /* 
     * 在屏幕的title区域显示当前数据表当中的数据的条数。 
     */  
    /* 
     * Cursor cur = db.query(TABLE_NAME, col, null, null, null, null, null)语句将查询到的数据放到一个Cursor 当中。 
        这个Cursor里边封装了这个数据表TABLE_NAME当中的所有条列。  
        query()方法相当的有用,在这里我们简单地讲一下。 
            第一个参数是数据库里边表的名字,比如在我们这个例子,表的名字就是TABLE_NAME,也就是"diary"。 
            第二个字段是我们想要返回数据包含的列的信息。在这个例子当中我们想要得到的列有title、body。我们把这两个列的名字放到字符串数组里边来。 
            第三个参数为selection,相当于SQL语句的where部分,如果想返回所有的数据,那么就直接置为null。 
            第四个参数为selectionArgs。在selection部分,你有可能用到“?”,那么在selectionArgs定义的字符串会代替selection中的“?”。 
            第五个参数为groupBy。定义查询出来的数据是否分组,如果为null则说明不用分组。 
            第六个参数为having ,相当于SQL语句当中的having部分。 
            第七个参数为orderBy,来描述我们期望的返回值是否需要排序,如果设置为null则说明不需要排序。 
     */  
      
    private void showItems() {  
  
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();  
        String col[] = { TITLE, BODY };  
        //查询数据   
        Cursor cur = db.query(TABLE_NAME, col, null, null, null, null, null);  
        Integer num = cur.getCount();  
        setTitle(Integer.toString(num) + " 条记录");  
    }  
}  
package com.sqlite;  
  
import android.app.Activity;  
import android.content.Context;  
import android.database.Cursor;  
import android.database.SQLException;  
import android.database.sqlite.SQLiteDatabase;  
import android.database.sqlite.SQLiteOpenHelper;  
import android.os.Bundle;  
import android.util.Log;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
  
/* 
 * 什么是SQLiteDatabase? 
 * 一个SQLiteDatabase的实例代表了一个SQLite的数据库,通过SQLiteDatabase实例的一些方法,我们可以执行SQL语句, 
 * 对数据库进行增、删、查、改的操作。需要注意的是,数据库对于一个应用来说是私有的,并且在一个应用当中,数据库的名字也是惟一的。  
 */  
  
/* 
 * 什么是SQLiteOpenHelper ?  
 * 这个类主要生成一个数据库,并对数据库的版本进行管理。 
 * 当在程序当中调用这个类的方法getWritableDatabase()或者getReadableDatabase()方法的时候,如果当时没有数据,那么Android系统就会自动生成一个数据库。 
 * SQLiteOpenHelper 是一个抽象类,我们通常需要继承它,并且实现里边的3个函数, 
 *     onCreate(SQLiteDatabase):在数据库第一次生成的时候会调用这个方法,一般我们在这个方法里边生成数据库表。 
 *     onUpgrade(SQLiteDatabase, int, int):当数据库需要升级的时候,Android系统会主动的调用这个方法。一般我们在这个方法里边删除数据表,并建立新的数据表,当然是否还需要做其他的操作,完全取决于应用的需求。 
 *     onOpen(SQLiteDatabase):这是当打开数据库时的回调函数,一般也不会用到。  
 */  
  
public class SQLiteDemo extends Activity {  
      
    OnClickListener listener1 = null;  
    OnClickListener listener2 = null;  
    OnClickListener listener3 = null;  
    OnClickListener listener4 = null;  
    OnClickListener listener5 = null;  
  
    Button button1;  
    Button button2;  
    Button button3;  
    Button button4;  
    Button button5;  
  
    DatabaseHelper mOpenHelper;  
  
    private static final String DATABASE_NAME = "dbForTest.db";  
    private static final int DATABASE_VERSION = 1;  
    private static final String TABLE_NAME = "diary";  
    private static final String TITLE = "title";  
    private static final String BODY = "body";  
  
    //建立一个内部类,主要生成一个数据库  
    private static class DatabaseHelper extends SQLiteOpenHelper {  
          
        DatabaseHelper(Context context) {  
            super(context, DATABASE_NAME, null, DATABASE_VERSION);  
        }  
  
        //在数据库第一次生成的时候会调用这个方法,一般我们在这个方法里边生成数据库表。  
        @Override  
        public void onCreate(SQLiteDatabase db) {  
  
            String sql = "CREATE TABLE " + TABLE_NAME + " (" + TITLE  
                    + " text not null, " + BODY + " text not null " + ");";  
            Log.i("haiyang:createDB=", sql);  
            db.execSQL(sql);  
        }  
  
        @Override  
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
        }  
    }  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        prepareListener();  
        initLayout();  
        mOpenHelper = new DatabaseHelper(this);  
  
    }  
  
    private void initLayout() {  
        button1 = (Button) findViewById(R.id.button1);  
        button1.setOnClickListener(listener1);  
  
        button2 = (Button) findViewById(R.id.button2);  
        button2.setOnClickListener(listener2);  
  
        button3 = (Button) findViewById(R.id.button3);  
        button3.setOnClickListener(listener3);  
          
        button4 = (Button) findViewById(R.id.button4);  
        button4.setOnClickListener(listener4);  
  
        button5 = (Button) findViewById(R.id.button5);  
        button5.setOnClickListener(listener5);  
  
    }  
  
    private void prepareListener() {  
        listener1 = new OnClickListener() {  
            public void onClick(View v) {  
                CreateTable();  
            }  
        };  
        listener2 = new OnClickListener() {  
            public void onClick(View v) {  
                dropTable();  
            }  
        };  
        listener3 = new OnClickListener() {  
            public void onClick(View v) {  
                insertItem();  
            }  
        };  
        listener4 = new OnClickListener() {  
            public void onClick(View v) {  
                deleteItem();  
            }  
        };  
        listener5 = new OnClickListener() {  
            public void onClick(View v) {  
                showItems();  
            }  
        };  
    }  
  
    /* 
     * 重新建立数据表 
     */  
    private void CreateTable() {  
        //mOpenHelper.getWritableDatabase()语句负责得到一个可写的SQLite数据库,如果这个数据库还没有建立,  
        //那么mOpenHelper辅助类负责建立这个数据库。如果数据库已经建立,那么直接返回一个可写的数据库。  
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
        String sql = "CREATE TABLE " + TABLE_NAME + " (" + TITLE  
                + " text not null, " + BODY + " text not null " + ");";  
        Log.i("haiyang:createDB=", sql);  
  
        try {  
            db.execSQL("DROP TABLE IF EXISTS diary");  
            db.execSQL(sql);  
            setTitle("数据表成功重建");  
        } catch (SQLException e) {  
            setTitle("数据表重建错误");  
        }  
    }  
  
    /* 
     * 删除数据表 
     */  
    private void dropTable() {  
        //mOpenHelper.getWritableDatabase()语句负责得到一个可写的SQLite数据库,如果这个数据库还没有建立,  
        //那么mOpenHelper辅助类负责建立这个数据库。如果数据库已经建立,那么直接返回一个可写的数据库。  
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
        String sql = "drop table " + TABLE_NAME;  
        try {  
            db.execSQL(sql);  
            setTitle("数据表成功删除:" + sql);  
        } catch (SQLException e) {  
            setTitle("数据表删除错误");  
        }  
    }  
  
    /* 
     * 插入两条数据 
     */  
    private void insertItem() {  
        //mOpenHelper.getWritableDatabase()语句负责得到一个可写的SQLite数据库,如果这个数据库还没有建立,  
        //那么mOpenHelper辅助类负责建立这个数据库。如果数据库已经建立,那么直接返回一个可写的数据库。  
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
        String sql1 = "insert into " + TABLE_NAME + " (" + TITLE + ", " + BODY  
                + ") values('haiyang', 'android的发展真是迅速啊');";  
        String sql2 = "insert into " + TABLE_NAME + " (" + TITLE + ", " + BODY  
                + ") values('icesky', 'android的发展真是迅速啊');";  
        try {  
            // Log.i()会将参数内容打印到日志当中,并且打印级别是Info级别  
            // Android支持5种打印级别,分别是Verbose、Debug、Info、Warning、Error,当然我们在程序当中一般用到的是Info级别  
            Log.i("haiyang:sql1=", sql1);  
            Log.i("haiyang:sql2=", sql2);  
            db.execSQL(sql1);  
            db.execSQL(sql2);  
            setTitle("插入两条数据成功");  
        } catch (SQLException e) {  
            setTitle("插入两条数据失败");  
        }  
    }  
  
    /* 
     * 删除其中的一条数据 
     */  
    private void deleteItem() {  
        try {  
            //mOpenHelper.getWritableDatabase()语句负责得到一个可写的SQLite数据库,如果这个数据库还没有建立,  
            //那么mOpenHelper辅助类负责建立这个数据库。如果数据库已经建立,那么直接返回一个可写的数据库。  
            SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
            //第一个参数是数据库表名,在这里是TABLE_NAME,也就是diary。   
            //第二个参数,相当于SQL语句当中的where部分,也就是描述了删除的条件。  
            //如果在第二个参数当中有“?”符号,那么第三个参数中的字符串会依次替换在第二个参数当中出现的“?”符号。   
            db.delete(TABLE_NAME, " title = 'haiyang'", null);  
            setTitle("删除title为haiyang的一条记录");  
        } catch (SQLException e) {  
  
        }  
  
    }  
  
    /* 
     * 在屏幕的title区域显示当前数据表当中的数据的条数。 
     */  
    /* 
     * Cursor cur = db.query(TABLE_NAME, col, null, null, null, null, null)语句将查询到的数据放到一个Cursor 当中。 
        这个Cursor里边封装了这个数据表TABLE_NAME当中的所有条列。  
        query()方法相当的有用,在这里我们简单地讲一下。 
            第一个参数是数据库里边表的名字,比如在我们这个例子,表的名字就是TABLE_NAME,也就是"diary"。 
            第二个字段是我们想要返回数据包含的列的信息。在这个例子当中我们想要得到的列有title、body。我们把这两个列的名字放到字符串数组里边来。 
            第三个参数为selection,相当于SQL语句的where部分,如果想返回所有的数据,那么就直接置为null。 
            第四个参数为selectionArgs。在selection部分,你有可能用到“?”,那么在selectionArgs定义的字符串会代替selection中的“?”。 
            第五个参数为groupBy。定义查询出来的数据是否分组,如果为null则说明不用分组。 
            第六个参数为having ,相当于SQL语句当中的having部分。 
            第七个参数为orderBy,来描述我们期望的返回值是否需要排序,如果设置为null则说明不需要排序。 
     */  
      
    private void showItems() {  
  
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();  
        String col[] = { TITLE, BODY };  
        //查询数据  
        Cursor cur = db.query(TABLE_NAME, col, null, null, null, null, null);  
        Integer num = cur.getCount();  
        setTitle(Integer.toString(num) + " 条记录");  
    }  
}  

四.内容提供器(Content provider)方式

在Android的设计“哲学”里是鼓励开发者使用内部类的,这样不但使用方便,而且执行效率也高。

1.什么是ContentProvider

数据在Android当中是私有的,当然这些数据包括文件数据和数据库数据以及一些其他类型的数据。难道两个程序之间就没有办法对于数据进行交换?解决这个问题主要靠ContentProvider。
一个Content Provider类实现了一组标准的方法接口,从而能够让其他的应用保存或读取此Content Provider的各种数据类型。也就是说,一个程序可以通过实现一个Content Provider的抽象接口将自己的数据暴露出去。外界根本看不到,也不用看到这个应用暴露的数据在应用当中是如何存储的,或者是用数据库存储还是用文件存储,还是通过网上获得,这些一切都不重要,重要的是外界可以通过这一套标准及统一的接口和程序里的数据打交道,可以读取程序的数据,也可以删除程序的数据,当然,中间也会涉及一些权限的问题。
下边列举一些较常见的接口,这些接口如下所示。

query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder)//通过Uri进行查询,返回一个Cursor。 
insert(Uri url, ContentValues values)//将一组数据插入到Uri 指定的地方。 
update(Uri uri, ContentValues values, String where, String[] selectionArgs)//更新Uri指定位置的数据。 
delete(Uri url, String where, String[] selectionArgs)//删除指定Uri并且符合一定条件的数据。
2.什么是ContentResolver

外界的程序通过ContentResolver接口可以访问ContentProvider提供的数据,在Activity当中通过getContentResolver()可以得到当前应用的ContentResolver实例。

query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder)//通过Uri进行查询,返回一个Cursor。 
insert(Uri url, ContentValues values)//将一组数据插入到Uri 指定的地方。 
update(Uri uri, ContentValues values, String where, String[] selectionArgs)//更新Uri指定位置的数据。 
delete(Uri url, String where, String[] selectionArgs)//删除指定Uri并且符合一定条件的数据。
3.ContentProvider和ContentResolver中用到的Uri

在ContentProvider和ContentResolver当中用到了Uri的形式通常有两种,一种是指定全部数据,另一种是指定某个ID的数据。
我们看下面的例子。
content://contacts/people/ 这个Uri指定的就是全部的联系人数据。
ontent://contacts/people/1 这个Uri指定的是ID为1的联系人的数据。

在上边两个类中用到的Uri一般由3部分组成。
第一部分是:“content://” 。
第二部分是要获得数据的一个字符串片段。
最后就是ID(如果没有指定ID,那么表示返回全部)。

由于URI通常比较长,而且有时候容易出错,且难以理解。所以,在Android当中定义了一些辅助类,并且定义了一些常量来代替这些长字符串的使用,例如下边的代码:
Contacts.People.CONTENT_URI (联系人的URI)。
1)实现的功能

​ 在这个例子里边,首先在系统的联系人应用当中插入一些联系人信息,然后把这些联系人的名字和电话再显示出来

2)实现方法

package com.contentProvider;  
  
import android.app.ListActivity;  
import android.database.Cursor;  
import android.os.Bundle;  
import android.provider.Contacts.Phones;  
import android.widget.ListAdapter;  
import android.widget.SimpleCursorAdapter;  
  
public class ContentProviderDemo extends ListActivity {  
      
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        //getContentResolver()方法得到应用的ContentResolver实例。   
        // query(Phones.CONTENT_URI, null, null, null, null)。它是ContentResolver里的方法,负责查询所有联系人,并返回一个Cursor。这个方法参数比较多,每个参数的具体含义如下。   
        //·  第一个参数为Uri,在这个例子里边这个Uri是联系人的Uri。   
        //·  第二个参数是一个字符串的数组,数组里边的每一个字符串都是数据表中某一列的名字,它指定返回数据表中那些列的值。   
        //·  第三个参数相当于SQL语句的where部分,描述哪些值是我们需要的。   
        //·  第四个参数是一个字符串数组,它里边的值依次代替在第三个参数中出现的“?”符号。   
        //·  第五个参数指定了排序的方式。   
        Cursor c = getContentResolver().query(Phones.CONTENT_URI, null, null, null, null);  
        startManagingCursor(c); //让系统来管理生成的Cursor。   
        ListAdapter adapter = new SimpleCursorAdapter(  
                this,  
                android.R.layout.simple_list_item_2,   
                c,   
                new String[] { Phones.NAME, Phones.NUMBER },   
                new int[] { android.R.id.text1, android.R.id.text2 });  
        setListAdapter(adapter); //将ListView和SimpleCursorAdapter进行绑定。   
    }  
      
}  
package com.contentProvider;  
  
import android.app.ListActivity;  
import android.database.Cursor;  
import android.os.Bundle;  
import android.provider.Contacts.Phones;  
import android.widget.ListAdapter;  
import android.widget.SimpleCursorAdapter;  
  
public class ContentProviderDemo extends ListActivity {  
      
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        //getContentResolver()方法得到应用的ContentResolver实例。  
        // query(Phones.CONTENT_URI, null, null, null, null)。它是ContentResolver里的方法,负责查询所有联系人,并返回一个Cursor。这个方法参数比较多,每个参数的具体含义如下。  
        //·  第一个参数为Uri,在这个例子里边这个Uri是联系人的Uri。  
        //·  第二个参数是一个字符串的数组,数组里边的每一个字符串都是数据表中某一列的名字,它指定返回数据表中那些列的值。  
        //·  第三个参数相当于SQL语句的where部分,描述哪些值是我们需要的。  
        //·  第四个参数是一个字符串数组,它里边的值依次代替在第三个参数中出现的“?”符号。  
        //·  第五个参数指定了排序的方式。  
        Cursor c = getContentResolver().query(Phones.CONTENT_URI, null, null, null, null);  
        startManagingCursor(c); //让系统来管理生成的Cursor。  
        ListAdapter adapter = new SimpleCursorAdapter(  
                this,  
                android.R.layout.simple_list_item_2,   
                c,   
                new String[] { Phones.NAME, Phones.NUMBER },   
                new int[] { android.R.id.text1, android.R.id.text2 });  
        setListAdapter(adapter); //将ListView和SimpleCursorAdapter进行绑定。  
    }  
      
}  

五. 网络存储方式

1.例子介绍

通过邮政编码查询该地区的天气预报,以POST发送的方式发送请求到webservicex.NET站点,访问WebService.webservicex.Net站点上提供查询天气预报的服务,具体信息请参考其WSDL文档,网址为:http://www.webservicex.net/WeatherForecast.asmx?WSDL。
输入:美国某个城市的邮政编码。
输出:该邮政编码对应城市的天气预报。

2.实现步骤如下
(1)如果需要访问外部网络,则需要在AndroidManifest.xml文件中加入如下代码申请权限许可: 
<!-- Permissions --> 
<uses-permission Android:name="Android.permission.INTERNET" /> 
(2)以HTTP POST的方式发送(注意:SERVER_URL并不是指WSDL的URL,而是服务本身的URL)。实现的代码如下所示:
private static final String SERVER_URL = "http://www.webservicex.net/WeatherForecast. asmx/GetWeatherByZipCode"; //定义需要获取的内容来源地址
HttpPost request = new HttpPost(SERVER_URL); //根据内容来源地址创建一个Http请求
// 添加一个变量 
List <NameValuePair> params = new ArrayList <NameValuePair>(); 
// 设置一个华盛顿区号
params.add(new BasicNameValuePair("ZipCode", "200120"));  //添加必须的参数
request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); //设置参数的编码
try { 
HttpResponse httpResponse = new DefaultHttpClient().execute(request); //发送请求并获取反馈
// 解析返回的内容
if(httpResponse.getStatusLine().getStatusCode() != 404)  
{ 
  String result = EntityUtils.toString(httpResponse.getEntity()); 
  Log.d(LOG_TAG, result); 
} 
} catch (Exception e) { 
Log.e(LOG_TAG, e.getMessage()); 
}

代码解释:
如上代码使用Http从webservicex获取ZipCode为“200120”(美国WASHINGTON D.C)的内容,其返回的内容如下:

<WeatherForecasts xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http: //www.w3.org/2001/XMLSchema-instance" xmlns="http://www.webservicex.net"> 
  <Latitude>38.97571</Latitude> 
  <Longitude>77.02825</Longitude> 
  <AllocationFactor>0.024849</AllocationFactor> 
  <FipsCode>11</FipsCode> 
  <PlaceName>WASHINGTON</PlaceName> 
  <StateCode>DC</StateCode> 
  <Details> 
    <WeatherData> 
      <Day>Saturday, April 25, 2009</Day> 
      <WeatherImage>http://forecast.weather.gov/images/wtf/sct.jpg</WeatherImage> 
      <MaxTemperatureF>88</MaxTemperatureF> 
      <MinTemperatureF>57</MinTemperatureF> 
      <MaxTemperatureC>31</MaxTemperatureC> 
      <MinTemperatureC>14</MinTemperatureC> 
    </WeatherData> 
    <WeatherData> 
      <Day>Sunday, April 26, 2009</Day> 
      <WeatherImage>http://forecast.weather.gov/images/wtf/few.jpg</WeatherImage> 
      <MaxTemperatureF>89</MaxTemperatureF> 
      <MinTemperatureF>60</MinTemperatureF> 
      <MaxTemperatureC>32</MaxTemperatureC> 
      <MinTemperatureC>16</MinTemperatureC> 
    </WeatherData>
…
  </Details> 
</WeatherForecasts>
Android四大组件详解 阅读详情

相关推荐

四大组件相关总结

一.Activity 1.activity生命周期及其各个方法 onCreate()——>onStart()——>onResume()——>onPause()——>onStop()——>onDestory() onStart()与onStop()是是否可见(是否在后台) onResume()与onPause()是是否处于运行状态(Activity位于工作栈栈顶),是否可点击。 2.一个activity正在运行,这时从前台切换到后台,然后在回到前台,这一整个过程的act

龚礼鹏的博客 1662

Android四大组件详解(大白话版)

 1. Activity:负责展示用户界面,就像App的一个个“页面”,用户通过它与应用交互。   2. Service:在后台默默干活的打工人,比如播放音乐或下载文件,没有界面但能长时间运行。   3. BroadcastReceiver:像“收音机”一样接收系统或应用发出的广播消息,比如电量低或网络变化,然后做出响应。   4. ContentProvider:是“数据管家”,管理应用的数据并提供统一接口,让其他应用也能访问这些数据。  

m0_73804764的博客 1万+

别再傻傻分不清了!一文搞懂电机里的‘旋变’和‘编码器’到底有啥区别

本文深度解析电机位置传感器中旋转变压器(旋变)与编码器的核心区别,包括工作原理、精度对比及环境适应性。通过实测数据和典型应用场景,帮助工程师在工业机器人、新能源汽车电机等关键领域做出精准选型决策,提升系统可靠性和控制精度。

weixin_28689507的博客 499

Android四大组件

仅供自己学习使用-转载请注明文中内容出自哪里(我已不知道哪里复制的) 目录 一、活动(Activity) 1.概念 2.生命周期 3.Intent 4.Activity启动模式和任务栈 二、服务(Service) 1.概念 2.生命周期 3.启动方式 三、广播接收者(Broadcast Receive) 1.概念 2.注册方式 四、内容提供者(Content Provider) 1.概念 2.用途 Android 系统的四大组件分别是:活动(activit...

小小怪大人物de博客 4895

别再问“这游戏啥引擎做的”了,手把手教你用SteamDB一键查询(附实战案例)

本文详细介绍了如何使用SteamDB一键查询游戏引擎信息,包括Unity 3D、Unreal Engine等热门引擎的识别方法。通过实战案例和高级查询技巧,帮助玩家快速获取游戏技术底细,优化游戏体验和兼容性分析。

weixin_31412781的博客 815

RACECAR底层平台安装:Jetson Nano+ROS Melodic全栈部署指南

移动机器人开发中,底层平台安装是将硬件转化为可编程移动平台的关键起点。其核心在于嵌入式系统、ROS中间件与传感器驱动的深度协同——需兼顾内核模块加载、GPIO/PWM精确控制、I2C设备初始化及ROS工作空间构建等多层技术耦合。尤其在竞速级小车如RACECAR场景下,Jetson Nano的硬件加速能力、MPU6050 IMU固件加载、TB6612FNG电机驱动配置等细节,直接决定运动控制精度与实时性。本文聚焦Ubuntu 18.04 + ROS Melodic + JetPack 4.4.1技术栈,覆盖从

weixin_32025789的博客 254

Android之四大组件、六大布局、五大存储

一.四大组件:          Android四大组件分别为activity、service、content provider、broadcast receiver。 一、android四大组件详解 1、activity (1)一个Activity通常就是一个单独的屏幕(窗口)。 (2)Activity之间通过Intent进行通信。 (3)android

shenggaofei的博客 15万+

RealSense D435i深度相机实战:从像素坐标到三维空间的精准映射(Python实现)

本文详细介绍了使用RealSense D435i深度相机实现从二维像素坐标到三维空间坐标精准映射的两种Python实战方法:深度图反投影法与点云直接查找法。文章涵盖环境搭建、相机对齐、代码实现、性能对比及与YOLO等检测模型结合的进阶应用,并提供了关键的避坑指南和参数调优建议,帮助开发者在机器人、三维重建等项目中高效应用。

weixin_29291573的博客 382

Android 四大组件、五大存储、六大布局总结

Android 四大组件、五大存储、六大布局: 参考链接:https://www.cnblogs.com/tsingke/p/9007563.html 四大组件: 活动(activity)、 服务(service)、 内容提供者(Content Provider)、 广播接收器(Broadcast Receive)。 活动应用程序是显示层,每一个画面对应于你的应用程序服务,服务应用程序中不可见的工人,而内容是指提供共享的数据储存,用来管理和共享应用程序的数据库,广播接收器是指广播...

低调,谦虚,自律,反思,成长! 1893

AD9914数字斜坡模式使用

类似的,如果DRG输出处于负斜率斜坡中间,DRCTL引脚由逻辑0变为逻辑1,那么DRG会立即切换成正斜率参数,恢复在两个限值之间振荡输出。当两个非驻留位同时设置时,每次DRG输出达到编程设定的上限值或下限值后(假定DRG过输出使能位(0x01[13])已设置),DROVER信号会产生一个正脉冲(两个DDS时钟周期)。不过,在非驻留操作中,DRG输出不一定保持在上下限值。例如,设置数字斜坡非驻留高位,则当达到上限值时,DRG会自动(立即)跳到下限值(这一过程并非以斜坡方式返回下限值,而是直接跳至下限值)。

wangjie36的博客 3862

线性自抗扰控制(LADRC)系统算法框图

NLADRC自抗扰控制从Simulink仿真到PLC控制实现_自抗扰控制器 simulink仿真-优快云博客本文介绍了如何将ADRC自抗扰控制算法从Simulink仿真应用到PLC控制中,包括Simulink框图、TD微分器模型、MATLAB函数的使用、SCL控制代码,以及非线性状态误差反馈控制率的实现。提供了详细的MATLAB仿真步骤和PLC源代码链接。ADRC自抗扰控制算法(含梯形图完整源代码和算法公式)_adrc算法-优快云博客。

RXXW_Dor的博客 1461

Android——四大组件、六大布局、五大存储

一.android四大组件 (一)android四大组件详解 Android四大组件分别为activity、service、content provider、broadcast receiver。 1、activity (1)一个Activity通常就是一个单独的屏幕(窗口)。 (2)Activity之间通过Intent进行通信。 (3)...

全场梦游c的博客 371

【网络安全】AntSword蚁剑新手快速入门(附实战案例)

蚁剑(AntSword)是一款开源的跨平台WebShell管理工具,它主要面向于合法授权的渗透测试安全人员以及进行常规操作的网站管理员。蚁剑的特点主要有如下几点:1.支持多平台。包括macOS、Linux 32位、Linux 64位、Linux armv7l、Linux arm64、Windows 32位、Windows 64位。2.完善的文档。中国蚁剑文档地址。3.多项功能。文件管理功能、虚拟终端功能、数据库管理功能。4.内置代理功能。

等风来 1万+

亿点点概述Android基础必会的四五六【四大组件 五大存储 六大布局】

Android 四大组件 五大存储 六大布局1. Android四大组件1.1 Activity1.1.1 概念1.1.2 生命周期1.1.3 四种启动模式1.1.4 三种跳转方式1.2 Service1.2.1 概念1.2.2 两种启动方式   最近girl friend需要搞Android基础汇报,在不情不愿却又你情我愿的的情况下,一起搞定了她的汇报文档,搞都搞了就想着自己也巩固下基础,做一份总结,希望可以让对Android感兴趣的朋友对Android的基础知识有些了解 1. Android四大组件  

一只立志于养老婆的程序猿 2420

全网最强AI辅助课题申报教程!超详细流程拆解,助你快速提高课题申报成功率(附各部分高效提示词)

实验法要详细说明自变量、因变量、实验类型、实验过程、实验步骤、测量工具名称、被试取样方式、无关变量控制方法。这个部分就是让评审专家相信我们有能力把这个项目干成,写的时候要重点突出两块内容:第一是研究基础,包括你或团队在相关领域已有的研究成果,比如发表的论文、承担过的课题、获得过的奖励、相关研究经验等,要具体、有说服力;课题申报专门给我们留了一小节用来突出课题的创新之处,不管是研究角度、研究对象、研究方法,还是应用价值都可以提炼作为我们的创新点,最后的语气成果也要明确具体,且要和课题内容紧密相关。

智能AI让学术科研更容易 665

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Android的四大组件、六大布局、五大存储方式

四大组件:Android四大组件分别为activity、service、content provider、broadcast receiver。 六大界面布局方式包括: 线性布局(LinearLayout)、框架布局(FrameLayout)、表格布局(TableLayout)、相对布局(RelativeLayout)、绝对布局(AbsoluteLayout)和网格布局(GridLayout) 。...

qq_34376587的博客 585

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

安卓四大组件、六大布局、五大存储

Android四大组件分别为activity、service、contentprovider、broadcast receiver。 一、android四大组件详解 1、activity (1)一个Activity通常就是一个单独的屏幕(窗口)。 (2)Activity之间通过Intent进行通信。 (3)android应用中每一个Activity都必须要在AndroidManifest...

weixin_34232363的博客 122

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Android之四大组件、六大布局、五大存储 总结

Android之四大组件、六大布局、五大存储 一.四大组件:Android四大组件分别为activity、service、content provider、broadcast receiver。 一、android四大组件详解 1、a...

Tsingke 246

Android--四大组件、六大布局、五大存储

 一.四大组件:        Android四大组件分别为activity、service、content provider、broadcast receiver。一、android四大组件详解1、activity(1)一个Activity通常就是一个单独的屏幕(窗口)。(2)Activity之间通过Intent进行通信。(3)android应用中每一个Activity都必须要在AndroidM...

Snail_gogo的博客 488

delphiXE关于Android四大组件五大存储六大布局的AndroidManifest.xml的设置(一)

delphiXE关于Android四大组件五大存储六大布局的AndroidManifest.xml的设置(一) 一、四大组件 1、Activity的设置及含义 编译你的应用项目时,IDE会复制模板文件AndroidManifest.template.xml到平台目录下,生成AndroidManifest.xml文件,并按照你在IDE中的配置信息修改其中的内容: <...

pulledup的博客 1535
上一篇: Asp .Net Core系列:基于MySQL的DBHelper帮助类和SQL Server的DBHelper帮助类
下一篇: 前端系列:正则表达式RegExp详解
Code技术分享
博客等级 码龄7年 3327粉丝 87原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值