提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录- 使用通知
- 通知的基本用法
- 通知的点击----PendingIntent
- 通知的高级功能
- 调用摄像头和相册
- 调用摄像头拍照
- 从相册中选择照片
- 播放多媒体文件
- 播放音频
- 播放视频
使用通知
通知(Notification)是Android系统中比较有特色的一个功能,当某个应用程序希望向用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知来实现。发出一条通知后,手机最上方的状态栏中会显示一个通知的图标,下拉状态栏后可以看到通知的详细内容
通知的基本用法首先需要一个NotificationManager来对通知进行管理,可以调用Context的getSystemService()方法获取到。
getSystemService()方法接收一个字符串参数用于确定获取系统的哪个服务,这里我们传入NOTIFICATION_SERVICE即可。因此,获取NotificationManager的实例就可以写成:
NotificationManager manager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
接下来需要NotificationChannel。构造方法需要三个参数,ChannelId是自定义的字符串;第二个参数是频道的名称;第三个是优先级。创建完NotificationChannel之后,还需要使用createNotificationChannels方法注册到系统中
NotificationChannel mchannel=new NotificationChannel("channelid1","test",NotificationManager.importANCE_HIGH);
manager.createNotificationChannel(mchannel);
接下来,setContentTitle()方法用于指定通知的标题内容,下拉系统状态栏就可以看到这部分内容。setContentText()方法用于指定通知的正文内容,同样下拉系统状态栏就可以看到这部分内容。setWhen()方法用于指定通知被创建的时间,以毫秒为单位,当下拉系统状态栏时,这里指定的时间会显示在相应的通知上。setSmallIcon()方法用于设置通知的小图标,注意只能使用纯alpha图层的图片进行设置,小图标会显示在系统状态栏上。setLargeIcon()方法用于设置通知的大图标,当下拉系统状态栏时,就可以看到设置的大图标了。
NotificationCompat.Builder builder=new NotificationCompat.Builder(MainActivity.this,"channelid1");
builder.setContentTitle("this is content title");
builder.setContentText("this is content text");
builder.setWhen(System.currentTimeMillis());
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
以上工作都完成之后,只需要调用NotificationManager的notify()方法就可以让通知显示出来了
manager.notify(1,builder.build());通知的点击----PendingIntent
PendingIntent从名字上看起来就和Intent有些类似,它们之间也确实存在着不少共同点。比如它们都可以去指明某一个“意图”,都可以用于启动活动、启动服务以及发送广播等。不同的是,Intent更加倾向于去立即执行某个动作,而PendingIntent更加倾向于在某个合适的时机去执行某个动作。所以,也可以把PendingIntent简单地理解为延迟执行的Intent。
PendingIntent的用法同样很简单,它主要提供了几个静态方法用于获取PendingIntent的实例,可以根据需求来选择是使用getActivity()方法、getBroadcast()方法,还是getService()方法。这几个方法所接收的参数都是相同的,第一个参数依旧是Context,不用多做解释。第二个参数一般用不到,通常都是传入0即可。第三个参数是一个Intent对象,我们可以通过这个对象构建出PendingIntent的“意图”。第四个参数用于确定PendingIntent的行为,有FLAG_ONE_SHOT、FLAG_NO_CREATE、FLAG_CANCEL_CURRENT和FLAG_UPDATe_CURRENT这4种值可选,每种值的具体含义你可以查看文档,通常情况下这个参数传入0就可以了。
Intent intent=new Intent(this,NotificationActivity.class); PendingIntent pi=PendingIntent.getActivity(this,0,intent,0); ... builder.setContentIntent(pi);
点击就会跳转到新的Activity
但是通知图标还没有消失,该如何解决?
第一种 在builder后连缀一个setAutoCancel()方法
builder.setAutoCancel(true);
第二种显示的调用NotificationManager对象的cancel()方法
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); manager.cancel(1);通知的高级功能
setStyle()这个方法允许我们构建出富文本的通知内容
通知内容文字过长的效果
builder.setStyle(new NotificationCompat.BigTextStyle().bigText("Learn how to build notifications, send and sync data, and use voice actions. Get the official Android IDE and developer tools to build apps for Android."));
setPriority()可以用于设置通知的重要程度
一共有5个常量值可选:
PRIORITY_DEFAULT表示默认的重要程度,和不设置效果是一样的;
PRIORITY_MIN表示最低的重要程度,系统可能只会在特定的场景才显示这条通知,比如用户下拉状态栏的时候;
PRIORITY_LOW表示较低的重要程度,系统可能会将这类通知缩小,或改变其显示的顺序,将其排在更重要的通知之后;PRIORITY_HIGH表示较高的重要程度,系统可能会将这类通知放大,或改变其显示的顺序,将其排在比较靠前的位置;PRIORITY_MAX表示最高的重要程度,这类通知消息必须要让用户立刻看到,甚至需要用户做出响应操作
新建一个CameraAlbumTest项目,然后修改activity_main.xml中的代码,如下所示:
只有两个控件,一个Button和一个ImageView。Button是用于打开摄像头进行拍照的,而ImageView则是用于将拍到的图片显示出来。
开始编写调用摄像头的具体逻辑,修改MainActivity中的代码
package com.example.cameraalbumtest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;
private ImageView picture;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取到Button和ImageView的实例,并给Button注册上点击事件
Button takePhoto=findViewById(R.id.take_photo);
picture=findViewById(R.id.picture);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//创建File对象,用于存储拍照后的图片
//图片命名为output_image.jpg
//将它存放在手机SD卡的应用关联缓存目录,调用getExternalCacheDir()方法可以得到这个目录
File outputImage=new File(getExternalCacheDir(),"output_image.jdp");
try{
if(outputImage.exists()){
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//判断设备的系统版本是否高于Android7.0
if(Build.VERSION.SDK_INT>24){
//调用FileProvider的getUriForFile()方法将File对象转换成一个封装过的Uri对象
//因为从Android 7.0系统开始,直接使用本地真实路径的Uri被认为是不安全的,
// 会抛出一个FileUriExposedException异常。
// 而FileProvider则是一种特殊的内容提供器,
// 它使用了和内容提供器类似的机制来对数据进行保护,
// 可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。
imageUri= FileProvider.getUriForFile(MainActivity.this,"com.example.android.choosepicdemo.fileprovider",outputImage);
}else{
//低于7.0版本调用Uri的fromFile()方法将File对象转换成Uri对象
//这个Uri对象标识着output_image.jpg这张图片的本地真实路径
imageUri=Uri.fromFile(outputImage);
}
//启动相机程序
Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");
//Intent的putExtra()方法指定图片的输出地址
intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
startActivityForResult(intent,TAKE_PHOTO);
}
});
}
@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{
//调用BitmapFactory的decodeStream()方法将output_image.jpg这张照片解析成Bitmap对象,
// 然后把它设置到ImageView中显示出来。
Bitmap bitmap= BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
}
刚才提到了内容提供器,那么我们自然要在AndroidManifest.xml中对内容提供器进行注册了,如下所示:
另外,这里还在标签的内部使用来指定Uri的共享路径,并引用了一个@xml/file_paths资源
右击res目录→New→Directory,创建一个xml目录,接着右击xml目录→New→File,创建一个file_paths.xml文件。然后修改file_paths.xml文件中的内容,如下所示:
从相册中选择照片
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import android.Manifest;
import android.app.Activity;
import android.content.ContentUris;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Path;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.documentsContract;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
//通过调用摄像头
public static final int TAKE_PHOTO = 1;
private ImageView picture;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取到Button和ImageView的实例,并给Button注册上点击事件
Button takePhoto=findViewById(R.id.take_photo);
picture=findViewById(R.id.picture);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//创建File对象,用于存储拍照后的图片
//图片命名为output_image.jpg
//将它存放在手机SD卡的应用关联缓存目录,调用getExternalCacheDir()方法可以得到这个目录
File outputImage=new File(getExternalCacheDir(),"output_image.jdp");
try{
if(outputImage.exists()){
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//判断设备的系统版本是否高于Android7.0
if(Build.VERSION.SDK_INT>24){
//调用FileProvider的getUriForFile()方法将File对象转换成一个封装过的Uri对象
//因为从Android 7.0系统开始,直接使用本地真实路径的Uri被认为是不安全的,
// 会抛出一个FileUriExposedException异常。
// 而FileProvider则是一种特殊的内容提供器,
// 它使用了和内容提供器类似的机制来对数据进行保护,
// 可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。
imageUri= FileProvider.getUriForFile(MainActivity.this,"com.example.android.choosepicdemo.fileprovider",outputImage);
}else{
//低于7.0版本调用Uri的fromFile()方法将File对象转换成Uri对象
//这个Uri对象标识着output_image.jpg这张图片的本地真实路径
imageUri=Uri.fromFile(outputImage);
}
//启动相机程序
Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");
//Intent的putExtra()方法指定图片的输出地址
intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
startActivityForResult(intent,TAKE_PHOTO);
}
});
Button chooseFromAlbum=findViewById(R.id.choose_from_album);
chooseFromAlbum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
}else{
Log.d("tag","edg");
openAlbum();
}
}
});
}
@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{
//调用BitmapFactory的decodeStream()方法将output_image.jpg这张照片解析成Bitmap对象,
// 然后把它设置到ImageView中显示出来。
Bitmap bitmap= BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
case CHOOSE_PHOTO:
if(resultCode==RESULT_OK){
//判断手机系统版本号
if(Build.VERSION.SDK_INT>=19){
Log.d("tag","666");
handleImageOnkitkat(data);
}else{
handleImageBeforeKitKat(data);
}
}
default:
break;
}
}
//通过访问图库
public static final int CHOOSE_PHOTO = 2;
private void openAlbum(){
Intent intent=new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent,CHOOSE_PHOTO);
}
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openAlbum();
} else {
Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
private void handleImageOnkitkat(Intent data){
String imagePath=null;
Uri uri=data.getData();
if(documentsContract.isdocumentUri(this,uri)){
String docId=documentsContract.getdocumentId(uri);
if("com.android.providers.media.documents".equals(uri.getAuthority())){
String id=docId.split(":")[1];
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 void handleImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(uri, null);
displayImage(imagePath);
}
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 String getImagePath(Uri uri, String selection) {
String path=null;
Cursor cursor=getContentResolver().query(uri,null,selection,null,null);
if(cursor!=null){
if(cursor.moveToFirst()){
path=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
}
cursor.close();
}
return path;
}
}
如果出现权限不允许的情况下,需要在AndroidManifest.xml文件上添加
选择照片后无法显示出来,还有如何解决super.onActivityResult()的办法
我们需要去build.gradle修改下面内容,降低版本即可使用OnActivityResult的第二种方法(不调用super)
在Android中播放音频文件一般都是使用MediaPlayer类来实现的,它对多种格式的音频文件提供了非常全面的控制方法,从而使得播放音乐的工作变得十分简单。下表列出了MediaPlayer类中一些较为常用的控制方法。
新建一个PlayAudioTest项目,然后修改activity_main.xml中的代码,如下所示:
在app/src/main->new->Directory 创建“assets” ,添加音频MP3进去, 修改MainActivity中的代码,如下所示:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private MediaPlayer mediaPlayer = new MediaPlayer();
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button play = (Button) findViewById(R.id.play);
Button pause = (Button) findViewById(R.id.pause);
Button stop = (Button) findViewById(R.id.stop);
play.setOnClickListener(this);
pause.setOnClickListener(this);
stop.setOnClickListener(this);
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission. WRITE_EXTERNAL_STORAGE }, 1);
} else {
initMediaPlayer(); // 初始化MediaPlayer
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
private void initMediaPlayer() {
try {
//File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");
AssetManager assetManager=getAssets();
AssetFileDescriptor path=assetManager.openFd("music.mp3");
mediaPlayer.setDataSource(path); // 指定音频文件的路径
mediaPlayer.prepare(); // 让MediaPlayer进入到准备状态
} catch (Exception e) {
e.printStackTrace();
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initMediaPlayer();
} else {
Toast.makeText(this, "拒绝权限将无法使用程序", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
}
}
@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;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
}
当点击Play按钮时会进行判断,如果当前MediaPlayer没有正在播放音频,则调用start()方法开始播放。当点击Pause按钮时会判断,如果当前MediaPlayer正在播放音频,则调用pause()方法暂停播放。当点击Stop按钮时会判断,如果当前MediaPlayer正在播放音频,则调用reset()方法将MediaPlayer重置为刚刚创建的状态,然后重新调用一遍initMediaPlayer()方法。
最后在onDestroy()方法中,我们还需要分别调用stop()方法和release()方法,将与MediaPlayer相关的资源释放掉。
播放视频使用VideoView类来实现的。这个类将视频的显示和控制集于一身,使得我们仅仅借助它就可以完成一个简易的视频播放器
目前找不到合适的解决办法,一直处于视频无法播放…
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.widget.VideoView;
import java.io.File;
import java.io.IOException;
//public class MainActivity extends AppCompatActivity implements View.OnClickListener{
//
// private VideoView videoView;
// @Override
// protected void onCreate(Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
// videoView=findViewById(R.id.video_view);
// Button play = (Button) findViewById(R.id.play);
// Button pause = (Button) findViewById(R.id.pause);
// Button replay = (Button) findViewById(R.id.replay);
// play.setonClickListener(this);
// pause.setonClickListener(this);
// replay.setonClickListener(this);
// if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission. WRITE_EXTERNAL_STORAGE }, 1);
// } else {
// try {
// initVideoPath(); // 初始化VideoView
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// }
//
// private void initVideoPath() throws IOException {
AssetManager assetManager=getAssets();
AssetFileDescriptor path=assetManager.openFd("movie.mp4");
// File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
// videoView.setVideoPath(file.getPath());
// }
//
// public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// switch (requestCode) {
// case 1:
// if (grantResults.length > 0 && grantResults[0] == PackageManager.
// PERMISSION_GRANTED) {
// try {
// initVideoPath();
// } catch (IOException e) {
// e.printStackTrace();
// }
// } else {
// Toast.makeText(this, "拒绝权限将无法使用程序", Toast.LENGTH_SHORT).show();
// finish();
// }
// break;
// default:
// }
// }
// @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;
// }
// }
// protected void onDestroy() {
// super.onDestroy();
// if (videoView != null) {
// videoView.suspend();
// }
// }
//}



