手机多媒体-通知和调用相机

在当今的手机当中,除了打电话和发短信,最长用的功能就是听歌,看视频,玩游戏,看新闻这些多媒体应用了。

今天抛开手机应用本身,站在开发者角度去实现一些主流的功能,例如:在我们玩微信,玩QQ时,当我们的这些应用在后台运行时,这个时候来消息,

通常我们的状态栏(也就是手机的最上方)会出现一个消息提醒,当然像很多很多其他的应用,今日头条有新新闻时,上方也会弹出消息提醒,等等。

-------------Notification。

当我们新下载一个应用,注册账号时,通常可以更换联系人头像,当点击更换时,通常有两种方式可以实现选择自己想要更换的相片,一种是:直接

进入相机拍照,另一种是:从当前图库中有的图片选择。 ----------------调用摄像头和相册功能。

一  Notification

首先我们来看下Notification功能,如果我们想实现一个Notification功能,我们应该怎么做?

上面我们了解了通知的基本概念,下面我们就来看一下通知的使用方法吧,首先通知的用法还是很灵活的,既可以在活动中创建,同时可以在广播中

创建,也可以在Service中创建,在活动中创建的还是比较少的,因为一般都只有当应用在后台时才需要使用通知。

1.首先我们需要一个NotificationManager来对通知进行管理,可以调用Context.getSystemService()来获得。

NotificationManager  manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

显示一个通知的方式为:manager.notify(1,notification);//第一个参数为id,要保证每个通知所指定的id都是不同的,第二个参数则是

Notification对象。

2.需要使用Builder构造器来构造一个Notification对象,但是几乎所有的android系统每个版本都会对通知做一些大大小小的修改,api不稳定的

问题在通知上显得尤其严重,那么我们最好的办法就是使用support库中提供的api,support-v4就提供了一个NotificationCompat类,我们

可以使用这个类来构造notification对象。

Notification notification = new  NotificationCompat.Builder(context).build();

当然上面只是创建了一个空的Notification对象并没有实际的作用,我们可以在build()之前设置任意多的方法来丰富这个notification对象。

下面我以一个简单的例子来创建一个包含Notification常用设置的通知。

效果图:

注册一个按钮发送通知消息                                                  下拉状态栏后通知显示的状态 

                                  


这里帖上创建通知的代码及布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.ruiwei.multimedia_practice.MainActivity">

    <Button
        android:id="@+id/send_notification"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send normal notification" />
</RelativeLayout>
public class MainActivity extends AppCompatActivity {
    private Button send_notification;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        send_notification = (Button) findViewById(R.id.send_notification);
        send_notification.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //当点击通知按钮能执行某项意图,我们可以使用setContentIntent,setContenIntent接收一个参数(pandingIntent);
                Intent intent = new Intent(MainActivity.this,Main2Activity.class);
                PendingIntent pi  = PendingIntent.getActivity(MainActivity.this,0,intent,0);
                //首先获取notification manager 的对象,通过context.getSystemService().
                NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                Notification notification =  new NotificationCompat.Builder(MainActivity.this)
                        .setContentTitle("This is content title") //设置通知title
                        //.setContentText("You have been working for three years and can apply for a 15k pay raise. Please apply.")
                        .setWhen(System.currentTimeMillis())//设置通知显示时间
                        .setSmallIcon(R.mipmap.samll_icon)//设置通知显示图标
                        //.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.samll_icon))
                        .setContentIntent(pi) //设置通知的延迟事件
                        //.setSound(Uri.fromFile(new File("/system/media/audio/ringtone/"))) 设置通知铃声
                        .setVibrate(new long[]{0,1000,1000,1000})  //设置发送通知时手机振动
                        .setLights(Color.BLUE,1000,1000)  //设置呼吸灯提醒
                        .setAutoCancel(true) //当通知被点击后,自动被移除掉当前通知状态
                        //设置通知中的content 为大图片
                        .setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(),R.drawable.d)))
                       . setPriority(NotificationCompat.PRIORITY_MAX)
                        .build();
                notificationManager.notify(1,notification);
            }
        });

    }
}

通知的常用属性都在上面有设置,还有一个setPriority()方法,setPriority方法接收一个参数用于设置这条通知的重要程度。

一共有5个常量值可选:

PRIORITY_DEFAULT,默认的与不设置一样。

PRIORITY_MIN表示最低的重要程度系统只会在特定的场景才会显示这条通知、

PRIORITY_LOW表示较低的重要程度,系统可能会讲这类通知缩小,或者改变其显示的顺序,并将其放在更重要的通知之后。

PRIORITY_HIGHT表示较高的重要程度,系统可能会将改通知放大,或改变其显示的顺序,将其放在比较靠前的位置。

PRIORITY_MAX表示最高的重要程度,这类通知必须让用户立刻看见。甚至需要用户做出相应操作。

具体写法:

Notification notification = new NotificationCompat.Builder(this).

. . .

.setPriority(NotificationCompat.PRIORITY_MAX);

. . .

二  调用摄像头拍照

如何才能在应用程序里调用手机的摄像头进行拍照?

新建一个CameraAlbumTest项目,然后修改activity_main.xml的代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ruiwei.cameraalbumtest.MainActivity">

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/entry_camera"
    android:text="camera"/>
 <ImageView
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:id="@+id/display_picture"
     android:layout_below="@+id/entry_camera"
     />
</RelativeLayout>

可以看见,布局中只有两个控件,一个是button和一个imageView.button是用于打开摄像头进行拍照的,而ImageView则是用于将拍摄

的图片显示出来。我把调用摄像头并显示出来的代码帖在下面,再做分析:

public class MainActivity extends AppCompatActivity {
    private Button entry_camera;
    private ImageView display_picture;
    private Uri imageUri;
    public static final int TAKE_PHOTE =1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        entry_camera = (Button) findViewById(R.id.entry_camera);
        display_picture = (ImageView) findViewById(R.id.display_picture);

        entry_camera.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                File outputImage = new File(getExternalCacheDir(),"outputImage.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.ruiwei.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_PHOTE);
            }
        });

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch(requestCode){
            case TAKE_PHOTE:
                if(requestCode == RESULT_OK){
                    try {
                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                        display_picture.setImageBitmap(bitmap);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
                break;
            default:
                break;
        }
    }
}

上面的代码其实不是很复杂,在MainActivity中要做的第一件事就是获取两个控件button 和 imagevies的实例,

并给button注册点击事件,然后在点击事件里开始处理调用摄像头的逻辑,我们重点看一下这一步代码。

首先:这里创建了一个File对象,用于存放摄像头拍下的照片,这里我们把图片命名为outputimage.jpg,并将它存放在当前应用的缓存数据目录下。

调用getExternCacheDir()方法就能得到这个目录。具体的路径是/sdcard/Android/data/<package name>/cache.只所以要使用缓存目录来存放

图片是因为从android6.0开始,读写SD卡别列为危险权限,如果将图片存放在SD卡的任何其他目录,都要进行运行时权限的处理才行。

其次:接着会进行一个判断,如果运行设备的系统低于android7.0,就调用Uri.fromFile()方法将File对象转换成Uri对象,这个Uri对象标识着outputImage

这张图片的本地真是路径,否则就调用FileProvider的getUriForFile()方法将File对象转换成一个封装过得Uri对象。

getUriForFile()方法接收三个参数,第一个为为context对象,第二个可以是任意唯一的字符串,第三个则是我们刚刚创建的File对象。之所以要进行这样

一层转换,是因为android7.0系统开始,直接使用本地真是路径的Uri是认为不安全的。会抛出一个FileUriExposedException异常。而FileProvider则是一个

特殊的内容提供器,它使用了和内容提供器类似的机制对数据进行保护,可以选择性的将封装过得Uri共享给外部,从而提高了应用的安全性。

然后:接下来会构建出一个Intent对象,并将这个Intent的action指定为:android.media.aciton.IMAGE_CAPTURE,再调用Intent的putExtra()方法

指定图片的输出地址,这里填入了刚刚得到的URI对象,最后调用startActivityResult来启动这个活动。

最后:由于刚才我们是使用startActivityResult来启动活动的,因此拍完照会有结果返回到onActivityResult()方法中.如果拍照成功,就可以调用

Bitmap.factory的decodeStream方法将outputImage.jpg这张图片解析成Bitmap对象,然后把他设置成imageView中显示出来。

我们需要注意的两点是:

刚才用到了FileProvider,自然的要再AndroidManifest.xml中对内容提供器进行注册下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.ruiwei.cameraalbumtest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <provider
        android:name = "android.support.v4.content.FileProvider"
        android:authorites="com.ruiwei.cameraabumtest.fileprovider"
        android:exported="flase"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths"/>
    </provider>
</manifest>

android :name 属性的值是固定的。

android:authorities属性的值必须要和刚才FileProvider.getUriForFile()方法中的第二个参数一致。

另外这里还在<provider>标签的内部使用了<meta-data>来指定Uri共享的路径,并引用了一个@xml/file_paths资源,

这个资源需要我们在res/目录下创建一个目录,接着创建一个file文件名为:file_paths.xml

 <paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path=""/>
</paths>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值