Android学习笔记之多媒体

Android学习笔记之多媒体,第1张

Android学习笔记之多媒体 使用多媒体 通知

8.0+引入通知渠道

创建通知渠道

一旦创建,其重要性不可修改,HIGH是d出横幅,MIN是没通知栏小图标

NotificationManager manager= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);//获取通知管理器,在管理器上 *** 作
    if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){//如果当前API版本>=8.0(8.0代号为字母O)
        NotificationChannel channel=new NotificationChannel("normal","Normal",NotificationManager.importANCE_DEFAULT);//创建通知渠道,参数为(渠道id,渠道名,重要性)
        manager.createNotificationChannel(channel);//添加到通知管理器
    }

创建点击通知后的跳转

Intent是立即执行,PendingIntent相当于延迟执行的Intent

方式一:

点击通知后跳转到AnotherActivity,再按返回键就会回到桌面

Intent intent = new Intent(this, AnotherActivity.class);
//参数为(上下文,请求码,Intent,flags)
PendingIntent pending = PendingIntent.getActivity(this, 0, intent, 0);

方式二:

点击通知后跳转到AnotherActivity,再按返回键会进入MainActivity

 
​
//创建1个任务栈构建器
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
//将在Manifest中指定好的父Activity加入到构建器中
stackBuilder.addParentStack(AnotherActivity.class);
//给构建器设定未来会发生的任务:执行intent
stackBuilder.addNextIntent(intent);
//得到要执行的任务intent的pending版本
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, 0);

创建通知并发送

Button button=findViewById(R.id.button);
button.setonClickListener((View v)->{
    Notification notification= new NotificationCompat.Builder(this,"normal")//使用compat可以兼容所有安卓版本,参数为(上下文,渠道id)
            .setContentTitle("通知标题")
            .setContentText("通知内容")
            .setSmallIcon(R.drawable.xxx)
            .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.xxx))//将图片解析为Bitmap对象
            .setContentIntent(pending)//点击通知后跳转到的页面
            .setAutoCancel(true)//点击通知后通知消失(或者是在AnotherActivity中写manager.cancel(1))
            .build();//创建通知对象
​
    manager.notify(1,notification);//通过管理器发送通知,参数为(通知id,通知对象)
});

还可以通过setStyle()指定更多样式,如大量文字,大图片,同一应用通知折叠InboxStyle,多媒体

.setStyle(new NotificationCompat.BigTextStyle().bigText("很长的一段文字"))

取消通知

//所有通知全部消失!!
manager.cancelAll();
调用相机

调用摄像头拍照并保存

public class MainActivity extends AppCompatActivity {
​
    public static String authority = "com.example.cameraalbumtest.fileprovider";
    ActivityMainBinding binding;
    Uri imageUri;
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.button.setonClickListener((View v) -> {
​
            //先在代码中新建File对象,意为预期在当前应用在内置SD卡中的沙盒cache目录创建output_image.jpg
            File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
            if (outputImage.exists()) {//存在则删除
                outputImage.delete();
            }
            try {
                outputImage.createNewFile();//不存在则创建
            } catch (IOException e) {
                e.printStackTrace();
            }
​
            
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //Android 7.0+ File→Uri要使用这种方式,因为content URI更安全(content://...)
                //此步骤需要为本应用创造一个Authority为"包名.fileprovider"的ContentProvider
                //FileProvider是一种特殊的ContentProvider,其getUriForFile()方法获得file的content URI
                imageUri = FileProvider.getUriForFile(this, authority, outputImage);
            } else {
                //低版本使用file URI(file://...)
                Uri.fromFile(outputImage);
            }
​
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);将拍到的照片转存到指定Uri
            startActivityForResult(intent, 1);
        });
    }
​
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1) {
            //如果成功,说明在我们指定的imageUri处已经有了新拍的照片文件
            if (resultCode == RESULT_OK) {
                try {
                    //Uri→InputStream→Bitmap
                    //ContentResolver中的openInputStream(Uri uri)是一种把给定的Uri→InputStream方式
                    Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                    binding.imageView.setImageBitmap(bitmap);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

因为创建了ContentProvider,所以要注册

因为要使用content://uri替代file://uri,那么,content://的uri如何定义呢?总不能使用文件路径,因为目的就是安全,不暴露真实路径

所以,需要一个虚拟的路径对文件路径进行映射,所以需要编写个xml文件,通过path以及xml节点确定可访问的目录,通过name属性来映射真实的文件路径

//是否允许授权文件的临时访问权限
    

file_paths支持的节点:

当这么声明以后,代码可以使用你所声明的当前文件夹以及其子文件夹

ValuePathroot-path/files-path/data/data/<包名>/filescache-path/data/data/<包名>/cacheexternal-path/storage/emulate/0external-files-path/storage/emulate/0/Android/data/<包名>/filesexternal-cache-path/storage/emulate/0/Android/data/<包名>/cache

这里我们在xml目录下创建file_paths的内容

//每个节点都支持两个属性:name+path
//path:需要临时授权访问的路径(.或/代表所有路径) 
//name:就是你给这个访问路径起个名字

    
调用相册
binding.photo.setonClickListener((View v) -> {
    Intent intent = new Intent(Intent.ACTION_OPEN_document);
    intent.addCategory(Intent.CATEGORY_OPENABLE);//源码中说这两个是必须指定的
    intent.setType("image*,image/*,documents/*,audio/*,...)
    startActivityForResult(intent, 2);
});

BitmapFactory.decodeFileDescriptor似乎比BitmapFactory.decodeStream占用内存更小

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    ...
    else if (requestCode == 2) {
        if (resultCode == RESULT_OK && data != null) {
            Bitmap bitmap = null;
            try {
                Uri uri = data.getData();//返回的就是选择的文件content URI
                FileDescriptor fd = getContentResolver().openFileDescriptor(uri, "r").getFileDescriptor();
                bitmap = BitmapFactory.decodeFileDescriptor(fd);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            binding.imageView.setImageBitmap(bitmap);
        }
    }
}
播放音频

在main包下新建assets文件夹

API特点MediaPlayer其他情况SoundPool适用于APP经常需要播放固定的,密集的,短促的音效;CPU占用率低,延迟小;可以自行设定声音品质音量等;支持多个音频同时播放

MediaPlayer

start()对应开始

pause()对应暂停

reset()对应停止

stop()+release()对应程序结束

 

MediaPlayer mMediaPlayer = new MediaPlayer();
AssetManager assetManager;
​
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
        
    assetManager = getAssets();
    initMediaPlayer();
​
    binding.play.setonClickListener((View v) -> {
        if (!mMediaPlayer.isPlaying())
            mMediaPlayer.start();
    });
​
    binding.pause.setonClickListener((v) -> {
        if (mMediaPlayer.isPlaying())
            mMediaPlayer.pause();
    });
​
    binding.stop.setonClickListener((v) -> {
        mMediaPlayer.reset();
        //停止播放后,准备好下一次播放的资源
        initMediaPlayer();
    });
}
​
public void initMediaPlayer() {
    try {
        AssetFileDescriptor afd = assetManager.openFd("music.mp3");
        FileDescriptor fd = afd.getFileDescriptor();
        //setDataSource()的其它重载也可以
        mMediaPlayer.setDataSource(fd, afd.getStartOffset(), afd.getLength());
        mMediaPlayer.prepare();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
​
@Override
protected void onDestroy() {
    ...
    //释放资源
    mMediaPlayer.stop();
    mMediaPlayer.release();
}

SoundPool

具体应用见BeatBox项目

//音频属性,指定音频的用途
AudioAttributes audioAttributes = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .build();
​
//声音池
SoundPool mSoundPool = new SoundPool.Builder()
        .setMaxStreams(5)//最多容纳多少个音频流,设置太多小心内存限制
        .setAudioAttributes(audioAttributes)
        .build();

加载进声音池

AssetFileDescriptor afd=mAssetManager.openFd("music.mp3");
//把音频文件载入声音池
int soundId=mSoundPool.load(afd,1);//这个soundId播放要用,需要保留
afd.close();

播放的时候需要指定soundId,我这里将它放入了Sound对象

int soundId = sound.getSoundId();
int streamId = mSoundPool.play(soundId, 1.0f, 1.0f, 1, 0, 1.0f);//可以指定左右音量,循环,倍速等播放属性
mSoundPool.pause(streamId);//暂停播放

最后要释放内存

mSoundPool.release();
播放视频

VideoView本质上是MediaPlayer的封装

对视频格式的支持以及播放效率方面还存在着不足

 

Uri uri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.video);//固定写法
binding.videoView.setVideoURI(uri);
​
binding.play.setonClickListener((v) -> {
    if (!binding.videoView.isPlaying())
        binding.videoView.start();//播放
});
​
binding.pause.setonClickListener((v) -> {
    if (binding.videoView.isPlaying())
        binding.videoView.pause();//暂停
});
​
binding.replay.setonClickListener((v) -> {
    binding.videoView.resume();//重播
});

最后释放内存

binding.videoView.suspend();

tips:获取视频资源Uri的Kotlin写法为

Uri uri = Uri.parse("android.resource://$packageName/${R.raw.video}");

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5708766.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存