- 浏览: 560240 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
北月与南安:
哥哥不要秀我,答案是11.38,你算出来36.43,要求N个点 ...
平均距离 -
xiao_android_jun:
[color=red][ size=xx-small ...
Android 之 进程的概念介绍 -
明子健:
小伙子,很有前途哦
《将博客搬至CSDN》 -
1140566087:
dugujiujian 写道R.layout.simple_s ...
Android 之 下拉(Spinner) 组件示例 -
dugujiujian:
R.layout.simple_spinner_dropdow ...
Android 之 下拉(Spinner) 组件示例
查询数据库:
两种方式--
第一种方式:类似INSERT UPDATE DELETE,有两种方法使用select 从SQLite数据库检索数据。
使用rawQuery()直接调用select 语句,使用query() 方法构建一个查询。
小贴士:
* onCreate(); 该方法在数据库第一次创建的时候调用,只调用一次;
* onUpgrade(); 该方法在数据库版本更新的时候调用;
* T-SQL: 国际标准机制
DDL:数据定义语言:create drop alter;
DCL: 数据控制语言:grant revoke;
DML: 数据管理语言:insert delete update select ;
* select 列的列表 from 表的列表 where 条件语句 group by 分组属性 having 分组条件 order by 排
序列 asc|desc limit m, n;
* 游标:游标的实质使一种能从包括多条数据记录的结果集种每次提取一条记录的机制;
游标的使用,Cursor的方法:
* close(); 关闭游标 ,释放资源;
* copyStringToBuffer(int columnIndex,CharArrayBuffer buffer); 在缓冲区中检索请求的列
的文本,将其存储;
* getColumnCount(); 返回所有列的行数;
* getColumnIndex(String columnName); 返回指定的列,如果不存在那么返回-1;
* getColumnIndexOrThrow(String columnName);从0开始返回指定列的名称,如果不存在将抛出异常;
* getColumnName(int columnIndex); 从给定的索引返回列名;
* getColumnNames(); 返回一个字符串数组的列名;
* moveToFirst(); 将游标移动到第一条;
* moveToLast(); 将游标移动到最后一条;
* move(int offset); 将游标移动到指定ID;
* moveToNext(); 将游标移动到下一条;
* moveToPrevious(); 将游标移动到上一条;
* getCount(); 得到游标总记录条数;
* isFirst(); 判断当前游标是否为第一条数据;
案例:创建一个数据库,并在数据库第一次创建的时候初始化创建一张表student,添加记录,
然后查询数据库种表的数据,显示出来;
java代码如下:
//案列如下:
实现效果:
仿制手机通讯录,实现编辑,删除的效果;java代码如下:
//数据库辅助类
//自定义布局文件,用于填充到对话框
//列表组件的布局方式
两种方式--
第一种方式:类似INSERT UPDATE DELETE,有两种方法使用select 从SQLite数据库检索数据。
使用rawQuery()直接调用select 语句,使用query() 方法构建一个查询。
小贴士:
* onCreate(); 该方法在数据库第一次创建的时候调用,只调用一次;
* onUpgrade(); 该方法在数据库版本更新的时候调用;
* T-SQL: 国际标准机制
DDL:数据定义语言:create drop alter;
DCL: 数据控制语言:grant revoke;
DML: 数据管理语言:insert delete update select ;
* select 列的列表 from 表的列表 where 条件语句 group by 分组属性 having 分组条件 order by 排
序列 asc|desc limit m, n;
* 游标:游标的实质使一种能从包括多条数据记录的结果集种每次提取一条记录的机制;
游标的使用,Cursor的方法:
* close(); 关闭游标 ,释放资源;
* copyStringToBuffer(int columnIndex,CharArrayBuffer buffer); 在缓冲区中检索请求的列
的文本,将其存储;
* getColumnCount(); 返回所有列的行数;
* getColumnIndex(String columnName); 返回指定的列,如果不存在那么返回-1;
* getColumnIndexOrThrow(String columnName);从0开始返回指定列的名称,如果不存在将抛出异常;
* getColumnName(int columnIndex); 从给定的索引返回列名;
* getColumnNames(); 返回一个字符串数组的列名;
* moveToFirst(); 将游标移动到第一条;
* moveToLast(); 将游标移动到最后一条;
* move(int offset); 将游标移动到指定ID;
* moveToNext(); 将游标移动到下一条;
* moveToPrevious(); 将游标移动到上一条;
* getCount(); 得到游标总记录条数;
* isFirst(); 判断当前游标是否为第一条数据;
案例:创建一个数据库,并在数据库第一次创建的时候初始化创建一张表student,添加记录,
然后查询数据库种表的数据,显示出来;
java代码如下:
/* 查询数据库 *//* 返回一个游标对象 */ public Cursor selectData(){ /* 与数据库获得连接,获得只读属性 */ SQLiteDatabase sqliteDatabase = dbhelper.getReadableDatabase(); /* 使用游标保存得到的结果集 *//* 参1:查询语句 ; 参2:查询条件 */ //Cursor cursor = sqliteDatabase.rawQuery("select * from student", null); /* 使用查询语句:方式二 * @ distinct --是否去除重复行 例:值为:true/false; * @ table --表名 * @ columns --要查询的列 例: new String[] {"id","name","age"} * @ selection --查询条件 例:"id>?" * @ selectionArgs --查询条件的参数 例:new String[]{"3"} * @ groupBy --对查询的结果进行分组 * @ having --对分组的结果进行限制 * @ orderby --对查询的结果进行排序; 例:"age asc" * @ limit --分页查询限制 ; 例:"2,5" 从第2行开始,到第5行结束;注:行数从0 开始; * */ Cursor cursor = sqliteDatabase.query(true,"student", new String[]{"_id","name","age"}, "_id>?", new String[]{"1"}, null, null, "age desc", "1,5"); /* 使用游标---获取游标中的数据 */ while(cursor.moveToNext()){ String id = cursor.getString(cursor.getColumnIndex("_id")); String name = cursor.getString(cursor.getColumnIndex("name")); String age = cursor.getString(cursor.getColumnIndex("age")); Toast.makeText(MainActivity.this, "_id="+id+" name="+name+" age="+age, 1000).show(); } return cursor; }
//案列如下:
实现效果:
仿制手机通讯录,实现编辑,删除的效果;java代码如下:
package com.example.sqliteselection; import android.app.Activity; import android.app.AlertDialog.Builder; import android.content.ContentValues; import android.content.DialogInterface; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.SimpleCursorAdapter; import android.widget.Toast; public class MainActivity extends Activity { private EditText edit_age; private EditText edit_name; private DBHelper dbhelper; private Button selectBtn,insertBtn; private ListView listview ; private Cursor cursorTemp; private String nameTemp; private String ageTemp; public void init(){ selectBtn =(Button) findViewById (R.id.selectBtn); insertBtn = (Button) findViewById(R.id.insertBtn); listview = (ListView) findViewById(R.id.listView); } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); /* 组件对象初始化 */ init(); /* 创建数据库 */ dbhelper = new DBHelper(this, "mydb.db", null, 1); /* 为insertBtn设置店家事件监听器 */ insertBtn.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub insertData(); Toast.makeText(MainActivity.this, "数据添加成 功", 1000).show(); } }); /* 为selectBtn设置点击事件监听器 *//* 动作:显示ListView组件里面的数据项 */ selectBtn.setOnClickListener(new OnClickListener() { public void onClick(View v) { Cursor cursor = selectData(); /* cursorTemp临时保存数据集 */ cursorTemp = cursor; /* 用于填充ListView组件的数据 */ listViewShow(cursor); } }); /* 为ListView编写长按事件 *//* 动作,获得条目对应的信息 */ listview.setOnItemLongClickListener(new OnItemLongClickListener() { public boolean onItemLongClick(AdapterView<?> arg0, View arg1,int id, long positive) { /* 直接移动到 指定 ID 的游标的数据行数 *//* cursorTemp.move(id-1) */ /* 获取用户点击的条目信息 */ nameTemp = cursorTemp.getString(cursorTemp.getColumnIndex("name")); ageTemp = cursorTemp.getString(cursorTemp.getColumnIndex("age")); Toast.makeText(MainActivity.this, "总数:"+cursorTemp.getCount()+" id="+id+" name="+cursorTemp.getString (cursorTemp.getColumnIndex("name")) +" age="+cursorTemp.getString(cursorTemp.getColumnIndex("age")), 1000).show(); return false; } }); /* 为ListView组件注册上下文菜单 */ registerForContextMenu(listview); } /* 查询数据库 *//* 返回一个游标对象 */ public Cursor selectData(){ /* 与数据库获得连接,获得只读属性 */ SQLiteDatabase sqliteDatabase = dbhelper.getReadableDatabase(); /* 使用游标保存得到的结果集 *//* 参1:查询语句 ; 参2:查询条件 */ //Cursor cursor = sqliteDatabase.rawQuery("select * from student", null); /* 使用查询语 句:方式二 * @ distinct --是否去除重复行 例:值为: true/false; * @ table --表名 * @ columns --要查询的列 例: new String[]{"id","name","age"} * @ selection --查询条件 例:"id>?" * @ selectionArgs --查询 条件的参数 例:new String[]{"3"} * @ groupBy --对查询的结果 进行分组 * @ having --对分组的结果进行限制 * @ orderby --对查询的结果进行排序; 例:"age asc" * @ limit --分页查询限制 ; 例:"2,5" 从第2行开始,到第5行结束;注:行数从0 开始; * */ Cursor cursor = sqliteDatabase.query(true,"student", new String[]{"_id","name","age"}, "_id>?", new String[]{"1"}, null, null, "age desc", "1,5"); /* 使用游标---获取游标中的数据 */ while(cursor.moveToNext()){ String id = cursor.getString(cursor.getColumnIndex ("_id")); String name = cursor.getString(cursor.getColumnIndex("name")); String age = cursor.getString(cursor.getColumnIndex("age")); //Toast.makeText (MainActivity.this, "_id="+id+" name="+name+" age="+age, 1000).show(); } return cursor; } /* 向数据哭中添加数据 */ public void insertData(){ /* 与数据库获得连接,并能对数据 库进行读写 */ SQLiteDatabase sqliteDatabase = dbhelper.getWritableDatabase(); /* 插入数据: 方式 一 */ sqliteDatabase.execSQL("insert into student(name,age) values('mark',18)"); sqliteDatabase.execSQL("insert into student(name,age) values('red',24)"); sqliteDatabase.execSQL("insert into student(name,age) values('blank',30)"); sqliteDatabase.execSQL("insert into student(name,age) values('log',22)"); sqliteDatabase.execSQL("insert into student(name,age) values('mark',18)"); sqliteDatabase.execSQL("insert into student(name,age) values(?,?)", new Object[]{"mary",20}); /* 插 入数据:方式二 */ ContentValues cv = new ContentValues(); cv.put("name", "jack"); cv.put("age", 15); sqliteDatabase.insert("student", null, cv); /* 清空数据 */ cv.clear(); } /* ListView 用于显示查到的数据信息 *//* 使用MVC操控 */ public void listViewShow (Cursor cursor){ /* V 已经确定,为ListView组件 */ /* M 层,传递过来的Cursor对象 */ /* C 层 ,使用SimpleCursorAdapter适配器进行数据绑定; *//* 条目布局文件自定义 */ SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.listviewlayout, cursor, new String[] {"name","age"}, new int[]{R.id.name,R.id.age}); /* 关联C和V */ listview.setAdapter(adapter); } /*------------------------------------------------上下文菜 单------------------------------------------------------*/ /*------------------------------------------------------------------------------------------------------------ ----*/ /* 创建上下文菜单 */ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); menu.setHeaderTitle("注册在列表上的上下文"); menu.setHeaderIcon(getResources().getDrawable (R.drawable.icon)); menu.add(1, 0, 1, "编辑"); menu.add(1, 1, 2, "删除"); menu.add(1, 2, 3, "保存"); menu.add(1, 3, 4, "提取"); } /* 上下文菜单事件 */ public boolean onContextItemSelected(MenuItem item) { int id = item.getItemId(); /* 点击不同的 条目对应不同的处理动作 */ switch(id){ case 0: Toast.makeText (MainActivity.this, "点击条目:"+item.toString(), 1000).show(); editAge(); break; case 1: /* 点击了删除 ,要删除对应的条目*/ deleteData (nameTemp, ageTemp); Toast.makeText(MainActivity.this, "点击条目:"+item.toString(), 1000).show(); break; case 2: Toast.makeText(MainActivity.this, "点 击条目:"+item.toString(), 1000).show(); break; case 3: Toast.makeText(MainActivity.this, "点击条目:"+item.toString(), 1000).show(); break; } return super.onContextItemSelected(item); } /*------------------------------------------------------------------------------------------------------------ ----*/ /*------------------------------------------------------------------------------------------------------------ ----*/ /* 上下文菜单之编辑:修改年龄 *//* 返回修改之后的值 */ public void editAge(){ /* 使用编辑对 话框 *//* new 一个Builder对象 */ Builder builder = new Builder(this); builder.setTitle(nameTemp); builder.setIcon(getResources().getDrawable(R.drawable.icon)); /* 通过getLayoutInflater().inflate(R.layout.edit_builder_layout, null)方法获取组件对象 */ LinearLayout linearlayout = (LinearLayout) getLayoutInflater().inflate(R.layout.edit_builder_layout, null); /* 获得EditText 对象 */ edit_age= (EditText) linearlayout.findViewById(R.id.eidt_age); edit_name = (EditText) linearlayout.findViewById(R.id.eidt_name); /* 将原始的数据信息显示在编辑 框内 */ edit_age.setText(ageTemp); edit_name.setText(nameTemp); /* 将组件设置 在对话框中 */ builder.setView(linearlayout); builder.setMessage(" input new age:"); /* 设置确定按钮 *//* 点击该按钮执行动作:获取编辑框的值,并更新数据库中的值 */ builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick (DialogInterface dialog, int which) { String newAge = edit_age.getText().toString(); String newName = edit_name.getText().toString(); updateData(newName, newAge); } }); builder.create().show(); } /* 更新数据信息 *//* 对数据库进行操作 */ public void updateData(String newName,String newAge){ /* 连接数据库 */ SQLiteDatabase sqliteDatabase = dbhelper.getWritableDatabase(); /* 删除 */ ContentValues cv = new ContentValues(); cv.put("name", newName); cv.put("age", newAge); sqliteDatabase.update("student", cv, "name=? and age=?",new String[] {nameTemp,ageTemp}); /* 获取游标 */ Cursor cursor = selectData(); cursorTemp = cursor; /* 为组件写值 */ listViewShow(cursor); } /* 删除数据信息 *//* 对数据库 进行操作 */ public void deleteData(String name,String age){ /* 连接数据库 */ SQLiteDatabase sqliteDatabase = dbhelper.getWritableDatabase(); /* 删除 */ sqliteDatabase.delete("student", "name=? and age=?", new String[]{name,age}); /* 获取游标 */ Cursor cursor = selectData(); cursorTemp = cursor; /* 为组件写值 */ listViewShow(cursor); } }
//数据库辅助类
package com.example.sqliteselection; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; public class DBHelper extends SQLiteOpenHelper { /* 构造方法 */ public DBHelper(Context context, String name, CursorFactory factory,int version) { super(context, name, factory, version); } /* 第一次创建数据库的 时候调用 , 可进行初始化*/ public void onCreate(SQLiteDatabase db) { System.out.println("onCreate().....第一次创建数据库的时候调用;创建表student"); /* 创建表 _id 的情况比较特殊,游标数据中需要用到;*/ db.execSQL("create table student(_id Integer primary key autoincrement,name text,age Integer)"); } /* 数据库版本更新的时候调用 */ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { System.out.println("onUpgrade()....数据库版本更新的时候调用;"); /* 删除表 */ db.execSQL("drop table student"); } }
//自定义布局文件,用于填充到对话框
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/linearlayout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > <EditText android:id="@+id/eidt_name" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <EditText android:id="@+id/eidt_age" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
//列表组件的布局方式
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#F5F5DC" android:orientation="horizontal" > <TextView android:id="@+id/name" android:layout_width="60dp" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:text="" android:textSize="20sp" /> <TextView android:id="@+id/age" android:layout_width="150dp" android:layout_height="wrap_content" android:layout_marginLeft="15dp" android:text="" android:textSize="15sp" /> </LinearLayout>
发表评论
-
Android 之 网络访问服务器,解析JSON数据
2014-03-28 22:50 3421提示:在访问网络,或者服务器的数据一定要注意 网络权限的声明: ... -
Android 之 AsyncTask 异步任务
2014-03-20 08:44 3525Android ... -
Android 之 Looper Handler Message 之间的关系
2014-03-19 10:16 3671Android 的消息 ... -
Android 之 多线程与Socket联合使用案例
2014-03-19 10:15 2683多线 ... -
Android 之 多线程和Socket套接字的使用介绍
2014-03-19 10:15 4889And ... -
Android 之 实现Runnable 接口与继承Thread的区别
2014-03-19 10:15 2203实现Runnable 接口 相 ... -
Android 之 GSON解析JSON数据
2014-03-19 10:14 4499... -
Android 之 使用Pull 解析xml文件
2014-03-18 21:04 1052/** * 使用Pull进行 xml 文件的解析 ... -
Android 之 使用DOM解析xml文件
2014-03-18 21:02 2749DOM 解析 xml 格式的文件 1、 xml简介:xml ... -
Android 之 百度API 密钥安全码生成
2014-03-04 22:29 2419近期要做个关于旅游助手的应用,开始接触百度API了。大神们 ... -
Android 之 EditText属性用法介绍
2014-01-06 23:49 3996EditText的属性 EditText继承关系:View-- ... -
Android 之 自定义适配器
2014-01-08 10:40 1787自定义适配器 1、实现 * 自定义适配器要继承 BaseA ... -
Android 之 自定义控件用法介绍
2014-01-08 10:40 1721自定义效果:实现:图片和文字混合 首先创建需要组合的子布局: ... -
Android 之 资源自适应与国际化
2014-01-08 10:40 3087<!-- 国际化和资源自适应 ... -
Android 之 Parcelable 序列化
2014-01-08 10:41 2702/* 序列化 * * 作 ... -
Android 之 五大布局案例
2014-01-08 10:41 21361、LinearLayout 线性布局例子: <Lin ... -
Android 之 通知Notification
2014-03-03 22:30 3904Notification 和 NotificationMana ... -
Android 之 手机全屏显示
2014-03-03 22:30 2351/* 1、全屏状态的显示 介绍:Android 中提供了Wi ... -
Android 之 拦截手机短信并自动转发
2014-03-03 22:29 5436拦截短信和发送短信都需要相关的权限: <?xml ve ... -
Android 之 将RAW资源文件写入SD卡工具类
2014-03-01 10:09 3622package com.sun.coptfiletosd; ...
相关推荐
这个“android demo,数据库操作的应用案例”很可能包含了一个完整的示例项目,展示了如何在Android应用中有效地使用SQLite数据库。SQLite是Android内置的关系型数据库系统,轻量级且易于使用,适合大部分移动应用的...
本篇将围绕“安卓SQLite数据库相关-移动查询系统-百纳铁路小助手”这一主题,详细介绍如何在Android应用中使用SQLite数据库。 首先,SQLite数据库在Android中的应用通常涉及以下几个关键组件: 1. **...
在Android开发中,SQLite数据库是应用内存储数据的主要方式,尤其对于小型数据集,它提供了高效、轻量级的解决方案。本课程将深入探讨如何在Android应用中使用SQLite进行数据查询,以“查询‘我身边的榜样’表所有的...
在Android中,SQLite数据库通常通过SQLiteOpenHelper类来管理和操作。SQLiteOpenHelper是一个抽象类,它提供了创建、升级和打开数据库的基本方法。开发者需要继承SQLiteOpenHelper并重写其中的关键方法,以便根据...
本项目“安卓数据库SQLite练习案例”是为初学者设计的一个实践教程,通过Android Studio实现,帮助开发者了解如何在安卓应用中有效地使用SQLite数据库。 首先,我们需要理解SQLite数据库的基本概念。SQLite提供了一...
通过这个"android中用SQLite对学生表进行增删改查"的项目,你可以学习到如何在Android环境中有效地管理SQLite数据库,从而实现数据的持久化存储。对于初学者来说,这是一个非常实用且基础的学习材料,有助于理解和...
【基于Android的日记本】是一款专为Android系统设计的简易日记应用,它利用SQLite数据库技术,为用户提供方便快捷的日记...对于想要学习Android应用开发,尤其是SQLite数据库使用的人来说,这是一个很好的实践案例。
Android系统支持SQLite数据库,一个轻量级的关系型数据库,适合移动设备上的本地数据存储。本文将深入探讨如何在Android中进行数据库操作,包括创建数据库、创建表、插入数据、查询数据、更新数据以及删除数据等核心...
Android系统内置了SQLite数据库,它是一个轻量级的关系型数据库,适用于存储应用程序中的结构化数据。SQLite支持SQL语法,可以进行数据查询、更新、插入和删除操作。在Android中,我们通过SQLiteOpenHelper类来创建...
"Mars Android 数据库开发代码"是一个关于如何在Android环境中使用SQLite数据库进行高效开发的实践案例集。SQLite是一个轻量级的嵌入式数据库,适用于移动设备,如Android手机和平板电脑。 在Android中,SQLite...
通过“数据库增删查改.rar”的学习,开发者可以熟练掌握在Android Studio中如何使用SQLite数据库进行数据管理,从而提升应用的本地数据处理能力。这个压缩包可能包含了相关的示例代码、教程文档或者数据库操作的实践...
首先,Android系统支持SQLite数据库,这是一个轻量级、嵌入式的数据库,特别适合移动设备使用。SQLite数据库在Android中的应用通常涉及到以下几个关键概念: 1. **SQLiteOpenHelper**:这是Android提供的一个基础类...
本书将深入讲解SQLite数据库的创建、操作、查询,包括SQL语句的编写、游标的使用以及ContentProvider的集成,以实现数据的持久化。同时,会讨论如何使用ORM(对象关系映射)框架,如ActiveAndroid或Room,简化数据库...
本项目通过构建一个简洁的Android通讯录应用程序,展示了如何使用SQLite数据库进行数据的存储与管理,以及如何实现联系人的增删改查等功能。这对于初学者来说是一个很好的实践案例,可以帮助他们理解和掌握Android...
在Android系统中,获取手机通讯录是常见的功能需求,它涉及到Android权限管理、ContentProvider、Cursor对象以及SQLite数据库等核心知识点。本实战应用不仅涵盖了如何读取存储在手机内部存储器上的联系人,还涉及了...
4. 数据库操作:学习SQLite数据库的创建、插入、查询、更新和删除操作,以及如何在应用中使用游标(Cursor)来处理查询结果。 5. 网络请求:了解如何使用HttpURLConnection、OkHttp或Retrofit等库进行网络请求,以及...
它允许不同的应用程序之间通过标准的接口进行数据交互,比如SQLite数据库中的数据。以下是对`Android中自定义ContentProvider实例`的详细解析: 首先,我们看到一个名为`MainActivity`的类,它是`Activity`的子类,...