学习路线可以参考:android学习路线
使用Android Studio开发
下载链接选择自己电脑系统的对应版本。
参考jdk8环境变量 jdk8图解安装
下载地址选择自己电脑系统的对应版本。安装过程和一般的没有什么两样,直到安装完成。
Android SDK 两种下载方式,按图内箭头指示即可下载。
声明Android程序布局有两种方式:
-1) 使用XML文件描述界面布局;
2) 在Java代码中通过调用方法进行控制。
我们既可以使用任何一种声明界面布局的方式,也可以同时使用两种方式。
使用XML文件声明有以下3个特点:
六大界面布局方式包括: 线性布局(LinearLayout)、框架布局(FrameLayout)、表格布局(TableLayout)、相对布局(RelativeLayout)、绝对布局(AbsoluteLayout)和网格布局(GridLayout) 。
1. LinearLayout线性布局
LinearLayout容器中的组件一个挨一个排列,通过控制android:orientation属性,可控制各组件是横向排列还是纵向排列。
LinearLayout的常用XML属性及相关方法
XML属性 | 相关方法 | 说明 |
---|---|---|
android:gravity | setGravity(int) | 设置布局管理器内组件的对齐方式 |
android:orientation | setOrientation(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添加组件,那么该组件将直接占用一行;
在表格布局中,可以为单元格设置如下三种行为方式:
XML属性 | 相关方法 | 说明 |
---|---|---|
android:collapseColumns | setColumns(int, boolean) | 设置需要被隐藏的列的序号,多个序号间用逗号分隔 |
android:shrinkColumns | setShrinkAllColumns(boolean) | 设置需要被收缩的列的序号 |
android:stretchColumns | setStretchAllColumns(boolean) | 设置允许被拉伸的列的序号 |
3. FrameLayout帧布局
FrameLayout直接继承自ViewGroup组件。帧布局为每个加入其中的组件创建一个空白的区域(称为一帧),每个子组件占据一帧,这些帧会根据gravity属性执行自动对齐。
FrameLayout的常用XM了属性及方法
XML属性 | 相关方法 | 说明 |
---|---|---|
android:foreground | setForeground(Drawable) | 设置该帧布局容器的前景图像 |
android:foregroundGravity | setForeGroundGraity(int) | 定义绘制前景图像的gravity属性 |
4. RelativeLayout相对布局
RelativeLayout的XML属性及相关方法说明
XML属性 | 相关方法 | 说明 |
---|---|---|
android:gravity | setGravity(int) | |
android:ignoreGravity | setIgnoreGravity(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:alignmentMode | setAlignmentMode(int) | 设置该布局管理器采用的对齐模式 |
android:columnCount | setColumnCount(int) | 设置该网格的列数量 |
android:columnOrderPreserved | setColumnOrderPreserved(boolean) | 设置该网格容器是否保留序列号 |
android:roeCount | setRowCount(int) | 设置该网格的行数量 |
android:rowOrderPreserved | setRowOrderPreserved(boolean) | 设置该网格容器是否保留行序号 |
android:useDefaultMargins | setUseDefaultMargins(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 . 另一种减少布局层次的技巧是使用 标签来合并布局;
3 . 重用布局。Android支持在XML中使用 标签, 通过指定android:layout属性来指定要包含的另一个XML布局。
如:
"@+id/id1" android:layout="@layout/mylayout">
"@+id/id2" android:layout="@layout/mylayout">
"@+id/id3" android:layout="@layout/mylayout">
1.TextView( 文本视图 )
2.EditText( 输入框 )
3.Button( 按钮 )&ImageButton( 图像按钮 )
4.ToggleButton( 开关按钮 )&Switch( 开关 )
5.RadioButton( 单选按钮 )
6.CheckBox( 多选框 )
7.Spinner( 下拉列表 )
8.ProgressBar( 进度条 )
9.Dialog( AlertDialog、ProgressDialog、TimePickerDialog、DatePickerDialog )提示对话框、进度对话框、时间选择对话框、日期选择对话框
10.ListView(列表视图)
11.SearchView(搜索框)
12.Notification、Toast(通知、吐司(短时提醒))
13.Menu( OptionMenu/SubMenu、ContextMenu )(菜单【选项菜单、上下文菜单】)
14.ImageSwitcher、TextSwitcher 、 ViewPager( 图像切换器、文本切换器 )
15.ActionBar ( 动作导航条 )
16.ScrollView(滚动视图)
本章取自xxfeng的博客
Adapter概念讲解
Adapter是连接后端数据和前端显示的适配器接口,是数据和UI(View)之间一个重要的纽带。在常见的View(ListView,GridView)等地方都需要用到Adapter。如下图直观的表达了Data、Adapter、View三者的关系:
Android中所以的Adapter一览:
由图可以看到在Android中与Adapter有关的所有接口、类的完整层级图。在我们使用过程中可以根据自己的需求实现接口或者继承类进行一定的扩展。比较常用的有 Base Adapter,Impleader,Adapter,Counteradaptation等。
BaseAdapter是一个抽象类,继承它需要实现较多的方法,所以也就具有较高的灵活性;
ArrayAdapter支持泛型操作,最为简单,只能展示一行字。
SimpleAdapter有最好的扩充性,可以自定义出各种效果。
SimpleCursorAdapter可以适用于简单的纯文字型ListView,它需要Cursor的字段和UI的id对应起来。如需要实现更复杂的UI也可以重写其他方法。可以认为是SimpleAdapter对数据库的简单结合,可以方便地把数据库的内容以列表的形式展示出来。
2.应用案例
1)ArrayAdapter
列表的显示需要三个元素:
a.ListVeiw 用来展示列表的View。
b.适配器 用来把数据映射到ListView上的中介。
c.数据 具体的将被映射的字符串,图片,或者基本组件。
案例一
public class ArrayAdapterActivity extends ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//列表项的数据
String[] strs = {"1","2","3","4","5"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1,strs);
setListAdapter(adapter);
}
}
案例二
public class MyListView extends Activity {
private ListView listView;
//private List<String> data = new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
listView = new ListView(this);
listView.setAdapter(new ArrayAdapter(this, android.R.layout.simple_expandable_list_item_1,getData())) ;
setContentView(listView);
}
private List<String> getData(){
List<String> data = new ArrayList<String>();
data.add("测试数据1");
data.add("测试数据2");
data.add("测试数据3");
data.add("测试数据4");
return data;
}
}
上面代码使用了Adapter(Context context, int resourcefulness, List objects)来装配数据,要装配这些数据就需要一个连接List View视图对象和数组数据的适配器来两者的适配工作,Adapter的构造需要三个参数,依次为this,布局文件(注意这里的布局文件描述的是列表的每一行的布局,android.R.layout.simple_list_item_1是系统定义好的布局文件只显示一行文字,数据源(一个List集合)。同时用adapter()完成适配的最后工作。效果图如下:
2)SimpleAdapter
simpleAdapter的扩展性最好,可以定义各种各样的布局出来,可以放上ImageView(图片),还可以放上Button(按钮),CheckBox(复选框)等等。下面的代码都直接继承了ListActivity,ListActivity和普通的Activity没有太大的差别,不同就是对显示ListView做了许多优化,方面显示而已。
案例一
simple.xml
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
/>
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="20sp"
/>
public class SimpleAdapterActivity extends ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SimpleAdapter adapter = new SimpleAdapter(this, getData(), R.layout.simple, new String[] { "title", "img" }, new int[] { R.id.title, R.id.img });
setListAdapter(adapter);
}
private List
案例二
下面的程序是实现一个带有图片的类表。首先需要定义好一个用来显示每一个列内容的xml,vlist.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5px"/>
<LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content">
<TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textColor="#FFFFFFFF" android:textSize="22px" />
<TextView android:id="@+id/info" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textColor="#FFFFFFFF" android:textSize="13px" />
LinearLayout>
LinearLayout>
public class MyListView3 extends ListActivity {
// private List data = new ArrayList();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SimpleAdapter adapter = new SimpleAdapter(this,getData(),R.layout.vlist,
new String[]{"title","info","img"},
new int[]{R.id.title,R.id.info,R.id.img});
setListAdapter(adapter);
}
private List> getData() {
List> list = new ArrayList>();
Map map = new HashMap();
map.put("title", "G1");
map.put("info", "google 1");
map.put("img", R.drawable.i1);
list.add(map);
map = new HashMap();
map.put("title", "G2");
map.put("info", "google 2");
map.put("img", R.drawable.i2);
list.add(map);
map = new HashMap();
map.put("title", "G3");
map.put("info", "google 3");
map.put("img", R.drawable.i3);
list.add(map);
return list;
}
}
使用Impleader的数据用一般都是Hash Map构成的List,list的每一节对应Listie的每一行。Hash Map的每个键值数据映射到布局文件中对应id的组件上。因为系统没有对应的布局文件可用,我们可以自己定义一个布局alist.XML。下面做适配,new一个Impleader参数一次是:this,布局文件(alist.XML),Hash Map的 title 和 info,IgM。布局文件的组件id,title,info,IgM。布局文件的各组件分别映射到Hash Map的各元素上,完成适配。
运行效果如下图:
3)SimpleCursorAdapter
public class SimpleCursorAdapterActivity extends ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//获得一个指向系统通讯录数据库的Cursor对象获得数据来源
Cursor cur = getContentResolver().query(People.CONTENT_URI, null, null, null, null);
startManagingCursor(cur);
//实例化列表适配器
ListAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cur, new String[] {People.NAME}, new int[] {android.R.id.text1});
setListAdapter(adapter);
}
}
一定要以数据库作为数据源的时候,才能使用SimpleCursorAdapter,这里特别需要注意的一点是:不要忘了在AndroidManifest.xml文件中加入权限
<uses-permission android:name="android.permission.READ_CONTACTS">uses-permission>
4)BaseAdapter
有时候,列表不光会用来做显示用,我们同样可以在在上面添加按钮。添加按钮首先要写一个有按钮的xml文件,然后自然会想到用上面的方法定义一个适配器,然后将数据映射到布局文件上。但是事实并非这样,因为按钮是无法映射的,即使你成功的用布局文件显示出了按钮也无法添加按钮的响应,这时就要研究一下ListView是如何现实的了,而且必须要重写一个类继承BaseAdapter。下面的示例将显示一个按钮和一个图片,两行字如果单击按钮将删除此按钮的所在行。并告诉你ListView究竟是如何工作的。
vlist2.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView android:id="@+id/img" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="5px"/>
<LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content">
<TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textColor="#FFFFFFFF" android:textSize="22px" />
<TextView android:id="@+id/info" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textColor="#FFFFFFFF" android:textSize="13px" />
LinearLayout>
<Button android:id="@+id/view_btn" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/s_view_btn" android:layout_gravity="bottom|right" />
LinearLayout>
/**
002 * @author
003 *
004 */
005 public class MyListView4 extends ListActivity {
006
007
008 private List> mData;
009
010 @Override
011 public void onCreate(Bundle savedInstanceState) {
012 super.onCreate(savedInstanceState);
013 mData = getData();
014 MyAdapter adapter = new MyAdapter(this);
015 setListAdapter(adapter);
016 }
017
018 private List> getData() {
019 List> list = new ArrayList>();
020
021 Map map = new HashMap();
022 map.put("title", "G1");
023 map.put("info", "google 1");
024 map.put("img", R.drawable.i1);
025 list.add(map);
026
027 map = new HashMap();
028 map.put("title", "G2");
029 map.put("info", "google 2");
030 map.put("img", R.drawable.i2);
031 list.add(map);
032
033 map = new HashMap();
034 map.put("title", "G3");
035 map.put("info", "google 3");
036 map.put("img", R.drawable.i3);
037 list.add(map);
038
039 return list;
040 }
041
042 // ListView 中某项被选中后的逻辑
043 @Override
044 protected void onListItemClick(ListView l, View v, int position, long id) {
045
046 Log.v("MyListView4-click", (String)mData.get(position).get("title"));
047 }
048
049 /**
050 * listview中点击按键弹出对话框
051 */
052 public void showInfo(){
053 new AlertDialog.Builder(this)
054 .setTitle("我的listview")
055 .setMessage("介绍...")
056 .setPositiveButton("确定", new DialogInterface.OnClickListener() {
057 @Override
058 public void onClick(DialogInterface dialog, int which) {
059 }
060 })
061 .show();
062
063 }
064 /** 当Listie有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候 就需要按需填充并重新使用view来减少对象的创建
065 *最快的方式是定义一个Pewholder,将convex的tag设置为Pewholder,不为空时重新使用即可
066 */
067 public final class ViewHolder{
068 public ImageView img;
069 public TextView title;
070 public TextView info;
071 public Button viewBtn;
072 }
073
074
075 public class MyAdapter extends BaseAdapter{
076
077 private LayoutInflater mInflater;
078
079
080 public MyAdapter(Context context){
081 this.mInflater = LayoutInflater.from(context);
082 }
083 @Override
084 public int getCount() {
085 // TODO Auto-generated method stub
086 return mData.size();
087 }
088
089 @Override
090 public Object getItem(int arg0) {
091 // TODO Auto-generated method stub
092 return null;
093 }
094
095 @Override
096 public long getItemId(int arg0) {
097 // TODO Auto-generated method stub
098 return 0;
099 }
100
101 @Override
102 public View getView(int position, View convertView, ViewGroup parent) {
103
104 ViewHolder holder = null;
105 if (convertView == null) {
106
107 holder=new ViewHolder();
108
109 convertView = mInflater.inflate(R.layout.vlist2, null);
110 holder.img = (ImageView)convertView.findViewById(R.id.img);
111 holder.title = (TextView)convertView.findViewById(R.id.title);
112 holder.info = (TextView)convertView.findViewById(R.id.info);
113 holder.viewBtn = (Button)convertView.findViewById(R.id.view_btn);
114 convertView.setTag(holder);
115
116 }else {
117
118 holder = (ViewHolder)convertView.getTag();
119 }
120
121
122 holder.img.setBackgroundResource((Integer)mData.get(position).get("img"));
123 holder.title.setText((String)mData.get(position).get("title"));
124 holder.info.setText((String)mData.get(position).get("info"));
125
126 holder.viewBtn.setOnClickListener(new View.OnClickListener() {
127
128 @Override
129 public void onClick(View v) {
130 showInfo();
131 }
132 });
133
134
135 return convertView;
136 }
137
138 }
139 }
下面将对上述代码,做详细的解释,listView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到listView的长度,然后根据这个长度,调用getView()逐一绘制每一行。如果你的getCount()返回值是0的话,列表将不显示同样return 1,就只显示一行。
系统显示列表时,首先实例化一个适配器(这里将实例化自定义的适配器)。当手动完成适配时,必须手动映射数据,这需要重写getView()方法。系统在绘制列表的每一行的时候将调用此方法。getView()有三个参数,position表示将显示的是第几行,covertView是从布局文件中inflate来的布局。我们用LayoutInflater的方法将定义好的vlist2.xml文件提取成View实例用来显示。然后将xml文件中的各个组件实例化(简单的findViewById()方法)。这样便可以将数据对应到各个组件上了。但是按钮为了响应点击事件,需要为它添加点击监听器,这样就能捕获点击事件。至此一个自定义的listView就完成了,现在让我们回过头从新审视这个过程。系统要绘制ListView了,他首先获得要绘制的这个列表的长度,然后开始绘制第一行,怎么绘制呢?调用getView()函数。在这个函数里面首先获得一个View(实际上是一个ViewGroup),然后再实例并设置各个组件,显示之。好了,绘制完这一行了。那再绘制下一行,直到绘完为止。在实际的运行过程中会发现listView的每一行没有焦点了,这是因为Button抢夺了listView的焦点,只要布局文件中将Button设置为没有焦点就OK了。
基于监听的事件处理分工明确,可维护性高,且会优先触发。
内部类形式:Class MyClickListener implements View.OnClickListener{ 实现的方法,即事件处理器}
外部类形式:将事件监听器类定义成一个外部类:public class SendSmsListener implements OnLongClickListener{容易把业务逻辑和显示逻辑耦合,不利于程序的内聚性:p195}
Activity本身作为事件监听器:让Activity本身实现监听器接口,并实现处理方法。做法简洁,Activity本身应该完成界面的初始化工作,同时包含事件处理比较混乱。public
匿名内部类形式:btn.setOnClickListener( new OnClickListener(){ 实现时间的处理方法 });
绑定到标签:在XML未指定标签绑定事件处理方法,android:onClick = “clickHandler”,写一个clickHandler(){ 处理 }方法。
监听事件处理是委托式处理,回调事件处理是实现组件自己特定的方法来处理事件,没有监听事件。
public MyButton extends Button{
public boolean onKeyDown(int KeyCode,KeyEvent event){
super.onKeyDown(KeyCode,event);
Log.v(“返回值”,”true不会向外扩散”);
return true;
}
}
MyButton重写了父类的onKeyDown()方法,不需要绑定监听,自己会处理相应的事件。
回调方法的返回值为true表示能完全处理,不会传播出去。返回false,表示未完全处理,会传播出去。 如果没有完成处理(false),则由监听器–>事件回调–>传播到activity,都会出发该方法处理。
Configuration类专门用于描述手机上配置信息,包括用户特定配置和系统动态配置。
Configuration cfg = getResources().getConfiguration();获取了Configuration对象可以使用该对象提供的属性来获取系统配置。
主线程又称为UI线程,在主线程不进行耗时操作,这是需要用到handler。耗时操作会引发ANR异常。
Handler类主要有两个作用:在新启动的线程中发送消息至MessageQueue ;在主线程中获取Looper分给他的消息,处理消息。
Looper :每个线程只能拥有一个looper ,负责管理MessageQueue,不断从消息队列中取出消息,分给对应的Handler处理。
MessageQueue :消息队列,采取先进先出的方式管理message。
HandlerMessage() :Handler接收和处理的消息对象。
在主线程中,系统已经初始化了一个Looper对象,因此程序直接创建Handler并收发消息即可;而自己启动的子线程,必须自己创建一个Looper对象并启动它:Looper.prepare() 创建对象并保证只有一个Looper对象。
Android不允许在子线程中更改UI组件,需要在子线程中更改界面组件必须用handler实现。
实现异步任务的机制有两种:Handler和AsyncTask。
AsyncTask[Params,Progress,Result]
三种泛型类型分别代表“启动任务执行的输入参数”、“后台任务执行的进度”、“后台计算结果的类型”。在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用java.lang.Void类型代替。
一个异步任务的执行一般包括以下几个步骤:
1.execute(Params… params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
2.onPreExecute(),在execute(Params… params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。
3.doInBackground(Params… params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress… values)来更新进度信息。
4.onProgressUpdate(Progress… values),在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上。
5.onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。
在使用的时候,有几点需要格外注意:
1.异步任务的实例必须在UI线程中创建。
2.execute(Params… params)方法必须在UI线程中调用。
3.不要手动调用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法。
4.不能在doInBackground(Params… params)中更改UI组件的信息。
5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。
(1)一个Activity通常就是一个单独的屏幕(窗口)。
(2)Activity之间通过Intent进行通信。
(3)android应用中每一个Activity都必须要在AndroidManifest.xml配置文件中声明,否则系统将不识别也不执行该Activity。
( 1 )service用于在后台完成用户指定的操作。service分为两种:
(a)started(启动):当应用程序组件(如activity)调用startService()方法启动服务时,服务处于started状态。
(b)bound(绑定):当应用程序组件调用bindService()方法绑定到服务时,服务处于bound状态。
( 2 )startService()与bindService()区别:
(a)started service(启动服务)是由其他组件调用startService()方法启动的,这导致服务的onStartCommand()方法被调用。当服务是started状态时,其生命周期与启动它的组件无关,并且可以在后台无限期运行,即使启动服务的组件已经被销毁。因此,服务需要在完成任务后调用stopSelf()方法停止,或者由其他组件调用stopService()方法停止。
(b)使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
( 3 )开发人员需要在应用程序配置文件中声明全部的service,使用标签。
( 4 )Service通常位于后台运行,它一般不需要与用户交互,因此Service组件没有图形用户界面。Service组件需要继承Service基类。Service组件通常用于为其他组件提供后台服务或监控其他组件的运行状态。
(1)你的应用可以使用它对外部事件进行过滤,只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个activity或serice来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力,例如闪动背灯、震动、播放声音等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。
(2)广播接收者的注册有两种方法,分别是程序动态注册和AndroidManifest文件中进行静态注册。
(3)动态注册广播接收器特点是当用来注册的Activity关掉后,广播也就失效了。静态注册无需担忧广播接收器是否被关闭,只要设备是开启状态,广播接收器也是打开着的。也就是说哪怕app本身未启动,该app订阅的广播在触发时也会对它起作用。
(1)android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。其他应用可以通过ContentResolver类从该内容提供者中获取或存入数据。
(2)只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。它的好处是统一数据访问方式。
(3)ContentProvider实现数据共享。ContentProvider用于保存和获取数据,并使其对所有应用程序可见。这是不同应用程序间共享数据的唯一方式,因为android没有提供所有应用共同访问的公共存储区。
(4)开发人员不会直接使用ContentProvider类的对象,大多数是通过ContentResolver对象实现对ContentProvider的操作。
(5)ContentProvider使用URI来唯一标识其数据集,这里的URI以content://作为前缀,表示该数据由ContentProvider来管理。
(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)。
一.Intent的介绍
Intent的中文意思是“意图,意向”,在Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互。因此,可以将Intent理解为不同组件之间通信的“媒介”专门提供组件互相调用的相关信息。
二.Inten启动组件的方法
Intent可以启动一个Activity,也可以启动一个Service,还可以发起一个广播Broadcasts。具体方法如下:
组件名称 | 方法名称 |
---|---|
Activity | startActivity() |
Service | startService() bindService() |
Broadcasts | sendBroadcasts() sendOrderedBroadcasts() sendStickBroadcasts() |
三.Intent的属性
Intent有以下几个属性:
动作(Action),数据(Data),分类(Category),类型(Type),组件(Compent)以及扩展信(Extra)。其中最常用的是Action属性和Data属性。
1.Intent的Action属性
Action是指Intent要完成的动作,是一个字符串常量。SDK中定义了一些标准的Action常量如下表所示。
Constant | Target component | Action |
---|---|---|
ACTION_CALL | activity | Initiate a phone call. |
ACTION_EDIT | activity | Display data for the user to edit. |
ACTION_MAIN | activity | Start up as the initial activity of a task, with no data input and no returned output. |
ACTION_SYNC | activity | Synchronize data on a server with data on the mobile device. |
ACTION_BATTERY_LOW | broadcast receiver | A warning that the battery is low. |
ACTION_HEADSET_PLUG | broadcast receiver | A headset has been plugged into the device, or unplugged from it. |
ACTION_SCREEN_ON | broadcast receiver | The screen has been turned on. |
ACTION_TIMEZONE_CHANGED | broadcast receiver | The setting for the time zone has changed. |
2.Intent的Data属性
Intent的Data属性是执行动作的URI和MIME类型,不同的Action有不同的Data数据指定。比如:ACTION_EDIT Action应该和要编辑的文档URI Data匹配,ACTION_VIEW应用应该和要显示的URI匹配。
3.Intent的Category属性
Intent中的Category属性是一个执行动作Action的附加信息。比如:CATEGORY_HOME则表示放回到Home界面,ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个。下表是SDK文档中关于Category的信息。
Constant | Meaning |
---|---|
CATEGORY_BROWSABLE | The target activity can be safely invoked by the browser to display data referenced by a link — for example, an image or an e-mail message. |
CATEGORY_GADGET | The activity can be embedded inside of another activity that hosts gadgets. |
CATEGORY_HOME | The activity displays the home screen, the first screen the user sees when the device is turned on or when the HOME key is pressed. |
CATEGORY_LAUNCHER | The activity can be the initial activity of a task and is listed in the top-level application launcher. |
CATEGORY_PREFERENCE | The target activity is a preference panel. |
4.Intent的Type属性
Intent的Type属性显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
5.Intent的Compent属性
Intent的Compent属性指定Intent的的目标组件的类名称。通常 Android会根据Intent 中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。
6.Intent的Extra属性
Intent的Extra属性是添加一些组件的附加信息。比如,如果我们要通过一个Activity来发送一个Email,就可以通过Extra属性来添加subject和body。
本文出自 “IT的点点滴滴” 博客,请务必保留此出处http://liangruijun.blog.51cto.com/3061169/634411
推荐鸿洋_大神的文章:Android Fragment 真正的完全解析(上)( 下 )
在Android中,可供选择的存储方式有SharedPreferences、文件存储、SQLite数据库方式、内容提供器(Content provider)和网络。
一.SharedPreferences方式
Android提供用来存储一些简单的配置信息的一种机制,例如,一些默认欢迎语、登录的用户名和密码等。其以键值对的方式存储,
使得我们可以很方便的读取和存入.
1)程序要实现的功能:
我们在Name文本框中输入wangwu,在Password文本框中输入123456,然后退出这个应用。我们在应用程序列表中找到这个应用,重新启动,可以看到其使用了前面输入的Name和Password
2)实现的代码
布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="SharedPreferences demo"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="name"
>
TextView>
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""
>
EditText>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="password"
>
TextView>
<EditText
android:id="@+id/password"
android:layout_width="match_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();
} //将用户名和密码保存进去
}
SharedPreferences保存到哪里去了?
SharedPreferences是以XML的格式以文件的方式自动保存的,在DDMS中的File Explorer中展开到/data/data/package
name/shared_prefs下,以上面这个为例,可以看到一个叫做SETTING_Infos.xml的文件
注意:Preferences只能在同一个包内使用,不能在不同的包之间使用。
二.文件存储方式
在Android中,其提供了openFileInput 和 openFileOuput 方法读取设备上的文件,下面看个例子代码,具体如下所示:
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)实现代码
所用到的字符文件
<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>
布局代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"
/>
<Button
android:text="@string/button1"
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="match_parent"
>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) + " 条记录");
}
}
四.内容提供器(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实例。
ContentResolver提供的接口和ContentProvider中需要实现的接口对应,主要有以下几个。
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指定的就是全部的联系人数据。
content://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进行绑定。
}
}
五. 网络存储方式
1.例子介绍
通过邮政编码查询该地区的天气预报,以POST发送的方式发送请求到webservicex.NET站点,访问WebService.webservicex.Net站点上提供查询天气预报的服务,具体信息请参考其WSDL文档,网址为:
http://www.webservicex.net/WeatherForecast.asmx?WSDL。
输入:美国某个城市的邮政编码。
输出:该邮政编码对应城市的天气预报。
2.实现步骤如下
(1)如果需要访问外部网络,则需要在AndroidManifest.xml文件中加入如下代码申请权限许可:
<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 params = new ArrayList ();
// 设置一个华盛顿区号
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"'>
38.97571 > '
<Longitude>77.02825Longitude>
<AllocationFactor>0.024849AllocationFactor>
<FipsCode>11FipsCode>
<PlaceName>WASHINGTONPlaceName>
<StateCode>DCStateCode>
<Details>
<WeatherData>
<Day>Saturday, April 25, 2009Day>
<WeatherImage>http://forecast.weather.gov/images/wtf/sct.jpgWeatherImage>
<MaxTemperatureF>88MaxTemperatureF>
<MinTemperatureF>57MinTemperatureF>
<MaxTemperatureC>31MaxTemperatureC>
<MinTemperatureC>14MinTemperatureC>
WeatherData>
<WeatherData>
<Day>Sunday, April 26, 2009Day>
<WeatherImage>http://forecast.weather.gov/images/wtf/few.jpgWeatherImage>
<MaxTemperatureF>89MaxTemperatureF>
<MinTemperatureF>60MinTemperatureF>
<MaxTemperatureC>32MaxTemperatureC>
<MinTemperatureC>16MinTemperatureC>
WeatherData>
…
Details>
WeatherForecasts>
推荐东月之神的文章Android开发学习之路–网络编程之初体验、Android开发学习之路–网络编程之xml、json。
待完善。
友情链接:
郭霖的博客
鸿洋的博客
夏安明的博客
东月之神的博客
shenggaofei的博客