
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支持的节点:
当这么声明以后,代码可以使用你所声明的当前文件夹以及其子文件夹
这里我们在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文件夹
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}");欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)