Android学习笔记(八)使用多媒体(通知、短信、摄像头、相册、音视频)

来源:互联网 发布:旅程网络 官网 编辑:程序博客网 时间:2024/06/05 17:58

8.1 通知(Notification)

当某个应用程序不在前台运行,但又希望给用户发送一些信息的时候,就可以借助通知来实现。
通知较为灵活,可在活动、广播接收器以及服务中创建,但实际应用中在活动中创建较少。

注意:
《第一行代码》原作中创建通知的方式已过时,现已更新为如下方式,简单示例:
/** * 1.创建一个通知管理对象 * getSystemService方法接收一个参数,用于确定获取系统的哪个服务 * 这里传入 Context.NOTIFICATION_SERVICE 即可 */NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);/** * 2.创建一个通知构造器builder对象 * param:Context上下文 */Notification.Builder builder = new Notification.Builder(MainActivity.this);//瞬时信息(通知刚被创建时,在系统栏一闪而过)builder.setTicker("有新通知啦快来查看!");//通知图标builder.setSmallIcon(R.drawable.android);//通知标题builder.setContentTitle("This is title");//通知内容builder.setContentText("Content....");//通知时间(显示在通知上)builder.setWhen(System.currentTimeMillis());//设置通知在点击后是否自动取消,默认falsebuilder.setAutoCancel(true);/** * 3.创建一个意图,用于指定点击该通知想要跳转到哪个Activity中 */Intent intent = new Intent(MainActivity.this, NotificationActivity.class);/** * 4.创建一个PendingIntent * PendingIntent,可简单理解为延迟执行的Intent,更倾向于在某个合适的时机去执行某个动作;而Intent更倾向于立即执行动作。 * pararm1:上下文 * pararm2:一般用不到,通常传入0 * pararm3:意图对象 * pararm4:指定PendingIntent的行为,有四种可选值 */PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);/** * 5.将PendingIntent设置给builder中 */builder.setContentIntent(pendingIntent);/** * 6.使用build()方法创建通知Notification对象 * ps:这里build方法提示了一个当前api最低版本比该方法所需API版本要低编译错误,所以,按AS提示加了一个@TargetApi注解 */Notification notification = builder.build();/** * 7.使用通知管理的notify()方法显示通知 * param1:自定义通知id * param2:通知对象 */manager.notify(1, notification);//取消通知,参数为通知id//manager.cancel(1);

8.2 发送接收短信

8.2.1 接收短信

        接收短信主要是利用了广播机制的原理。当手机收到短信时,会发出一条值为 android.provider.Telephony.SMS_RECEIVED 的广播,这条广播里携带着短信的信息,再从中解析出短信内容即可。

主要代码:
public class MainActivity extends AppCompatActivity {    public TextView sender;    public TextView content;    public SMSReceiver receiver;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        sender = (TextView) findViewById(R.id.sender);        content = (TextView) findViewById(R.id.content);        //注册广播监听        IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");        receiver = new SMSReceiver();        registerReceiver(receiver, intentFilter);    }    /**     * 短信广播接收器类     */    class SMSReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            //取出Bundle对象            Bundle bundle = intent.getExtras();            //使用 pdu 密钥来提取一个 SMS pdus 数组,其中每一个 pdu 都表示一条短信消息            Object[] pdus = (Object[]) bundle.get("pdus");            SmsMessage[] messages = new SmsMessage[pdus.length];            for (int i = 0; i < messages.length; i++) {                //将每一个pdu字节数组转换为SmsMessage对象                messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);                //新的API中此方法已被下面的方法所代替                //createFromPdu(byte[] pdu, String format);            }            //获取发送方号码            String address = messages[0].getOriginatingAddress();            //获取短信内容            String fullMsg = "";            for (SmsMessage smsMessage : messages) {                fullMsg += smsMessage.getMessageBody();            }            sender.setText(address);            content.setText(fullMsg);        }    }    @Override    protected void onDestroy() {        super.onDestroy();        //取消广播监听        unregisterReceiver(receiver);    }}

当然,读取短信也需要声明权限

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

(小技巧)Android Studio模拟器模拟发送短信不同于以往的方式,是酱婶儿的:


8.2.2 拦截短信

        当有短信到来时,不只自己的程序会接收短信,系统的程序也会接收短信,这样的效果会造成不好的用户体验。而收到短信后发出的广播正是一条有序广播,所以可以利用此方式来屏蔽系统短信。
两步:
(1)提高广播接收器优先级
intentFilter.setPriority(100);
(2)在onReceive方法中终止广播的继续传递
abortBroadcast();

拦截短信的功能还是要慎用,防止数据的丢失!

8.2.3 发送短信

(1)编写广播接收器,监听短信发送状态
class SMSSendReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        if (getResultCode() == RESULT_OK) {            Toast.makeText(context, "短信发送成功", Toast.LENGTH_SHORT).show();        } else {            Toast.makeText(context, "短信发送失败", Toast.LENGTH_SHORT).show();        }    }}
(2)注册广播并发送
/** * 1.注册监听短信发送状态的广播接收器 */sendFilter = new IntentFilter("SENT_SMS_ACTION");sendReceiver = new SMSSendReceiver();registerReceiver(sendReceiver, sendFilter);/** * 2.模拟点击事件发送短信 */btnSend.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        //通过getDefault()方法获取到SmsManager的实例        SmsManager manager = SmsManager.getDefault();        Intent intent = new Intent("SENT_SMS_ACTION");        PendingIntent pi = PendingIntent.getBroadcast(MainActivity.this, 0, intent, 0);        /**         * 发送短信         * param1:指定接收人的手机号码         * param2:null         * param3:短信内容         * param4:PendingIntent对象         * param5:null         */        manager.sendTextMessage(to.getText().toString(), null, msgInput.getText().toString(), pi, null);    }});

不要忘记取消注册广播!

(3)注册发送短信权限:
<uses-permissionandroid:name="android.permission.SEND_SMS"/>

ps:
        根据国际标准,每条短信的长度不得超过 160 个字符,如果想要发送超出这个长度的短信,则需要将这条短信分割成多条短信来发送,使用 SmsManager 的 sendMultipart-TextMessage()方法就可以实现上述功能。它的用法和 sendTextMessage()方法也基本类似。

8.3 调用摄像头和相册

8.3.1 调用摄像头

(1)修改布局文件,实现点击按钮去拍照,然后剪裁之后展示在下方的ImageView中。
<?xml version="1.0" encoding="utf-8"?><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:id="@+id/take_photo"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="Take Photo" />    <ImageView        android:id="@+id/picture"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center_horizontal" /></LinearLayout>
(2)主要代码如下:
public class MainActivity extends AppCompatActivity {    public static final int TAKE_PHOTO = 1;    public static final int CROP_PHOTO = 2;    private Button takePhoto;    private ImageView picture;    private Uri imageUri;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //获取控件实例        takePhoto = (Button) findViewById(R.id.take_photo);        picture = (ImageView) findViewById(R.id.picture);        //给按钮注册点击事件        takePhoto.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                /**                 * 1.创建File对象,用于存储拍照后的图像                 * Environment.getExternalStorageDirectory()获取的是SD卡根目录                 */                File outputImage = new File(Environment.getExternalStorageDirectory(), "output_image.jpg");                try {                    //如果该文件存在,则删除后再创建                    if (outputImage.exists()) {                        outputImage.delete();                    }                    outputImage.createNewFile();                } catch (IOException e) {                    e.printStackTrace();                }                /**                 * 2.然后调用Uri.fromFile()将File对象转换为Uri对象                 * 这个Uri对象标识着output_image.jpg的唯一地址                 */                imageUri = Uri.fromFile(outputImage);                /**                 * 3.构建意图,并用putExtra方法来指定图片的输出地址,使用刚刚创建的Uri对象                 * 启动相机                 */                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);                //启动相机程序,这样拍的照片将会存在output_image.jpg中                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) {                    /**                     * 4.有结果返回时,则再次构建意图,打开剪裁程序                     */                    Intent intent = new Intent("com.android.camera.action.CROP");                    intent.setDataAndType(imageUri, "image/*");                    intent.putExtra("scale", true);                    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);                    startActivityForResult(intent, CROP_PHOTO); // 启动裁剪程序                }                break;            //当为剪裁完照片的返回时            case CROP_PHOTO:                if (resultCode == RESULT_OK) {                    try {                        /**                         * 5.当剪裁完成后,通过以下方式将output_image.jpg解析为Bitmap对象                         */                        Bitmap bitmap = BitmapFactory.decodeStream                                (getContentResolver()                                        .openInputStream(imageUri));                        // 将裁剪后的照片显示出来                        picture.setImageBitmap(bitmap);                    } catch (FileNotFoundException e) {                        e.printStackTrace();                    }                }                break;            default:                break;        }    }}

(3)由于涉及到向SD卡中写入数据,所以需声明权限:
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

8.3.2 调用相册

注意:
        《第一行代码》原作中调用相册的代码已过时,现已改为如下方式(下面的例子亲测可用,在4.1版本的系统和4.4版本的系统上都能正常运行。只是实际中还需对图片进行压缩处理,防止图片过大而导致内存溢出,此处无优化):
public class SecondActivity extends AppCompatActivity {    //去相册选择图片请求码    private static final int CHOOSE_FROM_ALBUM = 0;    //剪裁图片请求码    private static final int CROP_PHOTO = 1;    private Button choosePic;    private ImageView picture;    private Uri imageUri;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        //获取控件        choosePic = (Button) findViewById(R.id.choose_from_album);        picture = (ImageView) findViewById(R.id.picture);        choosePic.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //创建File对象,用于存储选择的照片                File outputImage = new File(Environment.getExternalStorageDirectory(), "output_image.jpg");                try {                    //如果存在则删除                    if (outputImage.exists()) {                        outputImage.delete();                    }                    //创建新文件                    outputImage.createNewFile();                } catch (IOException e) {                    e.printStackTrace();                }                //将File对象转换为Uri对象                imageUri = Uri.fromFile(outputImage);                /**                 * 去相册选择                 */                Intent intent = new Intent("android.intent.action.PICK");                intent.setType("image/*");                //允许剪裁                intent.putExtra("crop", true);                //允许缩放                intent.putExtra("scale", true);                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);                //启动                startActivityForResult(intent, CHOOSE_FROM_ALBUM);            }        });    }    /**     * 启动活动回调函数     *     * @param requestCode 请求码     * @param resultCode  结果码     * @param data        回传的意图对象     */    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        switch (requestCode) {            //选择图片成功了要启动剪裁活动            case CHOOSE_FROM_ALBUM:                if (resultCode == RESULT_OK) {                    //判断手机系统的版本号                    if (Build.VERSION.SDK_INT >= 19) {                        handleImageOnKitKat(data);                    } else {                        handleImageBeforeKitkat(data);                    }                }                break;            //剪裁图片完成了要显示出来            case CROP_PHOTO:                if (resultCode == RESULT_OK) {                    try {                        Bitmap bitmap = BitmapFactory.decodeStream                                (getContentResolver()                                        .openInputStream(imageUri));                        // 将裁剪后的照片显示出来(实际还需压缩图片进行优化)                        picture.setImageBitmap(bitmap);                    } catch (FileNotFoundException e) {                        e.printStackTrace();                    }                }                break;            default:                break;        }    }    /**     * 当系统为4.4以上版本的时候,必须以以下方式才可以读取图片     *     * @param data 回传的intent对象     */    @TargetApi(19)    private void handleImageOnKitKat(Intent data) {        String imagePath = null;        Uri uri = data.getData();        imageUri = uri;        if (DocumentsContract.isDocumentUri(this, uri)) {            // 如果文档类型是uri,则通过document id 处理            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())) {            // 如果不是document类型的Uri,则使用普通方式处理            imagePath = getImagePath(uri, null);        } else {            Toast.makeText(SecondActivity.this, "未知类型!", Toast.LENGTH_SHORT).show();        }        cropImage(imagePath);    }    /**     * 当系统为4.4以下的时候必须以以下方式读取图片     *     * @param data 回传的intent对象     */    private void handleImageBeforeKitkat(Intent data) {        Uri uri = data.getData();        imageUri = uri;        String imagePath = getImagePath(uri, null);        cropImage(imagePath);    }    /**     * 获得选择的图片的真实路径     *     * @param uri       图片的标识符     * @param selection 选择的选项,可为空     * @return 选择的图片的真实路径     */    private String getImagePath(Uri uri, String selection) {        String path = null;        //通过Uri跟selection来获取真实的图片路径        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;    }    /**     * 启动剪裁图片活动     *     * @param imagePath 图片路径     */    private void cropImage(String imagePath) {        if (imagePath != null) {            Intent intent = new Intent("com.android.camera.action.CROP");            intent.setDataAndType(imageUri, "image/*");            intent.putExtra("scale", true);            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);            startActivityForResult(intent, CROP_PHOTO);        }    }}

8.4播放多媒体文件

8.4.1 播放音频

播放音频文件一般都是使用MediaPlayer 类来实现的,它对多种格式的音频文件提供了非常全面的控制方法。


主要代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private Button play;    private Button pause;    private Button stop;    /**     * 1.创建一个MediaPlayer的实例     */    private MediaPlayer mediaPlayer = new MediaPlayer();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        play = (Button) findViewById(R.id.play);        pause = (Button) findViewById(R.id.pause);        stop = (Button) findViewById(R.id.stop);        play.setOnClickListener(this);        pause.setOnClickListener(this);        stop.setOnClickListener(this);        /**         * 2.初始化MediaPlayer         */        initMediaPlayer();    }    private void initMediaPlayer() {        File file = new File(Environment.getExternalStorageDirectory(),                "music.mp3");        try {            //指定音频文件路径            mediaPlayer.setDataSource(file.getPath());            //使MediaPlayer进入到准备状态            mediaPlayer.prepare();        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * 3.执行对应操作     *     * @param v     */    @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;        }    }    /**     * 4.不要忘记释放资源     */    @Override    protected void onDestroy() {        super.onDestroy();        /**         *         */        if (mediaPlayer != null) {            mediaPlayer.stop();            mediaPlayer.release();        }    }}




8.4.2 播放视频

播放视频文件主要是通过VideoView类来实现的(实际上VideoView底层同样是利用的MediaPlayer,只不过做了很好的封装),常用方法如下:


        VideoView 并不是一个万能的视频播放工具类,它在视频格式的支持以及播放效率方面都存在着较大的不足。所以,如果想要仅仅使用 VideoView就编写出一个功能非常强大的视频播放器是不太现实的。
        使用VideoView类播放视频文件的步骤跟MediaPlayer类基本一致,在此略过。

0 0