使用通知
我们可以在Activity中、BroadcastReceiver以及Service中创建通知,不论在哪里创建,整体步骤是相同的,下面通过示例演示:
1 2 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或者微信的时候经常要别人分享图片,这些图片可以使手机摄像头拍摄也可以从相册中选取,这种功能非常普遍。
摄像头拍照
直接上代码展示可能更加清晰:
1 2 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 权限):
1 2 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,内容如下:
1 2 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共享给外部,提高应用安全性。
最后就是启动摄像头拍照并且回调获取图片了。
从相册中选择照片
直接选取一张现有图片比打开相机拍一张照片更加常用,一个优秀的应用应该将这两种方式都提供给用户。废话不多说直接上代码:
1 2 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() ,将资源释放掉;
其他内容略过。