2023BaiduAndroidlec5-lec6
lec5-Android四大组件
大作业要求:
Activity
用户与应用程序交互的界面,每一个Activity都会代表一个屏幕,负责展示屏幕并处理用户的操作。每个Activity都是独立的,它们之间可以进行跳转、数据传递等互动
-
实现xml布局
-
实现Activity类文件
1
2
3
4
5
6class MainActivity: Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) // 给Activity设置布局
}
} -
给Activity设置布局
-
在manifest中声明Activity
1
2
3
4
5
6
7
8
9
10<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>Intent-filter 中的配置代表这个Activity是应用程序入口,点击桌面图标可进入
exported 属性代表Activity是否应用外开放
Activity的生命周期
-
onCreate()
必须实现,首次创建Activity触发
-
onStart()
当 Activity 进入"已开始"状态时,系统会调用此回调
-
onStop()
Activity 不再对用户可见,说明其已进入"已停止"状态
-
onRestart()
当用户回到Activity(非首次)
-
onResume()
当Activity 可见并进入可交互状态
-
onPause() :比如应用程序切换到后台就是pause+stop
当Activity 可见并进入不可交互状态
-
onDestory()
当Activity 销毁之前回调
Activity 显示调用
从一个Activity 启动另一个 Activity
startActivity 无返回值
1 | val intent = Intent(this, SecondActivity::class.java) |
startActivityForResult 有返回值回调
1 | startActivityForResult(Intent(this, SecondActivity::class.java), 1000) |
RequestCode的含义
第三个参数
1000
是请求代码(Request Code),用于标识此次启动 Activity 的请求。它是一个整数值,用于标记这个请求,以便在返回结果时可以识别是从哪个请求返回的结果。
Activity 隐式调用
隐式调用是指应用程序中不需要明确指定Activity 名称的调用方式,需要使用Intent对象来指定要启动的Activity 的类型和动作。Intent 对象包含了要启动的Activity的category 和action 信息,当调用startActivity() 方法时, Android 系统会根据Intent 对象中的信息来查找匹配的Activity,并启动该Activity。隐式调用可能存在一些安全问题,需要增加校验,防止Activity 劫持
Activity 跳转时生命周期
ActivityA 跳转 ActivityB, A与B均不透明,生命周期变化
A:onPause
B:onCreate -> onStart -> onResume
A:onStop
ActivityB 回到 ActivityA,生命周期变化
B:onPause
A:onRestart -> onStart -> onResume
B:onStop -> onDestory
演示
启动第一个activity
依次是Create Start Resume
Activity的任务栈
遵守先进后出罢了
Activity 的四种启动模式
-
Standard(标准模式)
标准模式是默认的启动模式。
每次启动Activity时都会创建一个新的实例 ,并放置在任务栈的顶部。 -
SingleTop(单顶模式)
当Activity位于任务栈的顶部时,再次启动该Activity时不会创建新的实例,而是会调用已存在实例的onNewIntent()方法。如果不在顶部,则会创建新的实例。
-
SingleTask(单任务模式)
单任务模式下,每个任务栈只能包含一个该Activity的实例。如果要启动的Activity已经存在于任务栈中,则会将该任务栈调到前台,触发该Activity的onNewlntent()方法,并将该Activity之上的Activity全部出栈。如果要启动的Activity不存在于任何任务栈中,则会创建新的任务栈并将该Activity放入其中。
-
SingleInstance(单实例模式)
单实例模式是最为独特的一种启动模式。在单实例模式下,该Activity会独占一个任务栈,并且该任务栈中只能有一个实例。无论从哪个应用程序中启动该Activity,都会共享同一个实例。如果要启动的Activity不存在于任何任务栈中,则会创建新的任务栈并将该Activity放入其中。
这些启动模式可以通过在AndroidManifest.xml文件中为Activityi设置android:launchMode属性来指定。
单实例使用场景例子 调用微信支付—>回退返回到自己的程序
Fragment(注意并非四大组件之一
Fragment,在Activity 中负责用户界面部分,可以将多个Fragment 组合在一个Activity 中来创建多窗口UI,或者在Activity 中重复使用某个Fragment。
- Fragment 是依赖于Activity的,不能独立存在的。
- 一个Activity 里可以有多个Fragment。
- 一个Fragment 可以被多个Activity 重用。
- Fragment 有自己的生命周期,并能接收输入事件。
- 我们能在Activity 运行时动态地添加或删除Fragment。
Fragment 的生命周期
- onAttach():当Fragment 与Activity 关联时调用。在这个阶段可以获取到与Fragment 关联的Activity 实例。
- onCreateView():创建Fragment 的视图。在这个阶段,可以定义Fragment 的布局,并返回布局的根视图。
- onActivityCreated():当与Fragment 关联的Activity 的onCreate()方法返回时调用。
- onDestroyView():销毁Fragment 的视图。在这个阶段,应该清理与视图相关的资源。
- onDetach(): 当Fragment 与Activity 解除关联时调用。
Fragment 的实现
-
创建一个新的类,这个类需要继承自Fragment 类
1
2
3public class MyFragment: Fragment() {
// ...
} -
重写onCreateView方法。这个方法是Fragment 创建它的用户界面时调用的。在这个方法中,返回一个包含Fragment 布局的View。
1
2
3override fun View onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?):View? {
return inflater.inflate(R.layout.fragment_my, container, false)
}
Activity 添加Fragment
Fragment可以通过两种方式被添加到Activity 中
静态添加:在Activity 的布局中使用<fragment> 标签来声明Fragment。
动态添加:在运行时通过FragmentManager 和FragmentTransaction 来添加、替换或者移除Fragment
1 |
|
1 | val myFragment: Fragment = MyFragment() |
R.id.fragment_container 是要添加Fragment的布局的id
FragmentTransaction
- add():添加Fragment 到 Activity 界面中
- remove():移除 Activity 中的指定 Fragment
- replace()系列:通过内部调用 remove() 和add() 完成 Fragment 的修改
- hide() 和show():隐藏和显示 Activity 中的 Fragment
- commit():提交事务,对 Fragment 的改动都必须通过调用 commit() 方法完成提交
- commitAllowingStateLoss():和commit()类似,但是允许在Activity状态保存后执行commit
- addToBackStack():该方法用于将当前的事务添加到回退栈中 ,当用户点击后退键时,将会导航到上一个Fragment状态。
Activity 与 Fragment 通讯:使用Bundle
-
在Activity 中创建Bundle 并设置到Fragment 中
1
2
3
4val bundle = Bundle()
bundle.putString("key", "value")
val fragment = MyFragment()
fragment.setArguments(bundle) -
在Fragment 中获取参数
1
2
3if(getArguments() != null) {
val value = getArguments().getString("key")
}
Fragment 与Activity 通讯
-
定义接口
1
2
3interface FragmentListener {
fun test()
} -
Activity实现接口
1
2
3
4
5class MyFragmentActivity: FragmentActivity(), FragmentListener {
override fun test() {
// ...
}
} -
Fragment调用接口
1
2
3if (activity is FragmentListener) {
(activity as FragmentListener).test()
}
比如同一个activity下有多个fragment,那么两个fragment之间想要通信就可以通过都与activity通信来实现
BroadCast
没怎么仔细听
广播介绍
广播是一种跨应用程序的消息传递机制,允许应用程序发送和接收系统级或应用级的事件。广播的目的是为了实现不同组件之间的解耦和通信。
符合设计模式中的 观察者模式,
也符合 发布订阅模式?
标准广播
一种异步进行的广播,当广播发出后,所有的接收器几乎同时接收到这个消息,这种广播的执行效率比较高,但是无法被截断。标准广播主要用于对性能要求较高的场景。
有序广播
是一种同步进行的广播,当广播发出后,系统会按照优先级顺序逐个传递给接收器。接收器在处理完广播后可以决定是否继续传递给下一个接收器,这样就实现了对广播的截断。有序广播主要用于对数据安全性和顺序要求较高的场景。
广播的类型(根据来源和作用范围划分
- 系统广播 ( System Broadcast )
系统广播是由Android系统发出的广播,用于通知应用程序系统状态的变化,例如电池电量变化、网络状态变化、屏幕关闭等。应用程序可以通过注册广播接收器( BroadcastReceiver)来监听和处理这些系统广播。 - 自定义广播( Custom Broadcast )
自定义广播是由应用程序自己发出的广播,用于向其他应用程序或应用程序内的不同组件传递消息。自定义广播可以是标准广播也可以是有序广播,开发者可以根据实际需求选择合适的广播类型。 - 本地广播( Local Broadcast )
本地广播是一种仅限于应用程序内部使用的广播,它使用Android Support Library中的LocalBroadcastManager 进行管理。本地广播相比于全局广播更加安全,因为它不会泄露应用程序内部的信息给其他应用程序。
应用内部尽量使用本地广播,更安全
常见系统广播
自定义广播:自定义receiver继承BroadcastReceiver()
直接看demo6的NetStateChangeReceiver
1 | class NetStateChangeReceiver : BroadcastReceiver() { |
静态广播和动态广播
Service
Service是Android中的一个核心组件,它是一个在后台运行的组件,用于在不与用户交互的情况下执行一些长时间运行的操作。Service中的操作可以在用户不使用应用程序时运行,从而使我们可以在后台执行任务,如下载文件、播放音乐等。Service不具备用户界面,因此它不会对用户界面产生影响。
Service是在主线程运行的
适合service的场景:
- 音乐播放器
- 后台定位服务
- 网络同步
- 长时间运行的后台任务
- 跨进程通信 (IPC)
Service的类型
Service 的生命周期:有两种
启动服务
当使用startService() 方法启动服务时,服务会在后台无限期运行,直到它自行停止或被其他组件(如Activity)调用stopService() 方法停止
绑定服务
当使用bindService() 方法鄉定服务时,服务与调用它的应用组件(如Activity)建立了一个持续的连接。组件可以与服务进行双向通信
创建service
1 | class MyService : Service() { |
注意service也需要在manifest中注册
另外还需要再Manifest 中注册<service android:name=“.MyService”>
启动service
启动服务(startService):
val intent = Intent(this, MyService::class.java)
startService(intent)
停止服务(stopService):
val intent = Intent(this, MyService::class.java)
stopService(intent)
绑定服务 (bindService):
val intent = Intent(this, MyService::class.java)
bindService(intent, serviceConnection, Context. BIND_AUTO_CREATE)
取消绑定服务 (unbindService):
unbindService(serviceConnection)
ContentProvider
简介
ContentProvider URI
ContentProvider使用URI ( Uniform Resource Identifier,统一资源标识符)来唯一标识和访问不同的数据资源。ContentProvider URI通常具有以下结构:
- content:// :这是一个固定的前级,表示这是一个ContentProvider的URI。
- content://authority/path/id
- authority:用于标识ContentProvider的唯一字符串,通常采用应用的包名加上一个自定义的字符串。在AndroidManifest.xml文件中注册ContentProvider时 ,需要指定它的aandroid:authorities属性。
- path:表示数据资源的类型或类别,可以通过在URI中指定表名作为路径来访问特定表的数据
- id:这是一个可选部分,用于表示特定数据项的ID。在URI中加入ID可以让您访问特定记录的数据。
定义ContentProvider
1 | class MyContentProvider : ContentProvider() { |
在manifest中定义contentprovider
1 | <provider |
在需要访问数据的地方,通过ContentResolver与ContentProvider进行交互
1 | // 获取ContentResolver对象 |
FileProvider
name是对外的
path是自己的真实路径
作业
视频的页面可以先留空
实现能选就行了,存到哪以后再说
点击首页的加号进入新闻发布页
lec6-Android图形图像和多媒体实现
图片
图片格式介绍
图片内存大小
对于Bitmap对象,有几种常见色彩格式
- Bitmap.Config.ALPHA_8:每个像素占1个字节
- Bitmap.Config.RGB_565:每个像素占2个字节
- Bitmap.Config.ARGB_4444:每个像素占2个字节
- Bitmap.Config.ARGB_8888:每个像素占2个字节
1.使用ImageView加载图片
如Kotlin API
1 | // 找到ImageView控件 |
ImageView组件:xml
1 | <ImageView |
scaleType的值可以修改为上图所列
dp与sp
sp做单位会受缩放影响
2.使用android内置API加载图片
1 | val bitmap: BitMap = BitmapFactory.decodeResource(getResources(), R.drawable.example_image) |
基本不怎么用了,网络图片加载还要先异步请求
3.第三方图片加载库
推荐使用Glide或者Fresco
1 | Glide.with(this) |
图片缓存
三级缓存策略
三级缓存减少不必要的网络请求和内存占用
- 内存缓存
- 本地缓存
- 网络缓存
图片处理
压缩、裁剪、缩放、滤镜、拼接、合成、旋转
音频
MediaPlayer的使用方式
-
创建MediaPlayer实例
1
val mediaPlayer: MediaPlayer = MediaPlayer()
-
设置音频数据源
1
2
3
4// 设置本地音频数据源
mediaPlayer.setDataSource("/path/to/your/audio/file")
// 设置网络音频数据源
mediaPlayer.setDataSource("http://example.com/your/audio/file.mp3") -
准备播放
1
2
3
4// 同步准备
mediaPlayer.prepare()
// 异步准备
mediaPlayer.prepareAsync() -
设置监听器
1
2
3
4
5
6
7
8
9
10
11
12// 设置准备完成监听器:
mediaPlayer.setOnPreparedListener(object: MediPlayer.OnPreparedListener{
override fun onPrepared(mp: MediaPlayer?) {
// 异步准备完成回调
}
})
// 设置播放完成监听器:
mediaPlayer.setOnCompletionListener(object: MediaPlayer.OnCompletionListener{
override fun onConpletion(mp: MediaPlayer?) {
// 播放完成后,可以进行相应的操作
}
}) -
控制播放
1
2
3
4
5
6
7
8// 播放
mediaPlayer.start()
// 暂停
mediaPlayer.pause()
// 停止
mediaPlayer.stop()
// 释放资源
mediaPlayer.release()
prepare()
的调用可能需要很长时间,所以切勿从应用的界面线程中调用它,界面中任何响应时间超过十分之一秒的操作都会导致明显的暂停,并让用户觉得应用运行缓慢。推荐使用
prepareAsync()
在后台准备媒体,准备就绪后系统会调用通过setOnPreparedListener()
配置的MediaPlayer.OnPreparedListener
的onPrepared()
方法。
在Service中使用MediaPlayer
SoundPool的使用
AudioManager控制音频焦点
视频
播放视频的方式
VideoView
1 | <VideoView |
1 | // 加载视频并播放 |
SurfaceView介绍
TextureView介绍
SurfaceView
和TextureView
都是Android中用于显示图像、视频或动画的视图组件,但它们在实现和使用上有一些区别。
- SurfaceView:
SurfaceView
是一个特殊的视图,它允许你在一个独立的绘图表面上绘制内容。SurfaceView
适用于需要频繁更新的图像、视频播放、动画等场景,因为它允许在后台线程中进行绘制,避免了在主线程中的UI阻塞。主要特点和用途包括:
- 可以在后台线程(非UI线程)中绘制内容,避免主线程阻塞。
- 使用双缓冲技术,提高绘制性能,避免闪烁现象。
- 适合实现实时视频播放、相机预览等需要频繁刷新的场景。
- 对于自定义绘图、动画或游戏等复杂场景,更为灵活和强大。
- TextureView:
TextureView
是一个可以显示视频或动画的视图组件。它与SurfaceView
不同之处在于,它在视图层级中是一个普通的View
,可以与其他视图组件一起进行布局,并在Android的硬件加速支持下提供更高的灵活性。主要特点和用途包括:
- 可以在布局中与其他视图组件一起使用,更容易实现复杂的布局。
- 支持硬件加速,提供更高的绘制性能。
- 适用于视频播放、动画等场景,可以通过
MediaPlayer
或SurfaceTexture
来实现视频的播放。- 可以与动画效果、透明度等属性结合使用,实现更丰富的视觉效果。
选择使用
SurfaceView
还是TextureView
取决于你的应用需求。如果你需要频繁更新、复杂的绘图逻辑或更好的性能,那么SurfaceView
可能是更好的选择。如果你希望在布局中更灵活地使用,或者需要与其他视图组件结合使用,那么TextureView
可能更适合你。
MeidaPlayer+SurfaceView播放视频
MeidaPlayer+TextureView播放视频
ExoPlayer
更加灵活,可拓展性比MediaPlayer强
基本教程:Hello World
ExoPlayer is deprecated,原有的ExoPlayer已经被Media3 ExoPlayer取代
build.gradle
中不使用com.google.android.exoplayer:exoplayer-core:2.12.0
了,新增如下内容
1 | implementation "androidx.media3:media3-exoplayer:1.1.0" |
这一段不知道是啥,别人的笔记
如何使用MediaPlayer访问本地文件,并请求权限
我们在/storage/emulated/0/Music
目录上传了guitar.mp3
音乐文件,并希望播放此音乐
错误做法:直接设置mediaPlayer.setDataSource(/storage/emulated/0/Music/guitar.mp3)
或mediaPlayer.setDataSource(Environment.getExternalStorageDirectory().path + "/Music/guitar.mp3")
都会报错java.io.FileNotFoundException: /storage/emulated/0/Music/guitar.mp3: open failed: EACCES (Permission denied)
,意思没有访问的权限。
探索过程:
- 无效:设置
android:requestLegacyExternalStorage="true"
。This solution is temporary and won’t work on Android 11 - 有效:实现运行时权限获取 ,顺便参考storage access in android 11 ,个人感觉
allowPermissionForFile()
那个函数不能直接同步请求,应该放在异步任务中完成
解决方法:
-
在settings->Apps->Your_app->Permissions手动打开存储权限,不过这只适用于我们本地开发这么做,实际情况下需要引导用户打开权限
-
请求用户打开权限
ActivityManifest.xml
适用于API<=32的情景,若API>32,会提醒you should instead use one or more new storage permissions: READ_MEDIA_IMAGES, READ_MEDIA_VIDEO or READ_MEDIA_AUDIO
1 | <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> |
MediaPlayerActivity.kt
假如在用户界面同步请求权限,会导致应用程序卡主、长时间无响应甚至crash,所以我们应当在后台线程或异步任务重进行权限请求,避免阻塞主线程。这里借助
1 | // generated by chatgpt |
上述方法是获取本地存储的资源,简单起见可以将文件放在raw文件夹下,然后通过setDataResource
的方法获取(上述已给出实例)
如果要实现后台播放音乐,就需要用到Service的知识,暂不详述(其实不会x
随堂作业
不用能上下滑动,右边没有收藏分享啥的也可以
lec7-Android持久化
什么是持久化
持久化是将数据保存到可永久保存的存储设备中的过程。
持久化是将程序数据在 持久状态 和 瞬间状态 见转换的机制
三种数据持久化方式
Shared Preferences
-
是 Android系统 提供的一种轻量级的存储方式。
-
常用于存储简单的 应用设置、配置数据 或 状态信息。
-
使用 键值对 的方式来存储数据。
-
支持 多种不同数据类型 (如字符串、整数、浮点数、布尔值和长整型)
-
相关数据存放在 xml 中。 xml文件的存放路径为:
/data/data/packageName/shared_prefs/目录下
获取方式
-
通过Context对象获取: Context 的 getSharedPreferences() 方法,需要传入2个参数: 文件名 和 模式 ( 目前只有MODE_PRIVATE, 表示只有当前应用可以访问这个Shared Preferences)
1
2// 代码示例
val sharedPreferences = context.getSharedPreferences("my_prefs", Context.MODE_PRIVATE) -
通过Activity对象获取:Activity 中的 getPreferences() 方法, 它默认将当前活动的类名作为文件名,只需要传入操作模式作为参数
1
val sharedPreferences = getPreferences(MODE_PRIVATE);
-
通过PreferenceManager类获取:PreferenceManager的getDefaultSharedPreferences(), 它接收一个 Context参数
1
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
如何写入数据
使用Editor对象来写入数据。Editor对象可以通过SharedPreferences.edit()方法获取
1 | // 1. 创建一个SharedPreferences对象 |
同步写入会阻塞当前线程,直到数据写入完成。如果写入数据较多,会导致界面卡顿。因此建议写入大量数据时使用apply()方法异步写入(意思就是不会立即生效
其他操作
1 | // 创建(获取)一个SharedPreferences对象 |
感觉可以用在某个activity的临时数据上,但要注意每个activity要有其独立的sp,名字要区分开,否则会导致写到相同的,清除了同一个文件,当然这也需要从代码上进行物理空间的解耦
优点
缺点
容量有限、不支持复杂的数据结构、难以维护、安全性较低
跨进程不安全、全量写入、加载缓慢
卡顿
KV存储(简单了解,不是android原生的,SP的衍生
常用的有MMKV,Booster,PreferceDataStore, UniKV, 代理方式优化写入性能
UniKV:百度在用的
代理方式:字节在用
- MMKV
- 内存准备
- 数据组织
- 写入优化
文件存储
Android的文件存储方式,适用于存储本地的二进制数据。可以通过读写FileInputStream 和 FileOutputStream来操作文件
区别于SharedPreference,更适合用来存储html数据、下载文件、日志打印、照片、视频等。
存储空间
- /data/data
- 用户应用 的安装目录,如百度地图的安装路径是 /data/data/com.baidu.com, 该目录需要root权限
- /system
- 系统应用 的安装目录
- /storage
- 内置存储卡 和 外置SD卡 的挂载点
- 外置SD卡挂载节点:/storage/sdcard1
- 内置存储卡挂载节点:/storage/emulated/0
- 不同的设备挂载节点不同,有的可能在 /mnt下
内部存储空间
- 应用专属空间:创建其他应用不需要访问或不应访问的文件。
- getFilesDir(), data/data/包名/files/,用于持久文件
- getCacheDir(), data/data/包名/cache/,用于暂存文件
外部存储空间
- getExternalFilesDir(), /mnt/sdcard/Android/data/包名/files/,用于持久文件
- getExternalCacheDir(), /mnt/sdcard/Android/data/包名/cache/,用于暂存文件
具体代码应用
Context提供两种方法来打开数据文件里的文件IO流
- openFileInput(String name), 读文件
- openFileOutput(String name, int mode), 写文件,其中第二个参数指定打开文件的模式
- MODE_PRIVATE, 默认操作模式,当指定同样文件名的时候会覆盖原有文件内容。
- MODE_APPEND, 如果文件不存在就创建文件,如果存在就往后追加。
读取文件
1 | // 使用openFileinput() 以信息流的形式读取文件 |
写入文件
1 | // 使用 openFileOutput()写入文件 |
外部存储空间
读取外部存储中的文件之前,需要在AndroidManifest.xml文件中添加相应的权限声明
1 | <user-permission adnroid:name="android.permission.READ_EXTERNAL_STORAGE" /> |
之后跟内部存储方式的区别只是获取file的路径不同
1 | // 指定外部存储的路径和文件名 |
数据库存储
SQLite数据库
- SQLite是一款轻量级的关系型数据库,它的运行速度快,占用资源少,通常只需要几百k的内存即可。
- 因而特别适合在移动设备上使用
- SQLite不仅支持标准的SQL语法,还遵循数据库事务管理
- 只要以前用过其他关系型数据库就可以很快上手
创建数据库
- 为了更方便地管理数据库,提供了一个帮助类 SQLiteOpenHelper
- 新建一个类MyDatabaseHelper,继承SQLiteOpenHelper,实现三个方法:构造函数,onCreate,onUpgrade
1 | class MyDBHelper(context: Context): SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { |
1 | override fun onCreate(db: SQLiteDatabase) { |
添加数据
-
Android提供了一系列的辅佐性方法,使得在Android中,可以不去写SQL语句也能完成增删查改操作。
-
调用SQLiteOpenHelper的**getReadableDatabase()或getWritableDatabase()**方法可以用于创建和升级数据库
-
这两个方法会返回一个SQLiteDatabase对象,借助这个对象就可以对数据库进行增删查改操作。
-
SQLiteDatabase提供了一个insert() 方法,这个方法就是专门用于添加数据,它接收3个参数:
- 第一个参数:表名,要操作的表
- 第二个参数:null,在未指定添加数据的情况下给某些可以为空的列自动复制NULL
- 第三个参数:要添加的数据,它是一个ContentValues对象,提供一些列的put()方法重载来传入数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 访问数据座,先实例化 MVDBHelper 的子类
val dbhelper = MyDBHelper(this)
// 以写入模式获取数据存储库
val db: SQLiteDatabase = dbhelper.getWritableDatabase()
val values = ContentValues()
// 插入第一行数据
values.put("author","郭霖")
values.put('name',"第一行代码")
db.insert("Book", null, values)
// 插入其它数据前先清空
values.clear()
// 插入第二条数据
values.put("author" "张三")
values.put("name", "I/FARI")
db.insert("Book", null, values)
查询数据
-
SQLiteDatabase提供了query() 方法对数据进行查询,根据需要指定7个参数
-
调用query()方法后会返回一个Cursor对象,查询到得所有数据都将从这个对象中取出。
query() 参数 对应SQL部分 table from table_name columns select column1, column2 selection where column = value selectionArgs (where中占位符的值) groupBy group by coulmn having having column = value orderBy order by column
1 | val dbhelper = MyDBHelper(this) |
更新数据
-
SQLiteDatabase提供了update()方法对数据进行更新
-
这个方法接收4个参数:
- table:String ,要更新的表名
- values : ContentValues,要更新的数据
- whereClause:String ,约束要更新哪行的数据
- whereArgs:String[],上一个参数中占位符的值
1
2
3
4
5
6
7
8
9val dbhelper = MyDBHelper(this)
// 以写入模式获取数据存储库
val db: SQLiteDatabase = dbhelper.getWritableDatabase()
val values = ContentValues().apply{
put("name", "第二行代码")
}
// ?是一个占位符
// 第四个参数提供一个字符串数组,为第三个参数中的每个占位符指定相应的内容
db.update("Book", values, "author = ?", arrayOf("郭霖"))
删除数据
-
SQLiteDatabase中提供了delete()方法删除数据
-
这个方法接收了个参数:
- table :String,要更新的表名
- whereClause :String,约束要删除哪行的数据
- whereArgs :String[],上一个参数中占位符的值
1
2
3
4
5// 以写入模式获取数据存储库
val db: SQLiteDatabase = dbhelper.getWritableDatabase0)
// ?是一个占位符
// 第四个参数提供一个字符串数组,为第三个参数中的每个占位符指定相应的内容
db.delete("Book","author = ?",arrayOf("郭霖"))
其他的存储方式
作业
引申:
用户数据如何在不同设备之间共享?
其实是有个云服务器存储数据的
lec8-网络编程
lec9-
- 标题: 2023BaiduAndroidlec5-lec6
- 作者: SYuan03
- 创建于 : 2023-07-23 22:33:10
- 更新于 : 2024-09-30 20:51:52
- 链接: https://bblog.031105.xyz/posts/2023-Summer-Courses-百度移动端/2023baiduandroidlec5-lec6.html
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。