使用通知
我们可以在Activity中、BroadcastReceiver以及Service中创建通知,不论在哪里创建,整体步骤是相同的,下面通过示例演示:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 
 | NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
 
 
 
 Intent intent = new Intent(MainActivity.this,SecondActivity.class);
 
 PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);
 
 
 
 
 Notification notification = new NotificationCompat.Builder(context)
 .setContentTitle("title")
 .setContentText("content")
 .setSound(Uri.from(""))
 
 
 
 .setVibrate(new long[]{0,1000,1000,1000})
 .setWhen(System.currentMillis())
 .setSmallIcon(R.drawable.small_icon)
 .setLargeIcon(BitmapFactory.decodeResource(gerResources(),R.drawable.large_icon))
 .setContentIntent(pi)
 
 
 
 .setLights(Color.GREEN,1000,1000)
 .setAutoCancel(true)
 
 
 .setStyle(new NotificationCompat.BigTextStyle().bigText("fdasfdsafdsafdafdasfsdafadsfdsfasdffasdfdsfdsfsda"))
 
 
 .setPriority(NotificationCompat.PRIORITY_MAX)
 .build();
 
 
 manager.notify(1,notification);
 
 
 
 | 
调用摄像头和相册
平时使用QQ或者微信的时候经常要别人分享图片,这些图片可以使手机摄像头拍摄也可以从相册中选取,这种功能非常普遍。
摄像头拍照
直接上代码展示可能更加清晰:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 
 | takePhoto.setOnclickListener(new View.OnclickListener(){@Override
 public void onClick(View v){
 
 File outputImage = new File(getExternalCacheDir(),"output.jpg");
 try{
 if(outputImage.exists()){
 outputImage.delete();
 }
 outputImage.createNewFile();
 }catch(IOException e){
 
 }
 
 if(Build.VERSION.SDK_INT >= 24){
 imageUri = FileProvider.getUriForFile(MainActivity.this,
 "com.example.fileprovider",outputImage);
 
 }else{
 imageUri = Uri.fromFile(outputImage);
 }
 
 
 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:
 if(resultCode == RESULT_OK){
 try{
 
 Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver()
 .openInputStream(imageUri));
 ivPic.setImageBitmap(bitmap);
 }catch (FileNotFoundException e){
 
 }
 }
 
 break;
 }
 }
 
 
 | 
上面的代码中我们用了内容提供器,因此还需要在AndroidManifest.xml中声明这个提供器(有一点要注意的是,在4.4以前(4.4及以后不需要)访问SD卡得应用关联目录也是要声明权限的,为了兼容老版本的手机,需要声明 WRITE_EXTERNAL_STORAGE 权限):
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | <users-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><application
 android:icon="@mipmap/ic_launcher"
 ...
 android:theme="@style/AppTheme">
 
 <privider
 <!--这里,android:name属性的值是固定的,android:authorities属性的值必须要和刚才FileProvider.getUriForFile()-->
 
 android:name="android.support.v4.content.FileProvider"
 android:authorities="com.example.fileprovider"
 android:exported="false"
 android:grantUriPermissions="true">
 <meta-data
 android:name="android.support.FILE_PROVIDER_PATHS"
 android:resource="@xml/file_paths"/>
 
 </application>
 
 
 | 
当然,provider声明中使用了@xml/file_paths资源,这个资源我们还没创建,因此在res目录下可以创建这么个xml,内容如下:
| 12
 3
 4
 5
 6
 7
 
 | <?xml version="1.0" encoding="utf-8"><paths xmlns:android="http://schemas.android.com/apk/res/android">
 <!--这里面external-path指定Uri共享的,name属性随便填,path属性表示共享的具体路径,这里设置空值就表示将整个SD卡进行共享-->
 <!--当然,你可以仅仅共享我们存放output.jpg这张图片的路径-->
 <external-path name="my_images" path="">
 </paths>
 
 
 | 
以上整个代码首先创建了一个File对象,用于存放摄像头拍下的图片,我们将其命名为output.jpg,并将它存放在手机SD卡的应用关联缓存目录(指SD卡中专门用于存放当前应用缓存数据的位置,路径为/sdcard/Android/data//cache,调用getExternalCacheDir()方法就可以得到这个目录)下。为什么使用应用关联缓存目录来存放图片呢?因为从Android 6.0开始,读写SD卡被列为危险权限,如果将图片存放SD卡得任何其他目录,都要进行运行时权限处理才行,而使用应用关联目录则可以跳过这一步。  
接着会判断如果设备版本低于7.0,就调用Uri.fromFile()方法将File对象转换为Uri对象,这个Uri标识着图片的本地真实路径。否则就调用FileProvider的getUriForFile()方法获得Uri对象。之所以这样是因为从7.0开始,直接使用本地真实路径的Uri被认为是不安全的,会抛出异常,而FileProvider则是一种特殊的内容提供器,可以选择性地将封装过的Uri共享给外部,提高应用安全性。  
最后就是启动摄像头拍照并且回调获取图片了。
从相册中选择照片
直接选取一张现有图片比打开相机拍一张照片更加常用,一个优秀的应用应该将这两种方式都提供给用户。废话不多说直接上代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 
 | 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{
 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,String[] permissions,int[] grantResults){
 swithc(requestCode){
 case 1:
 if(grantResults.lenght > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
 openAlbum();
 }else{
 Toast.makeText(this,"you denied the permission",Toast.LENGTH_SHORT).show();
 }
 
 break;
 }
 }
 
 
 @Override
 protected void onActivityResult(int requestCode,int resultCode,Intent data){
 switch(requestCode){
 case CHOOSE_PHOTO:
 if(resultCode == RESULT_OK){
 if(Build.VERSION.SDK_INT >= 19){
 handleImageOnKitKat(data);
 }else{
 handleImageBeforeKitKat(data);
 }
 
 }
 
 break;
 }
 }
 
 
 @TargetApi(19)
 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 selection = MediaStore.Images.Media._ID + "=" + id;
 imagePath = getImagePaht(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())){
 imagePath = getImagePath(uri,null);
 }else if("file".eualsIgnoreCase(uri.getScheme())){
 imagePath = uri.getPath();
 }
 
 
 displayImage(imagePath);
 }
 
 
 private void handleImageBeforeKitKat(Intent data){
 Uri uri = data.getData();
 
 String imagePath = getImagePath(uri,null);
 displayImage(imagePath);
 }
 
 
 
 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.getColumnIndex(MediaStore.Images.Media.DATA));
 }
 cursor.close();
 }
 return path;
 }
 
 
 private void displayImage(String imagePath){
 if(imagePath != null){
 Bitmap bitmap  = BitmapFactory.decodeFile(imagePath);
 ivPicture.setImageBitmap(bitmap);
 }else{
 Toast.makeText(this,"failed to get image",Toast.LENGTH_SHORT).show();
 }
 }
 
 | 
因为照片是存在SD卡上的,所以我们首先进行权限处理,WRITE_EXTERNAL_STORAGE表示授予了对SD卡的读和写的能力。在onActivityResult回调中针对不同版本使用不同方式处理图片,因为从4.4开始,选取相册中的图片不再返回真实的Uri了,而是一个封装过的Uri,因此必须对这个Uri解析才行,在handleImageOnKitKat()方法中,如果返回的Uri是document类型的话,就取出document id进行处理,如果Uri的authority是media格式的话,document id还需要进行一次解析,要通过字符串分割的方式取出后半部分才能得到真正的数字id。
播放多媒体文件
播放音频和视频比较简单,没有兼容性等复杂问题,仅仅只需要记住:
- 申请 WRITE_EXTENAL_STORAGE 权限 
- 使用 MediaPlayer 播放音频结束时,在 onDestroy方法中要进行 MediaPlayer.stop() 和 MediaPlayer.release() ,将资源释放掉; 
- 使用 VideoView 播放视频结束时,在 onDestroy方法中要进行 VideoView.suspend() ,将资源释放掉; 
其他内容略过。