安卓速通(其实是期末复习~)(第四章+第五章)
ZealSinger 发布于 阅读:128 期末复习
⭐️
定义
Android的四大组件分别是Activity ; Service ; ContentProvider ; BroadcastReceiver,四大组件中在考试范围来讲,主要考试的就是Activity,其Activity是负责和用户交互的组件
个人感觉可能会考四大组件有哪些,每个组件的作用感觉不会怎么考(因为书上说的也说的少),感觉可以记一下有哪些组件
拓展:
其余三大组件的作用
(1)Service-服务-在后台执行长时间的运行操作,不依赖于用户界面
例如:音乐软件,放到后台一样的可以播放;游戏更新后台下载
特点:默认在主线程上执行,一般需要创建子线程处理耗时操作,通过startService()启动服务,bindService()绑定服务与组件交互
(2)ContentProvider-内容提供者-实现应用间数据的共享
例如:通讯录,短信等系统提供信息给别的应用
特点:通过contentResolver实现数据的增删改查;可以设置访问权限保证安全
(3)BroadcastReceiver-广播接收器-监听响应系统或者应用发起的全局广播事件
例如:开机完成 ; 电量低 ;网络变化
特点:可以静态注册也可以动态注册
Activity的生命周期⭐️
Activity的生命周期是指从Activity的创建到销毁的全过程,当我们在使用,,浏览,退出,返回应用程序的时候,应用程序中的Activity实例都会在不同的生命周期状态之间进行转换,存在启动状态 ; 运行状态 ;暂停状态 ;停滞状态;销毁状态五个状态
-
启动状态:启动状态一般维持时间会很短,Activity启动之后便会进入到启动状态
-
运行状态:Activity在此状态时,会处于界面的最前端,可见+具备焦点,并且可以和用户交互(点击按钮 输入文本等),当Activity进入运行状态后,就会尽量去维持当前Activity的运行状态,如果内存不允许的话,就会销毁栈底的Activity来确保当前Activity的运行(从这里也可以知道Activity的管理是依靠栈的结构进行维护的)
-
暂停状态:某些情况下Activity依然是可见但是无法获取焦点,无法对用户的操作做出响应(例如多窗口下,同一时刻只能存在一个窗口获得焦点,其实其余的窗口属于暂停状态)
-
停止状态:Activity完全不可用的时候就处于停止状态。当系统内存不足,停止状态的Activity有很大概率会被销毁
-
销毁状态:当Activity处于销毁状态得时候,就会被清楚内存,和启动状态一样,属于一种中间过渡状态,不会过长时间的停留
当Activity在生命周期的各个状态之间进行转化的时候,对应的提供了六个核心回调集,当Activity进行进入新状态的时候就会触发对应的回调方法
-
onCreate()方法
在系统首次创建Activity的时候进行调用,通常做一些初始化的工作,(书上没写,但是安卓官方文档中有写到这个回调函数是每个Activity必须实现的),在Activity整个生命周期中内仅仅只会发生一次,onCreate()方法执行完毕之后就会进入Started状态,进入后一般就是执行onStart()方法和onResume()方法
其实可以在我们的Android新键项目的默认代码中就可以看到,在默认启动主类MainActivity中就重写了onCreate()方法
-
onStart()方法
当Activity进入“已启动”状态的时候,一般在Acitivy即将可见的时候就会调用onStart()方法,正常启动的流程下,此方法回调完成之后就会进入到已恢复状态,之后会进行onResume()方法
-
onResume()方法
Activity获取到焦点的时候/activity进入到已恢复状态就会进入到前台,就会触发这个onResume()方法,应用会尽量一直保持这种状态,直到Activity无法获取焦点
-
onPause()方法
当前Activity被其他Activity覆盖或者屏幕锁屏等中断事件触发,但不代表一定会被销毁,就会调用onPause()方法 ; 如果此时当前Activity又回到了前台就会触发onResume()方法
-
onStop()方法
当Actitivy对于用户不可见的时候都会触发onStop方法,一般会在onStop方法内进行一些CPU密集行操作,例如持久化
-
onRestart()方法
当Activity从暂停状态再到启动状态,就会第哦啊用onRestart方法,进入启动状态后自然后续也会接着进行onStart方法和onResume方法
-
onDestroy()
销毁方法,在正式销毁前都会调用onDestroy()方法,一般用于释放资源,触发onDestory()方法一般是因为用户关闭activity 系统暂时销毁acticity更改(例如设备旋转,进入多窗口模式)
案例代码
class MainActivity : ComponentActivity() {
private val TAG = "MainActivityLifecycle"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate called")
enableEdgeToEdge()
setContent {
KtAndroisTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart called")
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume called")
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause called")
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop called")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy called")
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Column(modifier = modifier) {
// 新增 XML 布局
AndroidView(
factory = { context ->
// 加载 XML 布局
val view = View.inflate(context, R.layout.relativelayouttext, null)
val activity = context as MainActivity
// createRelativeLayout(context)
view
},
modifier = Modifier.padding(20.dp)
)
}
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
KtAndroisTheme {
Greeting("Android")
}
}
从日志中和操作视频上可以看到,首先是onCreated方法 然后Start方法,之后就是Resume方法,执行玩resume方法后整个Activity就是在运行状态了,当我们退出之后回到主界面,依次触发Pause方法和stop方法,我们再次返回应用程序,又是start方法和resume方法,最后将activi从后台移除之后才是destory方法
横竖屏切换的时候的生命周期变化(留心小知识)
当横竖屏幕切换的时候,软件默认是会随着手机的变化而变化的,在变化的时候,如果对应的Activity的配置项android:configChanges没有设置,那么每次横竖屏切换,其实底层就是调用onDestory()方法然后依次执行onCreate , onStart , onResume方法创建一个新的Activity 这样子的好处是默认配置不需要任何修改 , 缺点是因为是重新创建了一个Activity,在原本Activity中做的一些交互无法被保存需要重新进行
如下就是没有设置任何属性配置的时候的样子
反之,如果android:configChanges属性被设置为了对应的属性(android:configChanges="orientation|keyboardHidden"),横竖切换的时候就不会进行如上的过程,程序自适应的调整而不会触发生命周期的任何回调过程。
前后对比的操作视屏(注意有bgm 中间有一小部分属性填充错误了 所以重试了一下)
当然,而也可以通过设置android:screenOrientation="portrait" 锁定应用竖屏或者android:screenOrientation="landscape"缩影横屏
Activity的创建,配置,启动和关闭⭐️
这一部分很需要代码支持,纯粹的背诵就是背API了
创建和配置
创建就是纯电脑操作就行,可以直接创建Activiy,甚至还帮我们配备了常用的Activity模板
我们这里选择LoginActivity,他会对应的帮我们创建好一个普通的登录逻辑所需要的View视图对象,整个Login登录揭密胺的layout布局,以及创建对应的LoginActivity,全自动化很舒服
这里如果硬要说要考试的话,感觉应该是如下几个点
-
每个创建的Activity实际上就是自定义一个类继承自AppCompatActivity
-
所有的Activity需要在主清单配置文件AndroidManifest.xml文件中通过<activity>标签进行对应的配置记录,否则会报错“无法找到xxxActivty类”
启动,切换和关闭
启动和切换一块讲
我们可以拿上面那个checkBox的代码,现在有一个需求,点击篮球之后需要跳转到上面新键的这个LoginActivity登录页面,这个里面其实就设置到了checkBox的点击监听和Activity的启动和切换了
首先是Activity的启动,我们知道activity的生命周期的开始其实就是onCreate方法,在Android中,我们可以通过startActicity(Intent intent)方法求启动一个Activity
public void startActivity(Intent intent)
Intent
这里的Intent对象,是一个Activti的桥梁对象,表示一种意图,为何这么说,因为你启动了一个Activiv其实就是想要运行和交互他,因为同一时间只有一个Activity能获得焦点,所以必定会出现Activity之间的焦点争夺问题,我们创建一个Activity的时候就是其实就是想从当前的Activity跳转到了一个Actvivity中,这个就是所谓的意图,所以Intent的构造函数也就是如下
// 创建一个从A-Activity到B-Activity的意图对象
Intent intent = new Intent(Activity-A,Activity-B)
可以立即为,当你点击“开始游戏”其实就是想匹配开一把游戏,此时就是有一个意图:从正常的游戏首页面到匹配界面,跳转到匹配界面也就是
startActivity( 跳转到匹配界面的意图 ) = startActivity(new Intent(当前界面到匹配界面))
所以对应的,我们就可以完成上述需求
// 这里是直接在checkBox那个代码的handler方法进行修改的 其余的地方和checkBox中一样。LoginActivity是直接使用的系统创建的自带的模板,不需要单独写代码和修改
private fun handler(buttonView: View,isChecked: Boolean){
var checkBox = buttonView as CheckBox
var boxContent = checkBox.text.toString()
var hobbyText = this.findViewById<TextView>(R.id.hobbyText)
if(isChecked){ // 为true则说明被选中 加入到likeList中
likeList.add(boxContent)
hobbyText.setText("你选择的是:${likeList}")
Log.d(TAG,"准备跳转")
val intent = Intent(this,LoginActivity::class.java)
startActivity(intent)
}else{
likeList.remove(boxContent)
hobbyText.setText("你选择的是:${likeList}")
}
}
点击“篮球”选项之后,就可以发现Activity进行了切换
而关闭Activity就需要在对应的Activity中调用自己的finish()方法即可
这个是属于显示Intent,除此之外还有隐式Intent
IntentFile
隐式Intent不需要明确指明需要激活的目标组件,只需要对应的编写<IntentFile>标签并且针对action属性,data属性,category属性进行匹配,当三个属性全部匹配完毕,就可以进行唤起对应的目标组件
Activity之间的数据传输
假设我们在MainActivity中传数据给SecondActivity:
Activity之间可以借助Intent传输数据,主要利用putExtra(key,value)方法
val intent = Intent(this,LoginActivity::class.java)
intent.putExtra("name","zealsinger")
intent.putExtra("age",21)
intent.putExtra("isPeople",true)
而在被接收方,主要通过getIntExtra()/getStringExtra()/getBooleanExtra()通过key获取
val intent = intent
var name = intent.getStringExtra("name")
// 第二个参数表示当没有这个数值的时候设置的默认值
var age = intent.getIntExtra("age", 0)
var isPeople = intent.getBooleanExtra("isPeople", true)
当然也可以批量发送和获取,将有关的数据放入到一起进行传输。利用Bundle对象,Bundle对象类似于Map
// 实例化一个Bundle
Bundle bundle = new Bundle();
Intent intent=new Intent(MainActivity.this,Main2Activity.class);
//设置数据
String name="admin";String num="123";
//把数据保存到Bundle里
bundle.putString("name", name);
bundle.putString("num",num);
//把bundle放入intent里
intent.putExtra("Message",bundle);
startActivity(intent);
//获取数据
Intent intent = getIntent();
//从intent取出bundle
Bundle bundle = intent.getBundleExtra("Message");
//获取数据
String name = bundle.getString("name");
String num = bundle.getString("num");
//显示数据
text_show.setText(name + "\n" + num);
如果需要回传,即secondActivity传数据给MainActivity:
回传主要用如下三个方法
// 开启一个Activity且当创建的Activity销毁的时候就会接收其返回值
// 第二个参数代表一个请求COde 用于区分不同的子Activity
startActivityForResult(Intent intent , int requestCode)
// 子Activity中设置要返回的内容 返回的内容也可以让intent携带即可
setResult(int resultCode,Intent intent)
// 接收回传数据
onActivityResult(int requestCode,int resultCode,Intent data)
该方法需要重写 参考逻辑
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE) {
if (resultCode == RESULT_OK && data != null) {
String receivedData = data.getStringExtra("dataFromReceive");
// 处理回传的数据
System.out.println(receivedData);
}
}
}
任务栈与启动模式⭐️
Android任务栈其实也就是Task,也就是一个栈结构,先进后出的容器,用于管理Activity组件
如下,每次创建一个Activity都会往栈顶放入,类似于方法进入栈帧,先进后出
在我们实际的使用和开发中,会需要在多个Activity之间反复横跳,如上,我在Activity3的时候有需要跳到Actvity1,那么此时我应该再次创建一个Activity1还是让原来的Activity1放到栈顶上?对于不同操作我们就需要用启动模式进行标识
Android中存在四种启动模式
-
standard:Acitvity的默认模式,每次启动一个Acitivity都是在栈顶创建一个新的Activity
我们可以发现,这个过程中,在standard模式下启动了三次MainActivity后,都生成了不同的新实例,并添加到同一个任务栈中。这个时候Activity的onCreate、onStart、onResume方法都会被调用
-
singleTop:又称之为栈顶复用模式,会判断要启动的Acitivy是否处于栈顶,如果是的则不会创建新的实例,反之则会创建新的实例,相比较之下比standard更合理
-
singleTask:也称之为栈内复用模式。也是一种单例模式的体现,singTop是检测栈顶元素是否有需要启动的Activity,而singTask则是检测整个栈中是否存在当前需要启动的Activity,如果存在就直接将该Activity置于栈顶,并将该Activity以上的Activity都从任务栈中移出销毁,同时也会回调onNewIntent方法
-
singleInstance模式:在singleInstance模式下,该Activity在整个android系统内存中有且只有一个实例,而且该实例单独尊享一个Task。换句话说,A应用需要启动的MainActivity 是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A单独在这个新的任务栈中,如果此时B应用也要激活MainActivity,由于栈内复用的特性,则不会重新创建,而是两个应用共享一个Activity的实例
Fragment
Fragment(碎片) 是一种可以嵌入到Acitivity中的UI片段,用于描述Acitivty中的部分布局,主要是因为如果Activity中布局控件太多了一个Activity管理起来就很麻烦,通过Fragment进行模块化的管理更加高效
Fragment不能独立存在,必须嵌入到Activity中,一个Activity中可以有多个Fragment且Fragment的生命周期和Activity强绑定
Fragment的生命周期
Fragement的生命周期和Acitivty的生命周期是一样的,也是五个状态:启动状态;运行状态;暂停状态;停滞状态;销毁状态
Fragment的生命周期和Acitvity的生命周期相关,具体联系如下:
-
因为Fragment是Actvity中的一部分,所以Fragment至少需要等待Activity的创建才会启动整个生命,所以当Activity创建Fragment的时候,Fragment进入启动阶段
-
当Activity对内部的Fragment进行操作的时候,如果进行添加操作,Fragment处于启动状态 ; 反之如果进行删除则进入销毁状态
-
当Activity进入暂停状态,内部所有的Fragment进入暂停状态
-
当Activity进入销毁状态,内部素有的Fragment也会进入销毁状态
同样,每个Fragment的状态的切换都对应的存在回调方法/钩子函数,Fragment的相关方法如下
onAttach():用于Fragment和Acitivity建立关联
onCreateView():Fragment创建视图(加载布局的时候)调用
onActivityCreated():Fragment关联的Activity已经完成创建的时候调用
onDestoryView():Fragment的视图被移除删除的时候调用
onDetach():Fragment和Activity解除关联的时候调用
Fragment生命周期和钩子方法和视图生命周期之间的对应关系
可能的考点:Frgament和Activity的区别
Fragment的创建和使用(偏向代码性质,先略过,理论考点应该很少)
数据存储⭐️
Android中数据存储的方式有五种,分别为文件存储 ; SharedPreferences存储 ;SQLite数据库存储 ; ContentProvider ; 网络存储 本节内容主要针对前三种存储
文件存储
文件存储主要就是利用本地文件进行存储,存入即写入文件,读取即从文件读取,其实就是I/O流的相关知识,因为Android的主要开发语言就是Java/Kotlin,所以本质上就是对Java/Kotlin中的IO文件相关知识的运用
对于文件存储,分为了内部存储和外部存储
内部存储
内部存储就是写入到应用程序下的data/data/<packagename>目录下,这个目录是应用程序专有的,其他程序如果需要访问需要权限申请,并且如果该应用程序被删除对应文件中的内容也会被删除
内部存储主要运用的就是Context提供的openFileInput() 和 openFileOutput()
FileOutputStream fos = openFileOutput(String name,int mode)
FileInputStream fis = openFileInput(String name)
-
FileOutputStream是输出流,将内容写出程序到别的文件中
第一个参数为文件名name ; 第二个参数为写入模式mode,有四种模式
MODE_PRIVATE---该文件只能被当前程序读写
MODE_APPEND---当前文件的内容可以被追加
MODE_WORLD_READABLE---该文件的内容可以被其他程序读取
MODE_WORLD_WRITEABLE---该文件的内容可以被其他程序写入
需要注意的是,如果没有设置为最后两个配置,安卓的应用默认下任何应用程序创建的文件都是私有的,也就是默认都是MODE_PRIVATE
-
FileInputStream是输入流,将外部文件中的内容写入到程序中,只有一个参数name即文件名
外部存储
而所谓外部存储就是以文件的形式写入到一些外部设备,常见的就是SD卡或者设备内嵌的存储卡上,属于永久性的存储方式
因为外部存储器可以换到别的设备上也可以被任何程序读取使用和修改,所以是不安全的
因为手机可能没有外部存储设备,所以在使用外部存储的时候,一定需要先检查外部设备是否可用
String status = Environment.getExternalStorageState; //获取可用状态
if(status.equal(MODE_MEDIA_MOUNTED)){ // 判断可用
// 获取外部存储设备的存储路径,不同的设备存储路径可能不一样
File sdPath = Environment.getExternalStorageDirectory()
}
SharedPreferences存储
定义
SharedPreferences是Android平台上一个轻量级的存储类,可以进行一些少量数据的持久化
存入数据到SharedPreferences
SharedPreferences本身是一个只能从中获取数据的类,其数据的存储和修改对外是不开放的,但是因为其底层是Editor对象,所以我们一般都是利用Editor对象进行数据的存储和修改
实现逻辑过程是:
Editor以Key-Value键值对的形式保存数据且支持多种类型,但需要注意的是,末尾一定需要用commit提交保存否则操作不生效
// 获取SP对象 第一个参数data表示文件名 第二个参数表示文件操作模式
SharedPreferences sp = getSharedPreferences("data",MODE_PRIVATE)
// 通过SP对象获取可添加的Editor对象
SharedPreferences。Editor ed = sp.edit() 、
// Editor允许存储String Int Float Long Boolean Set<String>
ed.putString("name","张三")
ed.putInt("age",22)
ed.commit() // 提交存储数据
读取与删除SharedPreferences中的数据
读取
SharedPreferences中读取数据非常简单,获取到SharedPreferences对象之后,利用getxxx()方法直接获取即可,如果存在则返回数据,如果不存在就返回空字符串
SharedPreferences sp = getSharedPreferences("data",MODE_PRIVATE)
String data = sp.getString("name")
删除
删除对象是需要调用Edit对象的remove()方法即可
ed.remove("name") // 删除某一条数据
ed.clear() // 删除所有数据
SQLite数据库存储
前面两种方式适合存储简单数据,当需要存储大量数据的时候就不合适,为此Android提供了SQLite数据库用于存储大量数据进行管理维护
SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎,支持SQL语句,是世界上部署最广泛的数据库引擎
SQLite的创建
在Android中创建SQLIte很简单,因为它本质上是一个库类即SQLiteOpenHelper类,所以我们只需要自定义类继承这个类,重写其中的onCreate()方法和onUpgrade()方法即可
// Java的写法中可能会需要super调用父类的构造
// 需要四个参数即super(Context context , String dbName ,CursorFactory factory, int version )
// 第一个参数为上下文环境 一般传入当前Activity的环境即可 第二个参数为数据库的名字
// 第三个参数为游标工厂,不知道的情况下可以使用null ; 第四个参数为SQLite版本号,主流的为2,3目前
class MySQLite(val context:Context,val dbName:String):SQLiteOpenHelper(context,dbName,null,2){
//数据库第一次被创建的时候回调用这个方法 这里面就是execSQL就是执行SQL语句 传入的参数就是需要执行的SQL语句
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL("""
CREATE TABLE information(_id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARVHAR(20),PRICE INTEGER)
""".trimIndent())
}
//当数据库版本号增加的时候就会调用
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
}
}
如下,我们创建对应的MySQLite对象并且调用了writableDatabase获取创建了数据库的SQLiteDatabase对象(切记 一定需要获取到这个对象才算创建数据库,如果只是创建MySQLite对象可能不会真正创建),如下,创建的数据库的db文件默认在路径:/data/data/<包名>/databases/
,应该能看到两个文件:
-
first_sqlite_db
(主数据库文件) -
first_sqlite_db-journal
(日志文件)
SQLite数据库的CRUD操作
-
新增数据
使用insert()方法可以实现对SQLite数据库的数据新增
val db = MySQLite(activity,"first_sqlite_db") // 获得db对象
var writableDatabase = db.writableDatabase // 获得可操作的WritableDatabase对象
var values = ContentValues() // 设置要放入的数据 采用key-value的形式 即 字段-数值的形式
values.put("name","张三")
values.put("price",100)
// 第一个参数为表名 第二个参数表示 如果发现当前行为空行 则将该列设置为努力了 第三个对象即为ContentView对象
val id = writableDatabase.insert("information",null,values) // 返回新增数据的主键ID
Log.d("新增的数据ID为", id.toString())
//一定记得close 否则SQLite连接会一直存在,不断消耗内存,严重的会影响程序运行
writableDatabase.close()如下可以看到,information表结构和刚刚新增的数据都在
-
删除数据
删除数据也是用WriteableDatabase对象,使用其delete方法即可
val db = MySQLite(activity,"first_sqlite_db") // 获得db对象
var writableDatabase = db.writableDatabase // 获得可操作的WritableDatabase对象
var delete = writableDatabase.delete( // 返回值代表删除了多少行
"information", // 要操作的表名
"_id = ?", // WHERE 条件(? 是占位符)
arrayOf("1") // 替换占位符的实际参数值,传入的是数组 也就是可以匹配多个数值
)
//一定记得close 否则SQLite连接会一直存在,不断消耗内存,严重的会影响程序运行
writableDatabase.close() -
修改数据
修改数据也是用WriteableDatabase对象,使用其update()方法即可
val db = MySQLite(activity,"first_sqlite_db") // 获得db对象
var writableDatabase = db.writableDatabase // 获得可操作的WritableDatabase对象
// 修改 id=1 的数据(UPDATE 操作)
val updateValues = ContentValues().apply {
put("name", "李四") // 新姓名
put("price", 200) // 新价格
}
val updatedRows = writableDatabase.update(
"information", // 表名
updateValues, // 新值
"_id = ?", // WHERE 条件
arrayOf("1") // 参数值(自动替换 ?)
)
//一定记得close 否则SQLite连接会一直存在,不断消耗内存,严重的会影响程序运行
writableDatabase.close() -
查询数据
查询数据依靠的不再是WriteableDatabase对象,而是一个可读对象ReadableDatabase,使用它的query()方法进行查询
val db = MySQLite(activity,"first_sqlite_db").apply {
val readableDatabase = readableDatabase // 获取可读对象ReadableDatabase
// 查询所有数据(SELECT *)
val cursor = readableDatabase.query(
"information", // 表名
null, // 要返回的列(null 表示全部列)
null, // WHERE 条件 也可以和上面一样 _id=? 下面参数就是arrayOf("1")
null, // WHERE 参数
null, // GROUP BY
null, // HAVING
"_id ASC" // ORDER BY
)
// 解析查询结果
val dataList = mutableListOf<Map<String, Any>>()
while (cursor.moveToNext()) {
val item = mapOf(
"_id" to cursor.getInt(cursor.getColumnIndexOrThrow("_id")),
"name" to cursor.getString(cursor.getColumnIndexOrThrow("name")),
"price" to cursor.getInt(cursor.getColumnIndexOrThrow("price"))
)
dataList.add(item)
}
cursor.close()
// 输出结果
Log.d("DB", "查询结果: ${dataList.joinToString()}")
readableDatabase.close()
}也还可以利用rawQuery()直接传入SQL语句,利用原生SQL进行复杂查询
// 原生 SQL 查询(复杂查询时更灵活)
val cursor = readableDatabase.rawQuery("""
SELECT * FROM information
WHERE name LIKE ? AND price BETWEEN ? AND ?
ORDER BY _id
""", arrayOf("%张%", "100", "300"))
SQLIte事务
事务老生常谈了,和MySQL的事务性类似,也是保持ACID的特性(原子性,一致性,隔离性,持久性),含义也不多做解释,网上都查得到也是很基础的东西了
文章标题:安卓速通(其实是期末复习~)(第四章+第五章)
文章链接:https://zealsinger.xyz/?post=11
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自ZealSinger !
如果觉得文章对您有用,请随意打赏。
您的支持是我们继续创作的动力!

微信扫一扫

支付宝扫一扫