提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录- 使用通知
- 通知的基本用法
- 通知的点击----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(); // } // } //}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)