该文章为低质量文章,只对书籍中废弃的API进行替换更新,并无本质创新。
多媒体
使用通知
创建通知
每条通知都要属于一个对应的渠道,通知渠道一旦创建之后就不能再修改。
- 首先需要一个NotificationManager对通知进行管理,可以通过调用Context的getSystemService()方法获取;
- 接下来要使用NotificationChannel类构建一个通知渠道,并调用NotificationManager的createNotificationChannel()方法完成创建。
- AndroidX库中提供了一个NotificationCompat类,使用这个类的构造器创建Notification对象;
- 调用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。
- 创建意图;
- 获取PendingIntent的实例,可以根据需求来选择是使用getActivity()方法、getBroadcast()方法,还是getService()方法;
- 在构造器NotificationCompat.Builder中连缀一个setContentIntent()方法;
- 连缀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对象,这个对象就是用于设置大图片的。
设置重要等级
开发者只能在创建通知渠道的时候为它指定初始的重要等级,如果用户不认可这个重要等级的话,可以随时进行修改,开发者对此无权再进行调整和变更。
调用摄像头和相册
调用摄像头
- 创建File对象,用于存放摄像头拍摄的照片;
- 判断设备运行版本,如果运行设备的系统版本低于Android 7.0,就调用Uri的fromFile()方法将File对象转换成Uri对象,这个Uri对象标识着output_image.jpg这张图片的本地真实路径。否则,就调用FileProvider的getUriForFile()方法将File对象转换成一个封装过的Uri对象;
- 构建意图对象,并将意图指定为获取图片,并调用Intent的putExtra()方法指定图片的输出地址;
- 最后调用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类实现的。

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

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 [文件路径] git reset HEAD [文件路径] git log [id]
|