使用多媒体

多媒体

使用通知

创建通知

每条通知都要属于一个对应的渠道,通知渠道一旦创建之后就不能再修改。

  1. 首先需要一个NotificationManager对通知进行管理,可以通过调用Context的getSystemService()方法获取;
  2. 接下来要使用NotificationChannel类构建一个通知渠道,并调用NotificationManager的createNotificationChannel()方法完成创建。
  3. AndroidX库中提供了一个NotificationCompat类,使用这个类的构造器创建Notification对象;
  4. 调用NotificationManager的notify()方法让通知显示出来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MainActivity : AppCompatActivity() { 

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as
NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("normal", "Normal",NotificationManager.
IMPORTANCE_DEFAULT)
manager.createNotificationChannel(channel)
}
sendNotice.setOnClickListener {
val notification = NotificationCompat.Builder(this, "normal")
.setContentTitle("This is content title")
.setContentText("This is content text")
.setSmallIcon(R.drawable.small_icon)
.setLargeIcon(BitmapFactory.decodeResource(resources,
R.drawable.large_icon))
.build()
manager.notify(1, notification)
}
}
}

创建通知渠道的代码只在第一次执行的时候才会创建,当下次再执行创建代码时,系统会检测到该通知渠道已经存在了,因此不会重复创建,也并不会影响运行效率.

点击通知

使用PendingIntent实现通知的点击效果。

PendingIntent从名字上看起来就和Intent有些类似,PendingIntent倾向于在某个合适的时机执行某个动作。所 以,也可以把PendingIntent简单地理解为延迟执行的Intent。

  1. 创建意图;
  2. 获取PendingIntent的实例,可以根据需求来选择是使用getActivity()方法、getBroadcast()方法,还是getService()方法;
  3. 在构造器NotificationCompat.Builder中连缀一个setContentIntent()方法;
  4. 连缀setAutoCancel()方法设置通知消失或者显示调用NotificationManager的cancel()方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MainActivity : AppCompatActivity() { 

override fun onCreate(savedInstanceState: Bundle?) {
...
sendNotice.setOnClickListener {
val intent = Intent(this, NotificationActivity::class.java)
val pi = PendingIntent.getActivity(this, 0, intent, 0)
val notification = NotificationCompat.Builder(this, "normal")
.setContentTitle("This is content title")
.setContentText("This is content text")
.setSmallIcon(R.drawable.small_icon)
.setLargeIcon(BitmapFactory.decodeResource(resources,
R.drawable.large_icon))
.setContentIntent(pi)
.setAutoCancel(true)
.build()
manager.notify(1, notification)
}
}

}

设置通知样式

使用setStyle()方法,传入不同对象。比如NotificationCompat.BigTextStyle对象,这个对象就是用于封装长文字信息的;NotificationCompat.BigPictureStyle对象,这个对象就是用于设置大图片的。

设置重要等级

开发者只能在创建通知渠道的时候为它指定初始的重要等级,如果用户不认可这个重要等级的话,可以随时进行修改,开发者对此无权再进行调整和变更

调用摄像头和相册

调用摄像头

  1. 创建File对象,用于存放摄像头拍摄的照片;
  2. 判断设备运行版本,如果运行设备的系统版本低于Android 7.0,就调用Uri的fromFile()方法将File对象转换成Uri对象,这个Uri对象标识着output_image.jpg这张图片的本地真实路径。否则,就调用FileProvider的getUriForFile()方法将File对象转换成一个封装过的Uri对象;
  3. 构建意图对象,并将意图指定为获取图片,并调用Intent的putExtra()方法指定图片的输出地址;
  4. 最后调用startActivityForResult()启动Activity,并重写onActivityResult()方法,可调用BitmapFactory的decodeStream()方法将output_image.jpg这张照片解析成Bitmap对象,然后把它设置到ImageView中显示出来。

由于使用了FileProvider,它的本质是一个向外提供的ContentProvider,因此一旦使用,必须要进行注册。

调用相册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class MainActivity : AppCompatActivity() { 
...
val fromAlbum = 2
override fun onCreate(savedInstanceState: Bundle?) {
...
fromAlbumBtn.setOnClickListener {
// 打开文件选择器
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
// 指定只显示图片
intent.type = "image/*"
startActivityForResult(intent, fromAlbum)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
...
fromAlbum -> {
if (resultCode == Activity.RESULT_OK && data != null) {
data.data?.let { uri ->
// 将选择的图片显示
val bitmap = getBitmapFromUri(uri)
imageView.setImageBitmap(bitmap)
}
}
}
}
}
private fun getBitmapFromUri(uri: Uri) = contentResolver
.openFileDescriptor(uri, "r")?.use {
BitmapFactory.decodeFileDescriptor(it.fileDescriptor)
}
...
}

这样通过文件管理器的方式实现似乎不需要进行注册额外权限。

目前我们的实现还不算完美,因为如果某些图片的像素很高,直接加载到内存中就有可能会导致程序崩溃。更好的做法是根据项目的需求先对图片进行适当的压缩,然后再加载到内存中。

播放多媒体文件

在Android中播放音频文件一般是使用MediaPlayer类实现的。

QQ_1737181035574

播放视频文件其实并不比播放音频文件复杂,主要是使用VideoView类来实现的。

QQ_1737181087153


Kotlin课堂

infix 函数

Kotlin提供了一种高级语法糖特性:infix函数,把编程语言函数调用的语法规则进行调整。

1
2
3
4
infix fun String.beginsWith(prefix: String) = startsWith(prefix) 
if ("Hello Kotlin" beginsWith "Hello") {
// 处理具体的逻辑
}

infix函数允许我们将函数调用时的小数点、括号等计算机相关的语法去掉,从而使用一种更接近英语的语法来编写程序,让代码看起来更加具有可读性

infix函数有两个比较严格的限制:

  • 首先,infix函数是不能定义成顶层函数的,它必须是某个类的成员函数,可以使用扩展函数的方式将它定义到某个类当中;
  • 其次,infix函数必须接收且只能接收一个参数,至于参数类型是没有限制的。

典型应用:to结构

1
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that) 

Git进阶

使用.gitignore文件进行管理,Android Studio在创建项目的时候会自动帮我们创建出两个.gitignore 文件,进行初步的版本控制忽略。

以下是常见的命令:

1
2
3
4
5
git status # 查看修改情况
git diff [文件路径] # 查看文件变动情况 [文件路径]可忽略
git checkout [文件路径] # 撤销修改,只能撤销还未add的修改
git reset HEAD [文件路径] # 撤销已经add的修改
git log [id] # 查看提交记录,使用ID可以进行具体的查看