Android之多媒体技术

private void updateSeekBar() {

//6. 获取音乐文件的总时长 Gets the duration of the file.

final int duration = mediaPlayer.getDuration();

//7. 构造定时器

Timer timer = new Timer();

//7.1 创建任务

TimerTask timerTask = new TimerTask() {

@Override

public void run() {

//8. 获取歌曲的当前进度

int currentPosition = mediaPlayer.getCurrentPosition();

//9. 通过handler发送歌曲的信息到Activity更新UI

//9.1 通过将数据封装到Message中

Message msg = new Message();

//9.2 封装多条数据到Message中 将那些数据封装到Bundle中,其实Bundle底层就是Map

Bundle bundle = new Bundle();

bundle.putInt(“duration”, duration);

bundle.putInt(“currentPosition”, currentPosition);

msg.setData(bundle);

//10. 发送数据

MainActivity.handler.sendMessage(msg);

}

};

//7.2 300毫秒后 每隔1秒执行一次任务

timer.schedule(timerTask, 300, 1000); //每隔1秒获取歌曲的进度

}

  1. 在服务中添加一个播放进度的方法

/**

  • 设置播放音乐指定位置的方法

  • @param position 该位置由进度条拖动时提供

*/

private void seekToPosition(int position){

mediaPlayer.seekTo(position);

}

  1. 通过handler将数据传递到Activity更新UI

  2. SeekBar处理数据

sb_seekm.setMax(duration); //设置进度条最大值

sb_seekm.setProgress(currentPosition); //设置进度条当前进度

7. SurfaceView介绍

=================

  • SurfaceView控件是一个重量级控件

  • 内部维护了2个线程

  • A 获取数据 负责显示

  • B 负责显示 获取数据

  • 它直接可以在子线程更新UI 与进度相关的控件可以直接在子线程更新Ui

//找到控件

final SurfaceView sfv = (SurfaceView) findViewById(R.id.sfv);

final SurfaceHolder surfaceHolder = sfv.getHolder();

//添加一个callback

surfaceHolder.addCallback(new Callback() {

//当surfaceview销毁的时候调用

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

System.out.println(“surfaceDestroyed”);

if (player!=null && player.isPlaying()) {

//获取当前视频播放的位置

currentPosition = player.getCurrentPosition();

player.stop();

}

}

//当surfaceview 初始化了

@Override

public void surfaceCreated(SurfaceHolder holder) {

//[1]初始化mediaplayer

player = new MediaPlayer();

//[2]设置要播放的资源 path 可以是本地也可是网络路径

try {

player.setDataSource(“http://192.168.13.89:8080/cc.MP4”);

//[2.1]设置播放视频的内容 SurfaceHolder 是用来维护视频播放的内容

player.setDisplay(surfaceHolder);

//[3]准备播放

// player.prepare();

player.prepareAsync();

//设置一个准备完成的监听

player.setOnPreparedListener(new OnPreparedListener() {

@Override

public void onPrepared(MediaPlayer mp) {

//[4]开始播放

player.start();

//[5]继续上次的位置继续播放

player.seekTo(currentPosition);

}

});

} catch (Exception e) {

e.printStackTrace();

}

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

}

});

补充1 VideoView

  • 这个控件就是对SurfaceView和MediaPlayer进行封装

  • MediaPlayer 播放视频只支持3gp mp4格式

  • 如果只是播放一些游戏的片头动画,或者某个应用的视频宣传,使用VideoView还是绰绰有余的.

补充2 vitamio框架

vitamio框架是开源的,可以播放大多数视频格式的框架.

8. 照相和录像

=========

// create Intent to take a picture and return control to the calling

// application

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

File file = new File(Environment.getExternalStorageDirectory(),

“1.png”);

intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));

// start the image capture Intent

startActivityForResult(intent, 1);

9. 调用摄像头拍照并显示

==============

下面的demo如果需要加载大图片,其实严谨的来说,应该加如图片缩放.有时候拍的照片太大了,以至于无法加载,程序报错.

  1. 首先我们决定将照片放到sd卡的应用缓存目录下,通过getExternalCacheDir()可以得到这个目录(具体的路径是/sdcard/Android/data/<package name>/cache).因为从Android6.0开始,读写SD卡被列为危险权限,如果将图片存放在SD卡的任何其他目录,都要进行运行时权限处理才行,而使用管理目录可以跳过这一步.

  2. 如果运行设备的系统版本低于Android 7.0,就调用Uri.fromFile()方法将File对象转换成Uri对象,这个Uri对象标识着图片的本地真实路径.

否则,就调用FileProvider的getUriForFile()方法将File对象转换成一个封装过的Uri对象.

之所以要进行这样一层转换,是因为从Android 7.0开始,直接使用本地真实路径的Uri被认为是不安全的,会抛出FileUriExposedException异常.而FileProvider则是一种特殊的内容提供器,它使用了和内容提供器类似的机制来对数据进行保护,可以选择性的将封装过的Uri共享给外部,从而提高了应用的安全性.

既然是内容提供器,则需要到清单文件中配置,具体配置如下:

<provider

android:authorities=“com.xfhy. 《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》无偿开源 徽信搜索公众号【编程进阶路】 cameraalbumtest.fileprovider”

android:name=“android.support.v4.content.FileProvider”

android:exported=“false”

android:grantUriPermissions=“true”>

<meta-data

android:name=“android.support.FILE_PROVIDER_PATHS”

android:resource=“@xml/file_paths”

/>

还需要在res目录下创建xml文件夹,然后新建File,file_paths.xml文件.写入如下内容:

<?xml version="1.0" encoding="utf-8"?>

其中external-path是用来指定Uri共享的,name属性的值可以随便填,path属性的值表示共享的具体路径,这里设置为空值表示将整个SD卡进行共享

还有一点需要注意,在Android 4.4系统之前,访问SD卡的应用关联目录也是要声明权限的,从4.4系统开始不再需要权限申明.那么我们为了能够兼容老版本的系统的手机,需要在清单文件中申明如下权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

3.下面是具体的代码实现:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private static final int TAKE_PHOTO = 1;

private static final String TAG = “MainActivity”;

private Button bt_take_photo; //拍照按钮

private Button bt_choose_from_album;

private ImageView iv_picture; //显示图片

private Uri imageUri; //标示图片路径的uri

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

bt_take_photo = (Button) findViewById(R.id.bt_take_photo);

bt_choose_from_album = (Button) findViewById(R.id.bt_choose_from_album);

iv_picture = (ImageView) findViewById(R.id.iv_picture);

bt_take_photo.setOnClickListener(this);

bt_choose_from_album.setOnClickListener(this);

}

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.bt_take_photo:

takePhoto();

break;

case R.id.bt_choose_from_album:

break;

default:

break;

}

}

/**

  • 调用摄像头拍照

*/

private void takePhoto() {

//1. 创建File对象,用于存储拍照后的图片

//这里的getExternalCacheDir()是应用的关联缓存目录,在SD卡下面(/sdcard/Android/data//cache)

//这里在Android 6.0运行时不用进行运行时权限处理

File outputImage = new File(getExternalCacheDir(), “output_image.jpg”);

//2. 判断文件是否存在

try {

if (outputImage.exists()) {

outputImage.delete();

outputImage.createNewFile();

}

} catch (IOException e) {

e.printStackTrace();

}

//3. 判断当前用户的设备的系统版本是否大于24(android 7.0)

if (Build.VERSION.SDK_INT >= 24) {

//4. 将File对象转化为一个封装好的Uri对象

imageUri = FileProvider.getUriForFile(MainActivity.this,

“com.xfhy.cameraalbumtest.fileprovider”,outputImage);

} else {

imageUri = Uri.fromFile(outputImage);

}

//5.启动相机程序

Intent intent = new Intent(“android.media.action.IMAGE_CAPTURE”);

intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);

startActivityForResult(intent,TAKE_PHOTO);

}

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

//请求码

switch (requestCode){

case TAKE_PHOTO:

//如果返回码是RESULT_OK,则是成功拍照了的

if(resultCode == RESULT_OK){

try {

//6. 将拍摄的照片显示出来

Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));

iv_picture.setImageBitmap(bitmap); //设置显示图片

Log.i(TAG, "onActivityResult: ");

} catch (FileNotFoundException e) {

e.printStackTrace();

}

}

break;

default:

break;

}

}

}

10. 从相册选择照片

============

读取相册中的照片,是需要申请读取SD卡权限.

根据系统版本是否是Android 4.4以上,有2种处理方式.之所以要这样做,是因为Android系统从4.4版本开始,选取相册中的图片不再返回图片的真实Uri了,而是一个封装过的Uri,因此如果是4.4版本以上的手机就需要对这个版本进行解析才行.

下面是demo

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

/**

  • 申请码

*/

private static final int TAKE_PHOTO = 1; //照相

private static final int CHOOSE_PHOTO = 2; //打开相册

private static final String TAG = “MainActivity”;

private Button bt_take_photo; //拍照按钮

private Button bt_choose_from_album;

private ImageView iv_picture; //显示图片

private Uri imageUri; //标示图片路径的uri

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

bt_take_photo = (Button) findViewById(R.id.bt_take_photo);

bt_choose_from_album = (Button) findViewById(R.id.bt_choose_from_album);

iv_picture = (ImageView) findViewById(R.id.iv_picture);

bt_take_photo.setOnClickListener(this);

bt_choose_from_album.setOnClickListener(this);

}

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.bt_take_photo:

takePhoto();

break;

case R.id.bt_choose_from_album:

requestPermission();

break;

default:

break;

}

}

/**

  • 申请权限 需要选择相册中的图片,则需要读SD卡的权限

*/

private void requestPermission() {

//检查是否有读SD卡的权限 不相等则需要申请权限

if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)

!= PackageManager.PERMISSION_GRANTED) {

//申请读SD的权限

ActivityCompat.requestPermissions(MainActivity.this,

new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);

} else {

openAlbum();

}

}

/**

  • 打开相册 进行图片选择

*/

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) {

switch (requestCode) { //根据申请码进行判断

case 1:

//判断权限是否申请成功

if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

openAlbum();

} else {

Toast.makeText(this, “申请读SD卡权限失败”, Toast.LENGTH_SHORT).show();

}

break;

default:

break;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值