阅读郭林《第一行代码》的笔记——第8章 丰富你的程序,运用手机多媒体

一、调用摄像头和相册

1、调用摄像头拍照

例子:
布局文件,这边很简单的,就放一个Button和一个ImageView,Button用来启动拍照图片并截图,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/btn_photo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Take Photo" />

    <ImageView
        android:id="@+id/img_photo"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center_horizontal" />

</LinearLayout>

Java代码:

package com.test.photo;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

import com.test.R;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * Created by Administrator on 2016/5/4 0004.
 */
public class PhotoActivity extends Activity {
    private static final int TAKE_PHOTO = 1;
    private static final int CROP_PHOTO = 2;
    private Button btnPhoto;
    private ImageView imgPhoto;
    private Uri imgUri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_photo);
        btnPhoto = (Button) findViewById(R.id.btn_photo);
        imgPhoto = (ImageView) findViewById(R.id.img_photo);
        btnPhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//创建一个File对象,用于存储摄像头拍下的图片,这里命名为outputImg.jpg,并将它存放在手机SD卡的根目录下
//Environment.getExternalStorageDirectory()这个方法就是获取到手机SD卡的根目录
                File outputImg = new File(Environment.getExternalStorageDirectory(), "tempImg.jpg");
                try {
                    if (outputImg.exists()) {
                        outputImg.delete();
                    }
                    outputImg.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
//调用Uri.fromFile 将File对象转化成Uri对象,这个Uri对象标识着outputImg.jpg这张图片的唯一地址
                imgUri = Uri.fromFile(outputImg);
//构建Intent对象,Intent的action指定为android.media.action.IMAGE_CAPTURE表示使用系统的拍照功能
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
//调用Intent的putExtra指定图片的输出地址,这边为刚刚得到的Uri(即imgUri)对象
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
                startActivityForResult(intent, TAKE_PHOTO); //启动活动
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case TAKE_PHOTO:
                if (resultCode == RESULT_OK) {
//构建Intent对象,Intent的action指定为com.android.camera.action.CROP 表示使用系裁剪图片
                    Intent intent = new Intent("com.android.camera.action.CROP");
//查看类型为image的数据
                    intent.setDataAndType(imgUri, "image/*");
//设置该图片可缩放
                    intent.putExtra("scale", true);
//调用Intent的putExtra指定图片的输出地址,这边为刚刚得到的Uri(即imgUri)对象
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
                    startActivityForResult(intent, CROP_PHOTO);//启动裁剪程序
                }
                break;
            case CROP_PHOTO:
                if (resultCode == RESULT_OK) {
                    try {
                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imgUri));
                        imgPhoto.setImageBitmap(bitmap);//将裁剪后的图片显示出来
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
                break;
        }
    }
}

AndroidManifest.xml文件中声明权限:

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

2、从相册中选择照片

例子:在上一个例子的基础上加一下内容,
布局文件:

……
    <Button
        android:id="@+id/btn_album"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Choose from Album" />
……
 Java代码:
    private Button btnAlbum;
  @Override
    protected void onCreate(Bundle savedInstanceState) {
    ……
    btnAlbum = (Button) findViewById(R.id.btn_album);
        btnAlbum.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//创建一个File对象,用于存储摄像头拍下的图片,这里命名为outputImg.jpg,并将它存放在手机SD卡的根目录下
//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();
                }
//调用Uri.fromFile 将File对象转化成Uri对象,这个Uri对象标识着outputImg.jpg这张图片的唯一地址
                imgUri = Uri.fromFile(outputImage);
//构建Intent对象,Intent的action指定为android.media.action.GET_CONTENT允许用户选择特殊的数据并返回
                Intent intent = new Intent("android.intent.action.GET_CONTENT");
//查看类型为image的数据
                intent.setType("image/*");
//设置该图片可裁剪
                intent.putExtra("crop", true);
//设置该图片可缩放
                intent.putExtra("scale", true);
//调用Intent的putExtra指定图片的输出地址,这边为刚刚得到的Uri(即imgUri)对象
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
                startActivityForResult(intent, CROP_PHOTO);
            }
        });
}
……

二、使用通知

通知(Notification)是Android系统中比较有特色的一个功能,当某个应用程序希望向用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知来实现。发出一条通知后,手机最上方的状态栏中会显示一个通知的图标,下拉状态栏后可以看到通知的详细内容。

1、通知的基本用法

通知的用法还是比较灵活的,既可以在活动里创建,也可以在广播接收器里创建,当然还可以在服务里创建。相比于广播接收器和服务,在活动里创建通知的场景还是比较少的,因为一般只有当程序进入到后台的时候我们才需要使用通知。
不过,无论是在哪里创建通知,整体的步骤都是相同的。
例子:

//NotificationManager用于管理通知,它也是一个系统服务,调用Context的getSystemService()方法获取到,getSystemService()方法接收一个字符串参数用于确定获取系统的哪个服务,这里我们传入 Context.NOTIFICATION_SERVICE即可。
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//点击通知后,就不显示通知了。这里传入一个参数是id,就是我们创建通知的时候指定的id
manager.cancel(1);
//Notification对象用于存储通知所需的各种信息,我们可以使用它的有参构造函数来进行创建。Notification的有参构造函数接收三个参数,第一个参数用于指定通知的图标,第二个参数用于指定通知的ticker内容,当通知刚被创建的时候,它会在系统的状态栏一闪而过,属于一种瞬时的提示信息。第三个参数用于指定通知被创建的时间,以毫秒为单位,当下拉系统状态栏时,这里指定的时间会显示在相应的通知上。
Notification notification = new Notification(R.mipmap.ic_launcher,"This is ticker text",System.currentTimeMillis());
//创建一个Intent意图,指明这个通知要做的事情
Intent intent = new Intent(this, NotificationActivity.class);
//PendingIntent从名字上看起来就和Intent有些类似,它们之间也确实存在着不少共同点。比如它们都可以去指明某一个“意图”,都可以用于启动活动、启动服务以及发送广播等。不同的是,Intent更加倾向于去立即执行某个动作,而PendingIntent更加倾向于在某个合适的时机去执行某个动作。所以,也可以把PendingIntent简单地理解为延迟执行的Intent。
//PendingIntent的用法同样很简单,它主要提供了几个静态方法用于获取PendingIntent的实例,可以根据需求来选择是使用getActivity()方法、getBroadcast()方法、还是getService()方法。这几个方法所接收的参数都是相同的,
//第一个参数依旧是Context,
//第二个参数一般用不到,通常都是传入0即可。
//第三个参数是一个Intent对象,我们可以通过这个对象构建出PendingIntent的“意图”。
//第四个参数用于确定PendingIntent的行为,有FLAG_ONE_SHOT、FLAG_NO_CREATE、FLAG_CANCEL_CURRENT和FLAG_UPDATE_ CURRENT这四种值可选,每种值的含义你可以查看文档,我就不一一进行解释了。
PendingIntent pi = PendingIntent.getActivity(this, 0, intent,PendingIntent.FLAG_CANCEL_CURRENT);
//调用Notification的setLatestEventInfo()方法就可以给通知设置一个标准的布局。这个方法接收四个参数,第一个参数是Context,第二个参数用于指定通知的标题内容,下拉系统状态栏就可以看到这部分内容。第三个参数用于指定通知的正文内容,同样下拉系统状态栏就可以看到这部分内容。第四个参数就是我们创建好的PendingIntent。
notification.setLatestEventInfo(this, "This is content title", "This is content text", pi);
//调用NotificationManager的notify()方法就可以让通知显示出来了。notify()方法接收两个参数,第一个参数是id,要保证为每个通知所指定的id都是不同的。第二个参数则是Notification对象,这里直接将我们刚刚创建好的Notification对象传入即可。
manager.notify(1,notification);

2、通知的高级技巧

1、在通知发出的时候播放一段音频:

//在指定音频文件的时候还需要先获取到音频文件对应的URI
Uri soundUri = Uri.fromFile(new File("/system/media/audio/ringtones/Basic_tone.ogg"));
notification.sound = soundUri;

2、在通知到来的时候让手机进行振动:

//vibrate是一个长整型的数组,用于设置手机静止和振动的时长,以毫秒为单位。下标为0的值表示手机静止的时长,下标为1的值表示手机振动的时长,下标为2的值又表示手机静止的时长,以此类推。所以,如果想要让手机在通知到来的时候立刻振动1秒,然后静止1秒,再振动1秒。
long[] vibrates = {0, 1000, 1000, 1000};
notification.vibrate = vibrates;

不过,想要控制手机振动还需要声明权限的。因此,我们还得编辑AndroidManifest.xml文件,加入如下声明:

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

3、在通知到来时控制手机LED灯的显示:

//ledARGB用于控制LED灯的颜色,一般有红绿蓝三种颜色可选。
notification.ledARGB = Color.GREEN;
//ledOnMS用于指定LED灯亮起的时长,以毫秒为单位。
notification.ledOnMS = 1000;
//ledOffMS用于指定LED灯暗去的时长,也是以毫秒为单位。
notification.ledOffMS = 1000;
//flags可用于指定通知的一些行为,其中就包括显示LED灯这一选项。
notification.flags = Notification.FLAG_SHOW_LIGHTS;

当然,如果你不想进行那么多繁杂的设置,也可以直接使用通知的默认效果,它会根据当前手机的环境来决定播放什么铃声,以及如何振动,写法如下:notification.defaults = Notification.DEFAULT_ALL;
注意,以上所涉及的这些高级技巧都要在手机上运行才能看得到效果,模拟器是无法表现出振动、以及LED灯闪烁等功能的。

三、接收和发送短信

1、接收和发送短信

接收短信
当手机接收到一条短信的时候,系统会发出一条值为 android.provider.Telephony.SMS_RECEIVED 的广播,这条广播里携带着与短信相关的所有数据。每个应用程序都可以在广播接收器里对它进行监听,收到广播时再从中解析出短信的内容即可。

class MessageReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
//从Intent参数中取出了一个Bundle对象
            Bundle bundle = intent.getExtras();
//使用pdu密钥来提取一个SMS pdus数组,其中每一个pdu都表示一条短信消息。

            Object[] pdus = (Object[]) bundle.get("pdus"); // 提取短信消息
//使用SmsMessage的createFromPdu()方法将每一个pdu字节数组转换为SmsMessage对象
            SmsMessage[] messages = new SmsMessage[pdus.length];
            for (int i = 0; i < messages.length; i++) {
                messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
            }
//调用这个对象的getOriginatingAddress()方法就可以获取到短信的发送方号码

            String address = messages[0].getOriginatingAddress(); // 获取发送方号码
            String fullMessage = "";
//调用getMessageBody() 方法就可以获取到短信的内容,然后将每一个 SmsMessage对象中的短信内容拼接起来,就组成了一条完整的短信。
            for (SmsMessage message : messages) {
                fullMessage += message.getMessageBody(); // 获取短信内容
            }
            sender.setText(address);
            content.setText(fullMessage);
        }

    }

我们还需要对它进行注册才能让它接收到短信广播。

private IntentFilter receiveFilter; 
private MessageReceiver messageReceiver;
@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);
        receiveFilter = new IntentFilter();
        receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
        messageReceiver = new MessageReceiver();
        registerReceiver(messageReceiver, receiveFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(messageReceiver);
    }

不过最后我们还需要给程序声明一个接收短信的权限才行,修改 AndroidManifest.xml中的代码:

 <uses-permission android:name="android.permission.RECEIVE_SMS" />
拦截短信

public class MainActivity extends Activity {
    ……
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ……
        receiveFilter = new IntentFilter();
        receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
        receiveFilter.setPriority(100);//设置优先级
        messageReceiver = new MessageReceiver();
        registerReceiver(messageReceiver, receiveFilter);
    }
     ……
    class MessageReceiver extends BroadcastReceiver {


        @Override
        public void onReceive(Context context, Intent intent) {
            ……
            abortBroadcast();//阻止广播的传递
        }


    }
}

发送短信

权限:

<uses-permission android:name="android.permission. SEND_SMS" />
    Intent sentIntent = new Intent("SENT_SMS_ACTION");
                PendingIntent pi = PendingIntent.getBroadcast (MainActivity.this, 0, sentIntent, 0);
                smsManager.sendTextMessage(to.getText().toString(), null,
msgInput.getText().toString(), pi, null);

四、播放多媒体文件

1、播放音频

在Android中播放音频文件一般都是使用MediaPlayer类来实现的,它对多种格式的音频文件提供了非常全面的控制方法,从而使得播放音乐的工作变得十分简单。下表列出了MediaPlayer类中一些较为常用的控制方法。
这里写图片描述

下面是一个例子:
布局文件:

<?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">

    <Button
        android:id="@+id/btn_play"
        style="@style/audio_btn"
        android:text="Play" />

    <Button
        android:id="@+id/btn_pause"
        style="@style/audio_btn"
        android:text="Pause" />

    <Button
        android:id="@+id/btn_stop"
        style="@style/audio_btn"
        android:text="Stop" />
</LinearLayout>

Java代码:
代码运行有错,一直播放不了音乐,待解决~

2、播放视频

播放视频文件其实并不比播放音频文件复杂,主要是使用VideoView类来实现的。这个类将视频的显示和控制集于一身,使得我们仅仅借助它就可以完成一个简易的视频播放器。VideoView的用法和MediaPlayer也比较类似,主要有以下常用方法:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/u010102829/article/details/52550275