Android中Intent用法详细解释

2023-05-16


    Android中一些常见的Intent的习惯用法,比如如何通过Intent发送短信、发送邮件、启动摄像机拍照录视频、设置闹铃、打开WIFI设置界面等等。  

目录

发送短信

发送邮件

打电话

拍照

摄像


发送短信

发送短信的时候,我们要使用的action是Intent.ACTION_SENDTO,并且要指定其URI是smsto:协议,这样能保证是短信应用接收并处理我们的intent对象,而不是其他应用接收,从而准确实现发送短信的目的。如果我们的action不是Intent.ACTION_SENDTO,而是Intent.ACTION_SEND,且没有指定smsto:协议的URI的话,那么Android在接收到intent对象之后不会直接启动短信应用,而是弹出了App Chooser,让我们选择要启动哪个应用,比如电子邮件、QQ等等,所以为了确保直接启动短信应用,我们应该使用Intent.ACTION_SENDTO并且指定smsto:协议的URI。

示例代码如下:


//使用ACTION_SENDTO而不是ACTION_SEND
Intent intent = new Intent(Intent.ACTION_SENDTO);
//指定URI使用smsto:协议,协议后面是接收短信的对象
Uri uri = Uri.parse("smsto:10086");
intent.setData(uri);
//设置消息体
intent.putExtra("sms_body", "手头有点紧,借点钱吧~~");
​
ComponentName componentName = intent.resolveActivity(getPackageManager());
if(componentName != null){
    startActivity(intent);
}  

在构造发送短信的URI时,前面是smsto:协议,后面跟的是接收短信的对方的手机号。如果在构建URI时,只写了smsto:,而没有写后面的手机的号的话,那么该intent也可以成功启动短信应用,不过这种情形下,在启动了短信应用之后,还需要我们自己再手动输入接收信息的手机号。我们通过key为sms_body的extra设置短信的内容。

需要注意的是,在执行了startActivity(intent)之后,虽然短信应用启动了,但是短信没有直接发出去,需要我们再点击一下发送消息才可以。

发送邮件

发送邮件的时候,我们要使用的action也是Intent.ACTION_SENDTO,并且要指定其URI是mailto:协议,这样能保证是邮件应用接收并处理我们的intent对象,而不是其他应用接收,从而准确实现发送邮件的目的。如果我们的action不是Intent.ACTION_SENDTO,而是Intent.ACTION_SEND,且没有指定mailto:协议的URI的话,那么Android在接收到intent对象之后不会直接邮件应用,而是弹出了App Chooser,让我们选择要启动哪个应用,比如短信、QQ等等,所以为了确保直接启动邮件应用,我们应该使用Intent.ACTION_SENDTO并且指定mailto:协议的URI。

示例代码如下:


//使用ACTION_SENDTO而不是ACTION_SEND
Intent intent = new Intent(Intent.ACTION_SENDTO);
//指定URI使用mailto:协议,确保只有邮件应用能接收到此intent对象
Uri uri = Uri.parse("mailto:");
intent.setData(uri);
String[] addresses = {"zhangsan@126.com", "lisi@126.com"};
String[] cc = {"boss@126.com"};
String[] bcc = {"girlfriend@126.com"};
String subject = "加班";
String content = "国庆正常上班~~";
//设置邮件的接收方
intent.putExtra(Intent.EXTRA_EMAIL, addresses);
//设置邮件的抄送方
intent.putExtra(Intent.EXTRA_CC, cc);
//设置邮件的密送方
intent.putExtra(Intent.EXTRA_BCC, bcc);
//设置邮件标题
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
//设置邮件内容
intent.putExtra(Intent.EXTRA_TEXT, content);
//设置邮件附件
//intent.putExtra(Intent.EXTRA_STREAM, Uri.parse(...));
ComponentName componentName = intent.resolveActivity(getPackageManager());
if(componentName != null){
    startActivity(intent);
}  

启动邮件应用后的截图如下所示:

我们分别通过key为Intent.EXTRA_EMAIL、Intent.EXTRA_CC和Intent.EXTRA_BCC的extra依次设置邮件的接收方、抄送方、密送方,其值均为String数组。我们通过key为Intent.EXTRA_SUBJECT的extra设置邮件标题,通过key为Intent.EXTRA_TEXT的extra设置邮件内容。如果想发送附件,那么可以将附件封装成Uri的形式,然后通过key为Intent.EXTRA_STREAM的extra设置邮件附件。

需要注意的是,在执行了startActivity(intent)之后,虽然邮件应用启动打开了,但是邮件没有直接发出去,需要我们再点击一下右上角的发送按钮才能将邮件发出去。

打电话

要想通过Intent打电话,我们有两个可以使用的action:Intent.ACTION_DIAL和Intent.ACTION_CALL,二者有一定的区别。

如果使用Intent.ACTION_DIAL作为intent对象的action,那么当执行startActivity(intent)之后,会启动打电话应用,并且会自动输入指定的手机号,但是不会自动拨打,需要我们手动按下拨打按钮才能真正给对方打电话。

如果使用Intent.ACTION_CALL作为intent对象的action,那么当执行startActivity(intent)之后,会启动打电话应用,并且直接拨打我们指定的手机号,无需我们再手动按下拨打按钮。但是需要注意的是,该action需要权限android.permission.CALL_PHONE,如果在应用的AndroidManifest.xml文件中没有添加该权限,那么当指定到startActivity(intent)这句代码的时候,就会抛出异常,应用崩溃退出。

以下是示例代码:


//Intent.ACTION_DIAL只拨号,不打电话
//Intent intent = new Intent(Intent.ACTION_DIAL);
//Intent.ACTION_CALL直接拨打指定电话,需要android.permission.CALL_PHONE权限
Intent intent = new Intent(Intent.ACTION_CALL);
Uri uri = Uri.parse("tel:10086");
intent.setData(uri);
ComponentName componentName = intent.resolveActivity(getPackageManager());
if(componentName != null){
    startActivity(intent);
}  

在该示例代码中,我们使用了Intent.ACTION_CALL作为intent对象的action,并且在AndroidManifest.xml中添加了如下权限:


<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>  

我们使用tel:协议的URI,在协议后面的是要拨打的号码,将该Uri作为intent对象的data。

拍照

要想通过Intent启动摄像机进行拍照,我们需要设置intent对象的action值为MediaStore.ACTION_IMAGE_CAPTURE的action。然后我们用key为MediaStore.EXTRA_OUTPUT的extra设置图片的输出路径,最后调用startActivityForResult()方法以启动摄像机应用,并重写我们的onActivityResult()以便在该方法中得知拍照完成。

示例代码如下:


//表示用于拍照的requestCode
    private final int REQUEST_CODE_IMAGE_CAPTURE = 1;
    //我们存储照片的输出路径,以便后续使用
    private Uri imageOutputUri = null;
//拍照
private void captureImage(){
    PackageManager pm = getPackageManager();
​
    //先判断本机是否在硬件上有摄像能力
    if(pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        ComponentName componentName = intent.resolveActivity(pm);
        //判断手机上有无摄像机应用
        if(componentName != null){
            //创建图片文件,以便于通过Uri.fromFile()生成对应的Uri
            File imageFile = createImageFile();
            if(imageFile != null){
                //根据imageFile生成对应的Uri
                imageOutputUri = Uri.fromFile(imageFile);
                //利用该Uri作为拍照完成后照片的存储路径,注意,一旦设置了存储路径,我们就不能获取缩略图了
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageOutputUri);
                //调用startActivityForResult()方法,以便在onActivityResult()方法中进行相应处理
                startActivityForResult(intent, REQUEST_CODE_IMAGE_CAPTURE);
            }else{
                Toast.makeText(this, "无法创建图像文件!", Toast.LENGTH_LONG).show();
            }
        }else{
            Toast.makeText(this, "未在本机找到Camera应用,无法拍照!", Toast.LENGTH_LONG).show();
        }
    }else{
        Toast.makeText(this, "本机没有摄像头,无法拍照!", Toast.LENGTH_LONG).show();
    }
}
​
//创建图片文件,以便于通过Uri.fromFile()生成对应的Uri
private File createImageFile(){
    File image = null;
​
    //用时间戳拼接文件名称,防止文件重名
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
​
    try{
        image = File.createTempFile(
                imageFileName,  //前缀
                ".jpg",         //后缀
                storageDir      //文件夹
        );
    }catch (IOException e){
        image = null;
        e.printStackTrace();
        Log.e("DemoLog", e.getMessage());
    }
​
    return image;
}
​
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    //首先判断是否正确完成
    if(resultCode == RESULT_OK){
        switch (requestCode){
            case REQUEST_CODE_IMAGE_CAPTURE:
                //此处,我们可以通过imageOutputUri获取到我们想要的图片
                String imagePath = imageOutputUri.toString();
                Log.i("DemoLog", "照片路径是: " + imagePath);
                Toast.makeText(this, "照片路径是: " + imagePath, Toast.LENGTH_LONG).show();
​
                //以下代码尝试获取缩略图
                //如果设置MediaStore.EXTRA_OUTPUT作为extra的时候,那么此处的intent为null,需要判断
                if(intent != null){
                    Bitmap thumbnail = intent.getParcelableExtra("data");
                    //有的手机并不会给拍照的图片生成缩略图,所以此处也要判断
                    if(thumbnail != null){
                        Log.i("DemoLog", "得到缩略图");
                    }
                }
            default:
                break;
        }
    }
}  

我们分析一下上面的代码片段:

不是所有的Android设备都能拍照的,所以首先我们调用了PackageManager的hasSystemFeature(PackageManager.FEATURE_CAMERA)方法,判断当前设备在硬件层级是否具有拍照的能力。

然后我们创建了一个action为MediaStore.ACTION_IMAGE_CAPTURE的intent对象。

然后我们通过调用intent.resolveActivity(pm)方法判断当前设备有无摄像机应用以便我们启动。如果没有摄像机应用但是我们却把intent对象传递给startActivity()或startActivityForResult()的话,就会抛出异常,应用崩溃退出。

我们自己写了一个createImageFile方法,通过该方法我们在自己的应用所对应的外设存储卡上创建了一个图片文件。需要注意的是,此步骤需要WRITE_EXTERNAL_STORAGE权限,在AndroidManifest.xml中注册如下:


<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="18"></uses-permission>  

关于该权限的更多信息,可参见WRITE_EXTERNAL_STORAGE。

我们利用上面生成的图片文件生成了对应的Uri,将其存储在Activity中类型为Uri的字段imageOutputUri中,之后我们执行了intent.putExtra(MediaStore.EXTRA_OUTPUT, imageOutputUri),利用该Uri作为拍照完成后照片的存储路径。 ​ 此处需要特别注意的是,一旦设置了存储路径,我们就不能在onActivityResult()中获取缩略图了。

最后我们需要调用方法startActivityForResult(intent, REQUEST_CODE_IMAGE_CAPTURE)以启动摄像机应用进行拍照,其中REQUEST_CODE_IMAGE_CAPTURE是我们自定义指定的用于拍照的requestCode。

我们覆写了onActivityResult方法,拍照完成后触发该方法的执行。首先我们要判断resultCode是否与RESULT_OK相等,只有相等才表明拍照成功,然后我们判断如果requestCode是否等于REQUEST_CODE_IMAGE_CAPTURE,若相等表明是拍照返回的结果。那么此时,我们就可以通过我们之前存储的imageOutputUri获取刚刚拍完的照片了,其URI字符串如: file:///storage/sdcard0/Android/data/com.ispring.commonintents/files/Pictures/JPEG_20150919_112704_533002075.jpg

需要注意的是,如果我们在第5步之中设置MediaStore.EXTRA_OUTPUT作为照片输出路径的话,那么在onActivityResult中无法获取从摄像机应用换回的Intent,即为null,这样也就无法获取缩略图。反之,如果在第5步没有设置MediaStore.EXTRA_OUTPUT作为照片输出路径的话,intent不为空,可以尝试执行Bitmap thumbnail = intent.getParcelableExtra("data")获取缩略图,如果thumbnail不为空,表示能成功获取缩略图。但是有的手机并不会给拍照的图片生成缩略图,所以此处的thumbnail也有可能是null,所以在使用之前要先判断。

摄像

通过Intent启动摄像机进行摄像的步骤与上面刚提到的通过Intent启动摄像机进行拍照的步骤非常相似,稍有区别。要启动Camera进行摄像,我们需要给intent设置值为MediaStore.ACTION_VIDEO_CAPTURE的action,然后我们用key为MediaStore.EXTRA_OUTPUT的extra设置图片的输出路径,最后调用startActivityForResult()方法以启动摄像机应用,并重写我们的onActivityResult()以便在该方法中得知摄像完成。

以下是示例代码:


//表示用于录视频的requestCode
    private final int REQUEST_CODE_VIDEO_CAPTURE = 2;
//我们存储视频的输出路径,以便后续使用
private Uri videoOutputUri = null;
​
//摄像
private void captureVideo(){
    PackageManager pm = getPackageManager();
​
    //先判断本机是否在硬件上有摄像能力
    if(pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        //将intent的action设置为MediaStore.ACTION_VIDEO_CAPTURE
        Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
        ComponentName componentName = intent.resolveActivity(pm);
        //判断手机上有无摄像机应用
        if(componentName != null){
            //创建视频文件,以便于通过Uri.fromFile()生成对应的Uri
            File videoFile = createVideoFile();
            if(videoFile != null){
                //根据videoFile生成对应的Uri
                videoOutputUri = Uri.fromFile(videoFile);
                //利用该Uri作为摄像完成后视频的存储路径
                intent.putExtra(MediaStore.EXTRA_OUTPUT, videoOutputUri);
                //调用startActivityForResult()方法,以便在onActivityResult()方法中进行相应处理
                startActivityForResult(intent, REQUEST_CODE_VIDEO_CAPTURE);
            }else{
                Toast.makeText(this, "无法创建视频文件!", Toast.LENGTH_LONG).show();
            }
        }else{
            Toast.makeText(this, "未在本机找到Camera应用,无法摄像!", Toast.LENGTH_LONG).show();
        }
    }else{
        Toast.makeText(this, "本机没有摄像头,无法摄像!", Toast.LENGTH_LONG).show();
    }
}
​
//创建视频文件,以便于通过Uri.fromFile()生成对应的Uri
private File createVideoFile(){
    File videoFile = null;
​
    //用时间戳拼接文件名称,防止文件重名
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "MP4" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES);
​
    try{
        videoFile = File.createTempFile(
                imageFileName,  //前缀
                ".mp4",         //后缀
                storageDir      //文件夹
        );
    }catch (IOException e){
        videoFile = null;
        e.printStackTrace();
        Log.e("DemoLog", e.getMessage());
    }
​
    return videoFile;
}
​
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    //首先判断是否正确完成
    if(resultCode == RESULT_OK){
        switch (requestCode){
            case REQUEST_CODE_VIDEO_CAPTURE:
                //如果设置MediaStore.EXTRA_OUTPUT作为extra的时候,
                //在有的手机上,此处的intent为不为null,但是在有的手机上却为null,
                //所以不建议从intent.getData()中获取视频路径
                //我们应该自己记录videoOutputUri来得知视频路径,下面注释的代码不建议使用
                /*if(intent != null){
                    Uri videoUri = intent.getData();
                    if(videoUri != null){
                        //路径格式如content://media/external/video/media/130025
                        Log.i("DemoLog", "视频路径是: " + videoUri.toString());
                    }
                }*/
​
                String videoPath = videoOutputUri.toString();
                //1.如果没有设置MediaStore.EXTRA_OUTPUT作为视频文件存储路径,那么路径格式如下所示:
                //  路径格式如content://media/external/video/media/130025
                //2.如果设置了MediaStore.EXTRA_OUTPUT作为视频文件存储路径,那么路径格式如下所示:
                //  路径格式如file:///storage/sdcard0/Android/data/com.ispring.commonintents/files/Movies/MP420150919_184132_533002075.mp4
                Log.i("DemoLog", "视频路径是: " + videoPath);
                Toast.makeText(this, "视频路径是: " + videoPath, Toast.LENGTH_LONG).show();
                break;
            default:
                break;
        }
    }
}  

可以看到上面启动Camera摄像的代码与拍照的代码几乎完全一样,具体解释参见对拍照代码的描述。在该示例代码中,我们通过MediaStore.EXTRA_OUTPUT设置了视频的存放路径,拍照的时候我们也通过它设置了照片的输出路径,但是二者稍有区别:

  1. 对于拍照,设置了MediaStore.EXTRA_OUTPUT之后,onActivityResult中的Intent参数是null,不能从Intent中得知照片的存储路径。

  2. 对于摄像,设置了MediaStore.EXTRA_OUTPUT之后,onActivityResult中的Intent参数在有的手机上是null,但是在有的手机上不是null,我的手机小米1s得到的intent对象就不是null,所以此处很奇怪。如果intent不是null,可以通过intent.getData()获取到视频文件的存储路径,但是由于intent是否为null不确定,所以尽量不要通过intent.getData()方法获取其路径,而应该自己在Activity中存储一个字段保存我们之前设置的文件路径,这样就没问题了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android中Intent用法详细解释 的相关文章

随机推荐

  • 超详细一文到底!软件测试基本流程

    前言 xff1a 采用通用的测试流程 xff0c 能高效 高质量的完成软件测试工作 xff0c 有助于减少沟通成本 xff0c 对各阶段产出有明确认知等等 最终目标 xff1a 实现软件测试规范化 标准化 以下为非通用标准 xff0c 仅供
  • shell:重启&&关机

    文章目录 shutdownhaltpoweroffrebootinitsync shutdown 关机重启命令 shutdown h 10十分钟后关机shutdown h 0马上关机shutdown h now马上关机shutdown c取
  • 世界上最经典的25句话

    1 记住该记住的 xff0c 忘记该忘记的 改变能改变的 xff0c 接受不能改变的 2 能冲刷一切的除了眼泪 xff0c 就是时间 xff0c 以时间来推移感情 xff0c 时间越长 xff0c 冲突越淡 xff0c 仿佛不断稀释的茶 3
  • Android Intent 用法总结

    From xff1a https www jianshu com p 67d99a82509b Android 中提供了 Intent 机制来协助应用间的交互与通讯 xff0c Intent 负责对应用中一次操作的动作 动作涉及数据 附加数
  • centos8 配置vsftpd的SSL/TLS功能

    前面我带着大家已经配置了一个vsftpd服务器 xff08 虚拟用户模式 xff09 xff0c 匿名用户和本地用户模式配置起来比较简单就没再赘述 xff0c 本文再带大家开启vsftpd的SSL TLS功能 1 生成一个TLS证书 Vsf
  • ubuntu gnome 桌面增加快捷方式

    方法 在 ubuntu 的桌面增加快捷方式很简单 xff0c 在 usr share applications 下 xff0c 增加一个 desktop 文件就可 xff0c 内容基本如下 xff1a Desktop Entry Versi
  • DOS那一代的程序员现在都干嘛呢?

    亿友论坛 DOS那一代的程序员现在都干嘛呢 xff1f xff08 几年前的老帖子 xff09 作者 xff1a 包子夹蛋 发布时间 xff1a 2005 5 10 14 01 00 DOS那一代的程序员现在都干嘛呢 xff1f xff08
  • KVM虚拟机掉电重启后无法ssh连接访问

    KVM虚拟机掉电重启无法ssh连接访问 问题描述问题解决过程解决方法 问题描述 KVM虚拟机升级ssh版本后 xff0c 主机因为维护掉电 xff0c 等主机上电后 xff0c 虚拟机重启后 xff0c 再也无法ssh连接访问 问题解决过程
  • 让Ubuntu 18.04系统支持root用户登录的方法

    简介 默认的Ubuntu 18 04系统在登陆界面上是不支持root用户直接登录的 xff0c 但是你可以使用下面的方法让Ubuntu 18 04也支持root登录 通常情况下 xff0c 在Ubuntu 18 04中的普通用户只能通过运行
  • 这十个css动画案例惊艳众人

    大家好 我是前端实验室的大师兄 对于网页设计师和开发工程师而言 xff0c 创建一款极具趣味性和实用性的CSS网页动画 xff0c 能让网站美观不少 CSS动画 xff0c 就是通过CSS代码搭建网页动画 允许设计师和开发人员 xff0c
  • java线程和进程(阻塞队列)

    目录 1 阻塞队列简介 2Java中的阻塞队列 3 阻塞队列的实现原理 4 阻塞队列的使用场景 1 阻塞队列简介 阻塞队列常用于生产者和消费者的场景 xff0c 生产者是往队列里添加元素的线程 xff0c 消费者是从队列里拿元素的线程 阻塞
  • 子类可以重载父类的方法吗?重载会发生父类和子类之间吗?

    不可以 方法重载 xff1a 在同一个类中 xff0c 方法名相同 xff0c 参数列表不同的方法 xff0c 同一个类中 xff01 xff01 xff01 xff0c 子类和父类不是一个类啊 底层原理是方法区加载了子类和父类 xff0c
  • 时间复杂度和空间复杂度(基础,详细)

    前言 算法对于开发人员是非常重要的 xff0c 我们从常见的算法看起 xff0c 比如排序算法 xff0c 排序算法有好几种实现方法 xff0c 最简单的嵌套两个for循环进行排序 xff0c 进阶点就可以用 冒泡排序 xff0c 最终的结
  • 类与类之间的关系

    类之间的关系有 xff1a 泛化 xff08 继承 xff09 实现 关联 聚合 组合 依赖 目录 1 泛化 xff08 Generalization xff09 继承 2 实现 xff08 Realization xff09 3 关联 x
  • Unity调试Android

    Unity调试android xff0c 有两种方式 xff0c 第一种在unity编辑器中查看日志 xff0c 另一种是在android studio查看日志 xff0c 个人比较推荐android studio查看日志 xff0c 主要
  • 一文讲明白Linux中的umask原理及应用

    大家在学习Linux操作系统的时候肯定遇到过umask 大部分的书籍会对umask从原理到各种情况下的应用都讲的非常详细 xff0c 洋洋洒洒一大篇 xff0c 然后呢 然后你就看得云里雾里似乎明白了 xff0c 可是又不太懂这个东西干嘛搞
  • Unity Remote5 使用

    Unity Remote是Unity公司提供的一个移动端同步调试工具 xff0c 在Unity编辑器中以播放模式运行项目时 xff0c 该应用程序将与Unity连接 编辑器的可视输出被发送到设备的屏幕 xff0c 实时输入被发送回Unity
  • 里氏替换原则

    里氏替换原则主要是发生在父类和子类之间 xff0c 说到父类和子类 xff0c 在面向对象的语言中 xff0c 继承是必不可少的 非常优秀的语言机制 xff0c 它有如下优点 xff1a 代码共享 xff0c 减少创建类的代码量 xff0c
  • Android中的Intent

    Android中的Intent可以用来在一个组件中启动App中的另一个组件或者是启动另一个App的组件 xff0c 这里所说的组件指的是Activity Service以及Broadcast 目录 Intent的用途 Intent的类型 I
  • Android中Intent用法详细解释

    Android中一些常见的Intent的习惯用法 xff0c 比如如何通过Intent发送短信 发送邮件 启动摄像机拍照录视频 设置闹铃 打开WIFI设置界面等等 目录 发送短信 发送邮件 打电话 拍照 摄像 发送短信 发送短信的时候 xf