8.1 将程序运行到手机上
8.2 使用通知
8.2.1 通知的基本用法
8.2.2 通知的进阶技巧
8.2.3 通知的高级功能
8.3 调用摄像头和相册
8.3.1 调用摄像头拍照
8.3.2 从相册中选择照片
8.4 播放多媒体文件
8.4.1 播放音频
8.4.2 播放视频
8.5 小结与点评
打开手机开发者模式-USB 调试 (有些手机还有通过USB安装应用程序)
在设置中找不到开发者模式的话 需要点击系统版本 打开开发者
若仍然在AS中找不到手机,可能驱动未安装成功
本人解决方法:使用360手机助手 搞定的。
通知的用法灵活,既可以在活动里创建,也可在广播接收器里创建,还可在服务里创建。
Intent intent = new Intent(this, OtherNoticeActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// manager.cancel(1); 退出指定通知
//channelId 渠道id
Notification notification = new NotificationCompat.Builder(this,"chat")
.setContentTitle("This is content title")
.setContentText("this is content text")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setAutoCancel(true)
.setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))
//
.setVibrate(new long[]{0, 1000, 1000, 1000})//设置静止震动时长 震动1秒 静止1秒 在震动1秒
.setLights(Color.GREEN, 1000, 1000)//灯光
// .setDefaults(NotificationCompat.DEFAULT_ALL)//根据当前情况来决定播放什么铃声,以及如何震动
.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(),R.mipmap.jelly_fish)))
.setPriority(NotificationCompat.PRIORITY_HIGH)//显示级别 横幅
.setContentIntent(pendingIntent)
// .setFullScreenIntent(pendingIntent,true)//响应紧急事件 比如来电 直接跳转
.build();
manager.notify(1,notification);
上面提到了通知的基本用法,接下来介绍一些通知的其他技巧,比如:
在通知发出时播放一段音频,调用 setSound() 方法:
Notification notification = new NotificationCompat.Builder(this)
. . .
.setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg"))) // 在音频目录下选个音频文件
.build();
在通知到来时让手机振动,设置 vibrate 属性:
Notification notification = new NotificationCompat.Builder(this)
. . .
.setVibrate(new long[]{0,1000,1000,1000}) // 数组下标0表静止的时长,下标1表振动的时长,下标2表静止的时长,以此类推
.build();
当然别忘了声明振动权限:
在通知到来时显式手机 LED 灯,调用 setLights() 方法:
Notification notification = new NotificationCompat.Builder(this)
. . .
.setLights(Color.GREEN,1000,1000) // 三个参数:LED 灯的颜色、灯亮时长、灯暗时长
.build();
当然也可直接使用默认效果,如下:
Notification notification = new NotificationCompat.Builder(this)
. . .
.setDefaults(NotificationCompat.DEFAULT_ALL)
.build();
NotificationCompat.Builder 类中的 setStyle() 方法
setStyle() 方法接收一个 NotificationCompat.style 参数,这个参数用来构造具体的富文本信息,如长文字、图片等。
https://segmentfault.com/a/1190000008241257
调用摄像头和相册 是非常常用的功能,在这里,我们不仅实现了掉用摄像头和相册,同时也对于Android 7.0 系统进行了适配,主要的一点就是 获取Uri 相关连的代码,在返回结果的时候也是需要我们对于Uri进行解析,请看代码:
package com.dak.administrator.firstcode.multi_media;
import android.Manifest;
import android.annotation.TargetApi;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.Image;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Toast;
import com.dak.administrator.firstcode.R;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
public class CameraAlbumActivity extends AppCompatActivity {
private ImageView picture;
private static final int TAKE_PHOTO = 1;
private static final int CHOOSE_PHOTO = 2;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_album);
picture = findViewById(R.id.picture);
Button takePhoto = findViewById(R.id.take_photo);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openCamera();
}
});
Button fromAblum = findViewById(R.id.choose_from_album);
fromAblum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(CameraAlbumActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(CameraAlbumActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
} else {
openAlbum();
}
}
});
}
/**
* 打开相机
*/
private void openCamera() {
//创建用处存储拍照后的图片
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT >= 24) {
imageUri = FileProvider.getUriForFile(CameraAlbumActivity.this,
"com.dak.administrator.firstcode.fileprovider", outputImage);
} else {
imageUri = Uri.fromFile(outputImage);
}
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//输出地址
startActivityForResult(intent, TAKE_PHOTO);
}
/**
* 打开相册
* gallery
*/
private void openAlbum() {
//很漂亮页面
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_PHOTO);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openAlbum();
} else {
Toast.makeText(this, "请获取权限", Toast.LENGTH_SHORT).show();
}
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
// 压缩 循环 太慢
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
// int options = 100;
// while (baos.toByteArray().length / 1024 > 100) {//循环判断如果压缩后图片是否大于100kb,大于继续压缩
// baos.reset();//重置baos即清空baos
// bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
// options -= 10;//每次都减少10
// }
// ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
// Bitmap comBitmap = BitmapFactory.decodeStream(bais);
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
case CHOOSE_PHOTO:
if (resultCode == RESULT_OK) {
if (Build.VERSION.SDK_INT >= 19) {
//4.4及以上系统使用这个方法处理图片
handleImageOnKitKat(data);
} else {
//4.4及以下系统使用这个方法处理图片
handleImageBeforeKitKat(data);
}
}
break;
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private void handleImageOnKitKat(Intent data) {
String imagePath = null;
Uri uri = data.getData();
if (DocumentsContract.isDocumentUri(this, uri)) {
//如果是document 类型的uri ,则通过document id处理
String docId = DocumentsContract.getDocumentId(uri);
if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
//如果uri的authority是media格式 再次解析id 将字符串分割取出后半部分才能得到真正的数字id
String id = docId.split(":")[1];//解析出数字格式的id
String selection = MediaStore.Images.Media._ID + "=" + id;
imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
} else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
imagePath = getImagePath(contentUri, null);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
//如果是content类型的uri,则使用普通方式处理
imagePath = getImagePath(uri, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
//如果是file类型的uri,直接获取图片路径
imagePath = uri.getPath();
}
displayImage(imagePath);//根据图片路径显示图片
}
private String getImagePath(Uri externalContentUri, String selection) {
String path = null;
//通过Uri和selection来获取真实图片路径
Cursor cursor = getContentResolver().query(externalContentUri, null, selection, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cursor.close();
}
return path;
}
private void displayImage(String imagePath) {
if (imagePath != null) {
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
picture.setImageBitmap(bitmap);
} else {
Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show();
}
}
private void handleImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(uri, null);
displayImage(imagePath);
}
}
Xml页面:
在AndroidManifest.xml中配置Provider
file_paths.xml
当然也别忘了声明访问SD卡的权限:
注意事项:在实际开发中最好根据项目的需求先对照片进行适当的压缩,然后再加载到内存中。
在安卓中播放音频文件一般用 MediaPlayer 类来实现,播放视频文件主要用 VideoView 类来实现。
MediaPlayer 常用方法:
MediaPlayer | 构造方法 |
create | 创建一个要播放的多媒体 |
getCurrentPosition | 得到当前播放位置 |
getDuration | 得到文件的时间 |
getVideoHeight | 得到视频的高度 |
getVideoWidth | 得到视频的宽度 |
isLooping | 是否循环播放 |
isPlaying | 是否正在播放 |
pause | 暂停 |
prepare | 准备(同步) |
prepareAsync | 准备(异步) |
release | 释放MediaPlayer对象相关的资源 |
reset | 重置MediaPlayer对象为刚刚创建的状态 |
seekTo | 指定播放的位置(以毫秒为单位的时间) |
setAudioStreamType | 设置流媒体的类型 |
setDataSource | 设置多媒体数据来源(位置) |
setDisplay | 设置用SurfaceHolder来显示多媒体 |
setLooping | 设置是否循环播放 |
setOnButteringUpdateListener | 网络流媒体的缓冲监听 |
setOnErrorListener | 设置错误信息监听 |
setOnVideoSizeChangedListener | 视频尺寸监听 |
setScreenOnWhilePlaying | 设置是否使用SurfaceHolder来保持屏幕显示 |
setVolume | 设置音量 |
start | 开始播放 |
stop | 停止播放 |
VideoView和MediaPlaer也比较类似,主要有以下常用方法:
setVideoPath() |
设置要播放的视频文件的位置。 |
start() |
开始或继续播放视频。 |
pause() |
暂停播放视频。 |
resume() |
将视频重头开始播放。 |
seekTo() |
从指定的位置开始播放视频。 |
isPlaying() |
判断当前是否正在播放视频。 |
getDuration() |
获取载入的视频文件的时长。 |
package com.dak.administrator.firstcode.multi_media;
import android.Manifest;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.dak.administrator.firstcode.R;
import java.io.File;
import java.io.IOException;
public class MediaActivity extends AppCompatActivity implements View.OnClickListener {
private MediaPlayer mediaPlayer = new MediaPlayer();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media);
Button play = findViewById(R.id.play);
Button pause = findViewById(R.id.pause);
Button stop = findViewById(R.id.stop);
play.setOnClickListener(this);
pause.setOnClickListener(this);
stop.setOnClickListener(this);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}else {
initMediaPlayer();
}
}
private void initMediaPlayer() {
try {
File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");//music.mp3不存在
mediaPlayer.setDataSource(file.getPath());
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initMediaPlayer();
}else {
Toast.makeText(this, "请获取存储权限", Toast.LENGTH_SHORT).show();
finish();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
break;
case R.id.pause:
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
break;
case R.id.stop:
if (!mediaPlayer.isPlaying()) {
mediaPlayer.reset();
initMediaPlayer();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
}
xml文件:
package com.dak.administrator.firstcode.multi_media;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.widget.VideoView;
import com.dak.administrator.firstcode.R;
import java.io.File;
public class VideoActivity extends AppCompatActivity implements View.OnClickListener {
private VideoView videoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);
Button play = findViewById(R.id.play);
Button pause = findViewById(R.id.pause);
Button replay = findViewById(R.id.replay);
videoView = findViewById(R.id.video_view);
play.setOnClickListener(this);
pause.setOnClickListener(this);
replay.setOnClickListener(this);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}else {
initVideoPath();
}
}
private void initVideoPath() {
File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
videoView.setVideoPath(file.getPath());
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initVideoPath();
}else {
Toast.makeText(this, "请获取存储权限", Toast.LENGTH_SHORT).show();
finish();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!videoView.isPlaying()) {
videoView.start();
}
break;
case R.id.pause:
if (videoView.isPlaying()) {
videoView.pause();
}
break;
case R.id.replay:
if (videoView.isPlaying()) {
videoView.resume();//重新播放
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (videoView != null) {
videoView.suspend();//释放资源
}
}
}
xml文件:
郭霖总结:
本章我们主要对Android系统中的各种多媒体技术进行了学习,其中包括通知的使用校在模调用摄像头拍照从相册中选取照片, 以及播放香城和视频文件。由于所涉及的多媒体技术住快拟器上很难看得到效果,因此本章中还特意讲解了在Android手机上调试程序的方法。
又是充实饱满的一章啊!现在多媒体方面的知识已经学得足够多了,我希望你可以很好地将它们消化掉,尤其是与通知相关的内容,因为后面的学习当中还会用到它。目前我们所学的所有东西都仅仅是在本地上进行的,而实际上几乎市场上的每个应用都会涉及网络交互的部分,所比下一章中我们将会学习一下Android网络编程方面的内容。
我的总结:
在调用摄像头和相册这一点,我也是学到了非常多的东西,平时因为用一些框架,很少回去研究这些东西,如今算是学到了这些我们必要的一些知识。
因为MediaPlayer 主要是在音乐相关的项目上用到,所以也多了一些印象,VideoView的话 他在视频格式的支持以及播放效率方面都存在这较大的不足,所以建议我们只是用于播放一些游戏的片头动画,或者某个应用的视频宣传等。。