第一行代码——第八章:丰富你的程序——运用手机多媒体

目录:

8.1 将程序运行到手机上

8.2 使用通知

8.2.1 通知的基本用法

8.2.2 通知的进阶技巧

8.2.3 通知的高级功能

8.3 调用摄像头和相册

8.3.1 调用摄像头拍照

8.3.2 从相册中选择照片

8.4 播放多媒体文件

8.4.1 播放音频

8.4.2 播放视频

8.5 小结与点评


知识点:

8.1 将程序运行到手机上

打开手机开发者模式-USB 调试 (有些手机还有通过USB安装应用程序) 

在设置中找不到开发者模式的话 需要点击系统版本 打开开发者

若仍然在AS中找不到手机,可能驱动未安装成功

本人解决方法:使用360手机助手 搞定的。

8.2 使用通知

8.2.1 通知的基本用法

通知的用法灵活,既可以在活动里创建,也可在广播接收器里创建,还可在服务里创建。

Intent intent = new Intent(this, OtherNoticeActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);

        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//        manager.cancel(1);  退出指定通知
        //channelId  渠道id
        Notification notification = new NotificationCompat.Builder(this,"chat")
                .setContentTitle("This is content title")
                .setContentText("this is content text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                .setAutoCancel(true)
                .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))
                //
                .setVibrate(new long[]{0, 1000, 1000, 1000})//设置静止震动时长  震动1秒 静止1秒 在震动1秒
                .setLights(Color.GREEN, 1000, 1000)//灯光
//                .setDefaults(NotificationCompat.DEFAULT_ALL)//根据当前情况来决定播放什么铃声,以及如何震动
                .setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(),R.mipmap.jelly_fish)))
                .setPriority(NotificationCompat.PRIORITY_HIGH)//显示级别  横幅
                .setContentIntent(pendingIntent)
//                .setFullScreenIntent(pendingIntent,true)//响应紧急事件 比如来电 直接跳转
                .build();

        manager.notify(1,notification);

8.2.2 通知的进阶技巧

上面提到了通知的基本用法,接下来介绍一些通知的其他技巧,比如:

在通知发出时播放一段音频,调用 setSound() 方法:

Notification notification = new NotificationCompat.Builder(this)
        . . .
        .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg"))) // 在音频目录下选个音频文件
        .build();

在通知到来时让手机振动,设置 vibrate 属性:

Notification notification = new NotificationCompat.Builder(this)
        . . .
        .setVibrate(new long[]{0,1000,1000,1000}) // 数组下标0表静止的时长,下标1表振动的时长,下标2表静止的时长,以此类推
        .build();

当然别忘了声明振动权限:


在通知到来时显式手机 LED 灯,调用 setLights() 方法:

Notification notification = new NotificationCompat.Builder(this)
        . . .
        .setLights(Color.GREEN,1000,1000) // 三个参数:LED 灯的颜色、灯亮时长、灯暗时长
        .build();

当然也可直接使用默认效果,如下:

Notification notification = new NotificationCompat.Builder(this)
        . . .
        .setDefaults(NotificationCompat.DEFAULT_ALL)
        .build();

8.2.3 通知的高级功能

NotificationCompat.Builder 类中的 setStyle() 方法

setStyle() 方法接收一个 NotificationCompat.style 参数,这个参数用来构造具体的富文本信息,如长文字、图片等。

https://segmentfault.com/a/1190000008241257

8.3 调用摄像头和相册

8.3.1 调用摄像头拍照

8.3.2 从相册中选择照片

调用摄像头和相册 是非常常用的功能,在这里,我们不仅实现了掉用摄像头和相册,同时也对于Android 7.0 系统进行了适配,主要的一点就是 获取Uri 相关连的代码,在返回结果的时候也是需要我们对于Uri进行解析,请看代码:

package com.dak.administrator.firstcode.multi_media;

import android.Manifest;
import android.annotation.TargetApi;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.Image;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Toast;

import com.dak.administrator.firstcode.R;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;

public class CameraAlbumActivity extends AppCompatActivity {

    private ImageView picture;
    private static final int TAKE_PHOTO = 1;
    private static final int CHOOSE_PHOTO = 2;
    private Uri imageUri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_album);

        picture = findViewById(R.id.picture);

        Button takePhoto = findViewById(R.id.take_photo);
        takePhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                openCamera();
            }
        });

        Button fromAblum = findViewById(R.id.choose_from_album);
        fromAblum.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (ContextCompat.checkSelfPermission(CameraAlbumActivity.this,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(CameraAlbumActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                } else {
                    openAlbum();
                }

            }
        });
    }


    /**
     * 打开相机
     */
    private void openCamera() {

        //创建用处存储拍照后的图片
        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(CameraAlbumActivity.this,
                    "com.dak.administrator.firstcode.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);
    }

    /**
     * 打开相册
     * gallery
     */
    private 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) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    openAlbum();
                } else {
                    Toast.makeText(this, "请获取权限", Toast.LENGTH_SHORT).show();
                }
                break;
        }

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case TAKE_PHOTO:
                if (resultCode == RESULT_OK) {
                    try {
                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
//                        压缩 循环 太慢
//                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
//                        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
//                        int options = 100;
//                        while (baos.toByteArray().length / 1024 > 100) {//循环判断如果压缩后图片是否大于100kb,大于继续压缩
//                            baos.reset();//重置baos即清空baos
//                            bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
//                            options -= 10;//每次都减少10
//                        }
//                        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
//                        Bitmap comBitmap = BitmapFactory.decodeStream(bais);
                        picture.setImageBitmap(bitmap);

                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case CHOOSE_PHOTO:
                if (resultCode == RESULT_OK) {
                    if (Build.VERSION.SDK_INT >= 19) {
                        //4.4及以上系统使用这个方法处理图片
                        handleImageOnKitKat(data);
                    } else {
                        //4.4及以下系统使用这个方法处理图片
                        handleImageBeforeKitKat(data);
                    }
                }
                break;
        }
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void handleImageOnKitKat(Intent data) {
        String imagePath = null;
        Uri uri = data.getData();

        if (DocumentsContract.isDocumentUri(this, uri)) {
            //如果是document 类型的uri ,则通过document id处理

            String docId = DocumentsContract.getDocumentId(uri);
            if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
                //如果uri的authority是media格式 再次解析id 将字符串分割取出后半部分才能得到真正的数字id
                String id = docId.split(":")[1];//解析出数字格式的id
                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())) {
            //如果是content类型的uri,则使用普通方式处理
            imagePath = getImagePath(uri, null);
        } else if ("file".equalsIgnoreCase(uri.getScheme())) {
            //如果是file类型的uri,直接获取图片路径
            imagePath = uri.getPath();
        }
        displayImage(imagePath);//根据图片路径显示图片
    }

    private String getImagePath(Uri externalContentUri, String selection) {
        String path = null;
        //通过Uri和selection来获取真实图片路径
        Cursor cursor = getContentResolver().query(externalContentUri, 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_SHORT).show();
        }

    }

    private void handleImageBeforeKitKat(Intent data) {
        Uri uri = data.getData();
        String imagePath = getImagePath(uri, null);
        displayImage(imagePath);
    }


}

Xml页面:




    

在AndroidManifest.xml中配置Provider

 
        
        
        

            
            
        

第一行代码——第八章:丰富你的程序——运用手机多媒体_第1张图片

file_paths.xml



    
        

        

    

当然也别忘了声明访问SD卡的权限:


注意事项:在实际开发中最好根据项目的需求先对照片进行适当的压缩,然后再加载到内存中。

8.4 播放多媒体文件

  在安卓中播放音频文件一般用 MediaPlayer 类来实现,播放视频文件主要用 VideoView 类来实现。

MediaPlayer 常用方法:

MediaPlayer 构造方法
create 创建一个要播放的多媒体
getCurrentPosition 得到当前播放位置
getDuration 得到文件的时间
getVideoHeight 得到视频的高度
getVideoWidth 得到视频的宽度
isLooping 是否循环播放
isPlaying 是否正在播放
pause 暂停
prepare 准备(同步)
prepareAsync 准备(异步)
release 释放MediaPlayer对象相关的资源
reset 重置MediaPlayer对象为刚刚创建的状态
seekTo 指定播放的位置(以毫秒为单位的时间)
setAudioStreamType 设置流媒体的类型
setDataSource 设置多媒体数据来源(位置)
setDisplay 设置用SurfaceHolder来显示多媒体
setLooping 设置是否循环播放
setOnButteringUpdateListener 网络流媒体的缓冲监听
setOnErrorListener 设置错误信息监听
setOnVideoSizeChangedListener 视频尺寸监听
setScreenOnWhilePlaying 设置是否使用SurfaceHolder来保持屏幕显示
setVolume 设置音量
start 开始播放
stop 停止播放

  VideoView和MediaPlaer也比较类似,主要有以下常用方法:

setVideoPath()

设置要播放的视频文件的位置。

start()

开始或继续播放视频。

pause()

暂停播放视频。

resume()

将视频重头开始播放。

seekTo()

从指定的位置开始播放视频。

isPlaying()

判断当前是否正在播放视频。

getDuration()

获取载入的视频文件的时长。

8.4.1 播放音频

package com.dak.administrator.firstcode.multi_media;

import android.Manifest;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.dak.administrator.firstcode.R;

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

public class MediaActivity extends AppCompatActivity implements View.OnClickListener {

    private MediaPlayer mediaPlayer = new MediaPlayer();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_media);

        Button play = findViewById(R.id.play);
        Button pause = findViewById(R.id.pause);
        Button stop = findViewById(R.id.stop);

        play.setOnClickListener(this);
        pause.setOnClickListener(this);
        stop.setOnClickListener(this);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }else {
            initMediaPlayer();
        }

    }

    private void initMediaPlayer() {
        try {
            File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");//music.mp3不存在
            mediaPlayer.setDataSource(file.getPath());
            mediaPlayer.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            initMediaPlayer();
        }else {
            Toast.makeText(this, "请获取存储权限", Toast.LENGTH_SHORT).show();
            finish();
        }
    }

    @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;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }

    }
}

xml文件:




    

8.4.2 播放视频

package com.dak.administrator.firstcode.multi_media;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.widget.VideoView;

import com.dak.administrator.firstcode.R;

import java.io.File;

public class VideoActivity extends AppCompatActivity implements View.OnClickListener {


    private VideoView videoView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video);

        Button play = findViewById(R.id.play);
        Button pause = findViewById(R.id.pause);
        Button replay = findViewById(R.id.replay);

        videoView = findViewById(R.id.video_view);

        play.setOnClickListener(this);
        pause.setOnClickListener(this);
        replay.setOnClickListener(this);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }else {
            initVideoPath();
        }
    }

    private void initVideoPath() {
        File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
        videoView.setVideoPath(file.getPath());

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            initVideoPath();
        }else {
            Toast.makeText(this, "请获取存储权限", Toast.LENGTH_SHORT).show();
            finish();
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.play:
                if (!videoView.isPlaying()) {
                    videoView.start();
                }
                break;
            case R.id.pause:
                if (videoView.isPlaying()) {
                    videoView.pause();
                }
                break;
            case R.id.replay:
                if (videoView.isPlaying()) {
                    videoView.resume();//重新播放
                }
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (videoView != null) {
            videoView.suspend();//释放资源
        }
    }
}

xml文件:




    

        

8.5 小结与点评

郭霖总结:

本章我们主要对Android系统中的各种多媒体技术进行了学习,其中包括通知的使用校在模调用摄像头拍照从相册中选取照片, 以及播放香城和视频文件。由于所涉及的多媒体技术住快拟器上很难看得到效果,因此本章中还特意讲解了在Android手机上调试程序的方法。

又是充实饱满的一章啊!现在多媒体方面的知识已经学得足够多了,我希望你可以很好地将它们消化掉,尤其是与通知相关的内容,因为后面的学习当中还会用到它。目前我们所学的所有东西都仅仅是在本地上进行的,而实际上几乎市场上的每个应用都会涉及网络交互的部分,所比下一章中我们将会学习一下Android网络编程方面的内容。

我的总结:

在调用摄像头和相册这一点,我也是学到了非常多的东西,平时因为用一些框架,很少回去研究这些东西,如今算是学到了这些我们必要的一些知识。

因为MediaPlayer 主要是在音乐相关的项目上用到,所以也多了一些印象,VideoView的话 他在视频格式的支持以及播放效率方面都存在这较大的不足,所以建议我们只是用于播放一些游戏的片头动画,或者某个应用的视频宣传等。。

你可能感兴趣的:(第一行代码,第一行代码知识点,Android,第一行代码,第八章)