Android——使用通知,运用手机多媒体
1.Notification通知
通知Notification,当某个应用希望向用户发送一些提示信息,而该应用不在前台运行,就借助通知来实现。发出一条通知,手机上方的状态栏中会显示一个通知图标,下拉状态栏后可以看到通知的详细内容。通知可以在活动,广播接收器,服务里创建,一般程序进入后台的时候我们才使用通知。
步骤:需要一个NotificationManager来对通知进行管理,可以调用Context的getSystemService()方法得到,接收一个字符串参数用于确定获取系统的哪个服务。传入Context.NOTIFICATION_SERVICE即可。接下来需要使用一个Builder构造器来创建Notification对象,使用NotificationCompat类。
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Send Notice"
android:id="@+id/send_notice"/>
</LinearLayout>
新建一个NotificationActivity活动,修改xml文件里的代码
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/text_view"
android:text="this is Notification"/>
MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendNotice = (Button) findViewById(R.id.send_notice);
sendNotice.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.send_notice:
Intent intent = new Intent(MainActivity.this,NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel("1","channel1",NotificationManager.IMPORTANCE_HIGH);
Notification notification = new NotificationCompat.Builder(MainActivity.this,"1")
.setContentTitle("this is a notification Title")
.setContentText("this is a notification text")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
.setContentIntent(pi)
.build();
manager.notify(1,notification);
break;
default:
break;
}
}
}
notify()方法接收两个参数,第一个参数id,每个通知指定的id是不一样的,第二个参数是Notification对象。
PendingIntent和Intent类似,可以指明某个意图,启动活动,启动服务,发送广播等,不同的是Intent更加倾向于立即去执行某个动作,PendingIntent倾向于在某个合适的时机去执行,可理解为延迟执行的Intent。获取PendingIntent的实例,可选择getActivity()方法,getBroadcast()方法,getService()方法,这三个方法接收的参数一样,第一个Content,第二个通常用不到传入0,第三个是一个Intent对象,可以通过这个对象构建出PendingIntent的“意图”,第四个参数用于确定PendingIntent行为,通常传入0。NotificationCompat.Builder,这个构造器再连缀一个setContentIntent()方法,接收的参数正是一个PendingIntent对象,因此这里可以通过一个PendingIntent构建出一个延迟执行的“意图”,当用户点击这条通知时就会执行相应的逻辑。
运行效果
点击按钮
点进去
2.调用摄像头和相册
新建一个CameraAlbumTest项目
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/take_photo"
android:text="Take Photo"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:id="@+id/picture"/>
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 takePhoto = (Button) findViewById(R.id.take_photo);
picture = (ImageView) findViewById(R.id.picture);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
File outputImage = new File(getExternalCacheDir(),"output_image.jpg");
try{
if(outputImage.exists())
outputImage.delete();
outputImage.createNewFile();
}catch (IOException e){
e.printStackTrace();
}
if(Build.VERSION.SDK_INT >=24){
imageUri = FileProvider.getUriForFile(MainActivity.this,
"com.example.cameraalbumtest.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));
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
}
按钮的点击事件里,首先创建了一个File对象,用于存放摄像头拍下的照片,图片命名为output_image.jpg,并将它存放在SD卡的应用关联缓存目录下(SD卡中专门用于存放当前应用缓存数据的位置),调用getExternalCacheDir()方法可以得到这个目录,
然后判断,运行设备的系统版本低于Android 7.0,就调用Uri的fromFile()方法将File对象转换成Uri对象,这个Uri对象标识着output_image.jpg的本地真实路径,否则就调用FileProvider的getUriForFile()方法将File对象转换成一个封装过的Uri对象。getUriForFile()方法接收三个参数,第一个Context,第二个参数可以是任意唯一的字符串,第三个参数是刚刚创建的File对象。Android 7.0开始,直接使用本地真实路径的Uri被认为不安全,FileProvider是一种特殊的内容提供器,使用了和内容提供器类似的机制对数据进行保护,可以选择性地将封装过地Uri共享给外部,提高了应用的安全性。
接下来构建出了一个Intent对象,将这个Intent的action指定为android.media.action.IMAGE_CAPTURE,再调用Intent的putExtra()方法将指定的图片输出地址,最后调用startActivityForResult()来启动活动,使用了隐式Intent,系统会找出能响应这个Intent的活动去启动,这样照相机程序会被打开,拍下的照片会输出到output_image.jpg中。
刚刚使用了startActivityForResult()来启动活动,拍完照后会有结果返回到onActivityResult()方法中,若拍照成功,就可以调用BitmapFactory的decodeStream()方法将output_stream.jpg解析成Bitmap对象,然后把他设置到ImageView中显示出来
我们要在AndroidManifest.xml中对内容提供器进行注册,
...
<provider
android:authorities="com.example.cameraalbumtest.fileprovider"
android:name="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
...
android:name的属性是固定的
android:authorities的属性要和刚刚FileProvider.getUriForFile()方法中第二个参数一致,另外,使用< meta-data >来指定Uri的共享路径,并引用一个@xml/file_paths资源,在res目录下创建它,创建一个xml目录,创建一个file_paths.xml文件
<?xml version="1.0" encoding="utf-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="" />
</paths>
external-path来指定Uri共享,name属性的值可以随便填,path属性的值表示共享的具体路径,空值表示将整个SD卡进行共享。
Android 4.4系统之前访问SD卡的应用关联目录要声明权限,4.4之后不需要说明,为了兼容老手机,在AndroidManifest.xml中声明一下访问SD卡的权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
从相册中选择照片
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
......
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/choose_photo"
android:text="Choose Photo"/>
......
</LinearLayout>
public class MainActivity extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;
public static final int CHOOSE_PHOTO = 2;
private ImageView picture;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
......
Button chooseFromAlbum = (Button) findViewById(R.id.choose_photo);
chooseFromAlbum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
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();
}
}
});
}
@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;
default:
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 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())){
imagePath = getImagePath(uri,null);
}else if("file".equalsIgnoreCase(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);
picture.setImageBitmap(bitmap);
}else{
Toast.makeText(this,"failed to get image",Toast.LENGTH_LONG).show();
}
}
public void openAlbum(){
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent,CHOOSE_PHOTO);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
openAlbum();
}else{
Toast.makeText(this,"you deny the permission",Toast.LENGTH_LONG).show();
}
break;
default:
}
}
......
}
首先在chooseFromAlbum按钮的点击事件里进行了权限处理,动态申请WRITE_EXTERNAL_STORAGE这个危险权限,同时授予程序对SD读和写的能力。
授权了权限申请之后会调用openAlbum()方法,构建了一个Intent对象,并将他的动作指定为android.intent.action.GET_CONTENT,接着给这个Intent设置一些必要的参数,然后调用startActivityForResult()方法就可以给打开相册程序选择照片,startActivityForResult的第二个参数是CHOOSE_PHOTO,当选择完照片回到onActivityResult()方法时会进入CHOOSE_PHOTO的case,处理图片。
如果是4.4系统版本以上,调用handleImageOnKitKat()方法,不是则调用handleImageBeforeKitKat()方法,android系统从4.4开始,选取相册中的图片不再返回图片真实的Uri,是一个封装过的Uri,需要对这个Uri进行解析。
handleImageOnKitKat()方法里,如果返回的Uri是document类型,就取出document id进行处理,如果不是就用普通方式处理,如果Uri的authority是media格式的话,document id还需要再解析一次,通过字符串分割取出后半部分,得到真正的数字id,取出的id用于构建新的Uri和条件语句,然后把这些值作为参数传入到getImagePath()方法中将图片显示到界面上。
handleImageBeforeKitKat()方法直接将Uri传入到getImagePath()方法中。
本文地址:https://blog.csdn.net/zhougongjinxuan/article/details/108534143
推荐阅读
-
Android使用JobScheduler定期推送本地通知实例代码
-
android手机端与PC端使用adb forword通信
-
Android中使用Notification实现状态栏的通知
-
Android中使用Notification在状态栏上显示通知
-
Android开发之Notification手机状态栏通知用法实例分析
-
Android使用AsyncQueryHandler实现获取手机联系人功能
-
使用python编写批量卸载手机中安装的android应用脚本
-
AirPods Pro和安卓手机使用可以降噪吗 怎么连接android手机
-
Android使用模板生成支持手机直接查看的Word文档
-
如何在无数据线USB连接, 只有wifi情况下使用android studio build app到手机进行调试?