Android基础图形的一些表示方法,SoundPool,VideoView,SurfaceView

本文主要是介绍Android基础图形的一些表示方法,SoundPool,VideoView,SurfaceView,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


##图形的表示方法
位图:由许多点组成的点阵图。构成位图的点称为像素。目前Android中使用的都是位图。(缺点是放大倍数过大,图片质量会失真)

位图大小的计算
1. 单色 = 1位 = 八分之一byte,每个像素占用八分之一byte  
    200 * 200 / 8 = 5000
2. 2的24次幂色(约1600万) = 24位 = 3byte,每个像素占用3byte  
    200 * 200 * 3 = 120000
3. 256色 = 8位 = 1byte,每个像素占用1byte  
    200 * 200 = 40000

矢量图(svj):矢量图形是通过计算机将一串线条和图形转换为一系列指令,在计算机中只存储这些指令,而不是像素。矢量图形看起来没有位图图像真实,但矢量图形的存储空间比位图图像要小得多,而且矢量图形通过拉伸、移动、放大等操作,图形不会产生实真。

##如何加载图片到内存中
    //加载一个图片到内存
    Bitmap bitmap = BitmapFactory.decodeFile("mnt/sdcard/big.jpg");

##加载大图片时存在什么问题
1. 存在的问题
    * 加载大图片会出现内存溢出的异常(OOM)
2. 产生的原因
    * Android中的图片使用32位的ARGB模式,A-透明度、R-红色值、G-绿色值、B-蓝色值。每个像素都要占用4个byte。
    * 用图片的分辨率乘以4就得到了图片在Android中所需的内存空间大约为15M,模拟器默认每个应用占用的内存为16M,所以就产生了内存溢出(OOM)

##加载大图片的处理方法
1. 思路
    
    * 先获取图片的分辨率和手机的分辨率,计算出压缩比,加载时加载压缩后的图片
2. 实现

        Bitmap bitmap = decodeSampledBitmapFromResource("mnt/sdcard/big.jpg", screenWidth, screenHeight);
        iv.setImageBitmap(bitmap);

        /**
         * 获取压缩后的图片
         * @param pathName 图片的路径11
         * @param reqWidth 要显示的宽
         * @param reqHeight 要显示的高
         */
        public static Bitmap decodeSampledBitmapFromResource(String pathName,  
            int reqWidth, int reqHeight) {  
            //1.第一次解析将inJustDecodeBounds设置为true,来获取图片大小  
            final BitmapFactory.Options options = new BitmapFactory.Options();  
            options.inJustDecodeBounds = true;  
            BitmapFactory.decodeFile(pathName, options);  
            
            //2.调用计算压缩比的工具方法,计算出 inSampleSize的值
            options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
            
            //3.使用计算好的压缩比,获得压缩后的图片
            options.inJustDecodeBounds = false;  
            return BitmapFactory.decodeFile(pathName, options);  
        }  

        /**
         * 计算压缩比
         * @param options 加载图片的参数
         * @param reqWidth 要显示的宽
         * @param reqHeight 要显示的高
         */
        public static int calculateInSampleSize(BitmapFactory.Options options,  
             int reqWidth, int reqHeight) {  
            //源图片的高度和宽度  
            final int height = options.outHeight;  
            final int width = options.outWidth;  
            int inSampleSize = 1;  
            
            //如果源图片的宽高大于要显示的宽高,则需要压缩
            if (height > reqHeight || width > reqWidth) {  
                // 计算出实际宽高和目标宽高的比率  
                final int heightRatio = Math.round((float) height / (float) reqHeight);  
                final int widthRatio = Math.round((float) width / (float) reqWidth);  
                // 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高  
                // 一定都会大于等于目标的宽和高。  
                inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;  
            }  
            return inSampleSize;  
        }

##如何创建一个缩放的图片
1. 创建一个空白的bitmap,宽高信息和原图保存一致

        Bitmap copyBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(),     srcBitmap.getConfig());
2. 创建一个画板
    
        Canvas canvas = new Canvas(copyBitmap);
3. 创建画笔

        Paint paint = new Paint();
4. 作画

        Matrix matrix = new Matrix();
        //matrix 变化矩阵     
        matrix.setScale(0.6f, 0.6f);
        canvas.drawBitmap(srcBitmap, matrix, paint);

##矩阵的缩放、平移、旋转
    //缩放,参数为:x轴的缩放比例,y轴的缩放比例
    matrix.setScale(0.6f, 0.6f);
    //平移,参数为:x轴的平移距离,y轴的平移距离
    matrix.setTranslate(100, 100);
    //旋转,参数为:旋转的角度,中心点的x轴坐标,中心点的y轴坐标
    matrix.setRotate(30, srcBitmap.getWidth()/2, srcBitmap.getHeight()/2);

##4eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee矩阵的缩放、平移、旋转的叠加使用
Matrix提供了四种操作:translate(平移)、rotate(旋转)、scale(缩放)、skew(倾斜)

1. pre是在队列最前面插入,post是在队列最后面追加,而set先清空队列在添加
2. 下面通过一些例子具体说明:

        matrix.preScale(2f,1f);    
        matrix.preTranslate(5f, 0f);   
        matrix.postScale(0.2f, 1f);    
        matrix.postTranslate(0.5f, 0f);  
        执行顺序:translate(5, 0) -> scale(2f, 1f) -> scale(0.2f, 1f) -> translate(0.5f, 0f)

        matrix.postTranslate(2f, 0f);   
        matrix.preScale(0.2f, 1f);     
        matrix.setScale(1f, 1f);   
        matrix.postScale(5f, 1f);   
        matrix.preTranslate(0.5f, 0f);   
        执行顺序:translate(0.5f, 0f) -> scale(1f, 1f) ->  scale(5f, 1)

##SeekBar的监听事件
    seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

        //停止滑动时调用,只调用一次
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            
        }

        //开始滑动时调用,只调用一次
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        //进度发生改变时调用,可能调用很多次
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress,
                boolean fromUser) {

        }
    });

##控件的触摸监听事件onTouchListener
* 触摸事件中有三个重要的事件
    * MotionEvent.ACTION_DOWN 按下,只触发一次
    * MotionEvent.ACTION_MOVE 移动,可触发多次
    * MotionEvent.ACTION_UP 抬起,只触发一次

* 随手涂鸦的核心逻辑

        iv.setOnTouchListener(new OnTouchListener() {
            int startX;
            int startY;
    
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    // 按下时记录起始位置
                    startX = (int) event.getX();
                    startY = (int) event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    // 移动后,记录移动后的位置,并在画布上画出这段距离
                    int newX = (int) event.getX();
                    int newY = (int) event.getY();
                    canvas.drawLine(startX, startY, newX, newY, paint);
                    iv.setImageBitmap(alterBitmap);

                    // 重新初始化起始位置
                    startX = (int) event.getX();
                    startY = (int) event.getY();
                    break;
                case MotionEvent.ACTION_UP:// 离开
                    break;
                }
                return true;
            }
        });

##在代码里使用dip单位
在代码里填写的数字一般都是以px为单位的,下面是将px转化为dip的方法

    DisplayMetrics displaysMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaysMetrics);             //密度
    int dipValue = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 320, displaysMetrics);

##保存bitmap到手机中
    File file = new File(Environment.getExternalStorageDirectory(),
            SystemClock.currentThreadTimeMillis() + ".jpg");
    FileOutputStream stream = new FileOutputStream(file);
    //参数分别为:图片格式,图片质量,输出流
    alterBitmap.compress(CompressFormat.JPEG, 100, stream);
    stream.close();

##向手机里添加图片后,如何通知图库应用更新
1. 发送一个SD卡挂载的广播

        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_MEDIA_MOUNTED);
        intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));
        sendBroadcast(intent);
2. 发送一个通知媒体扫描器扫描文件的广播

        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        intent.setData(Uri.fromFile(file));
        sendBroadcast(intent);
3. 直接使用MediaScannerConnection扫描文件
        
        MediaScannerConnection.scanFile(this, new String[]{file.toString()}, null, null);

##设置bitmap某个像素点为某个颜色
    //设置横坐标为x,纵坐标为y的点的颜色为color
    Bitmap.setPixel(int x, int y, int color)

##getX和getRawX的区别
![](http://i.imgur.com/KgxmKvF.png)

* getRowX:触摸点相对于屏幕的坐标
* getX: 触摸点相对于按钮的坐标
* getTop: 按钮左上角相对于父view的y坐标
* getLeft: 按钮左上角相对于父view的x坐标

##ColorMatrix的使用
    ColorMatrix cm = new ColorMatrix();
    cm.set(new float[] {
        1*result, 0, 0, 0, 0,     //红
        0, 1, 0, 0, 0,            //绿
        0, 0, 1, 0, 0,            //蓝
        0, 0, 0, 1, 0            //透明度
    });
    //设置颜色过滤器
    paint.setColorFilter(new ColorMatrixColorFilter(cm));
    //开始调整
    7
    canvas.drawBitmap(srcBitmap, new Matrix(), paint);
    iv.setImageBitmap(copyedBitmap);

##音乐播放状态图
![](http://i.imgur.com/CvexNKV.gif)

##网络音乐的播放prepareAsync()
播放网络上的音乐文件时,当网速较慢时,可能使界面卡住,所以要使用异步的prepare

    //异步的准备,开启子线程去准备
    mediaPlayer.prepareAsync();
    //设置准备完毕的回调事件
    mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            pd.dismiss();
            mediaPlayer.start();
        }
    });

##SoundPool的使用场景及使用方式
1. 使用场景
    * 大量较短的音频文件需要播放时内部双缓冲机制,能让两个线程同时工作
    可一直子线程中更新UI  (特例)
2. 使用方式

        //参数分别为:声音池中声音的最大数量,声音类型,声音质量(暂时没效果)
        SoundPool soundPool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
        //参数分别为:上下文,音频资源id,优先级(暂时没效果)
        soundID = soundPool.load(this, R.raw.shoot, 1);
        //参数分别为:音频id,左声道音量,右声道音量,优先级,循环模式(0不循环,-1一直循环),播放的速率
        soundPool.play(soundID, 1.0f, 1.0f, 0, 0, 1.0f);

##使用系统提供VideoView播放视频
1. 在布局文件中添加VideoView控件
        
        <VideoView
            android:id="@+id/vv"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
2. 代码
    
        //设置视频文件
        vv.setVideoPath("/mnt/sdcard/oppo.3gp");
    
        //设置控制器
        MediaController mc = new MediaController(this);
        //mc控制的是那一个VideoView
        mc.setAnchorView(vv);
        //设置VideoView的控制器为mc
        vv.setMediaController(mc);

        //播放
        vv.start();

##SurfaceView的作用、实现机制、特点(比较大所以使用svc模式)
1. 作用:单位时间内完成界面的大量多次更新,一般用于游戏开发
2. 实现机制:双缓冲机制
    * A线程----更新ui -----后台计算---更新ui
     * B线程----后台计算----更新ui  ---后台计算
3. 特点:可以在子线程中更新UI
4. 使用方式
    * 使用SurfaceHolder进行控制
    
            //拿到控制器
            SurfaceHolder holder = sv.getHolder();
            //获得画布
            Canvas canvas = holder.lockCanvas();
            //在画布上画
            canvas.drawXxx();
            ...
            //将画好的图形输出的屏幕上
            holder.unlockCanvasAndPost(canvas);

##SurfaceView的生命周期
* SurfaceView占用的内存和cpu的开销很大,当界面完全可见的时候才被创建完毕,如果界面最小化就会被销毁.
        //注册一个surffaceview的控制器回调 下面三个回调
        sv.getHolder().addCallback(new Callback() {
            
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                System.out.println("surface被销毁了");
            }
            
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                System.out.println("surface创建了");
            }
            
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                System.out.println("surfaceda大小发生了变化");
            }
        });

##使用SurfaceView播放视频的步骤
1. 给MediaPlayer指定显示的控件

        mediaPlayer.setDisplay(surfaceHolder);
2. 界面销毁时记录视频播放位置

        mediaPlayer.getCurrentPosition();
3. 界面重新创建时指定从上次记录的位置开始播放

        mediaPlayer.seekTo(int milliseconds);

##调用系统相机拍照的步骤
1. 使用隐式意图调用系统拍照界面

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        //设置生成照片的路径
        file = new File(Environment.getExternalStorageDirectory(),SystemClock.uptimeMillis()+".jpg");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
        startActivityForResult(intent, 0);
2. 在onActivityResult处理结果

        if(file!=null&&file.exists()&&file.length()>0){
            System.out.println(file.getAbsolutePath());
            ImageView iv = (ImageView) findViewById(R.id.iv);
            iv.setImageURI(Uri.fromFile(file));
        }

##调用系统相机录视频的步骤
1. 使用隐式意图调用系统录视频界面

        Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

        //设置生成视频的路径
        file = new File(Environment.getExternalStorageDirectory(),SystemClock.uptimeMillis()+".3gp");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
        startActivityForResult(intent, 0);
2. 在onActivityResult处理结果

        if(file!=null&&file.exists()&&file.length()>0){
            System.out.println(file.getAbsolutePath());
            VideoView vv= (VideoView) findViewById(R.id.vv);
            vv.setVideoPath(file.getAbsolutePath());
            MediaController mc = new MediaController(this);
            mc.setAnchorView(vv);
            vv.setMediaController(mc);
            vv.start();
        }

##传感器的使用
* 传感器(英文名称:sensor)是一种检测装置,能感受到被测量的信息,并能将感受到的信息,按一定规律变换成为电信号或其他所需形式的信息输出

        #define SENSOR_TYPE_ACCELEROMETER??????               1 //加速度
        #define SENSOR_TYPE_MAGNETIC_FIELD?????              2 //磁力
        #define SENSOR_TYPE_ORIENTATION???????   ?             3 //方向
        #define SENSOR_TYPE_GYROSCOPE??????????                4 //陀螺仪
        #define SENSOR_TYPE_LIGHT??????????????             5 //光线感应
        #define SENSOR_TYPE_PRESSURE??????????         ?     6 //压力
        #define SENSOR_TYPE_TEMPERATURE???????     ?         7 //温度
        #define SENSOR_TYPE_PROXIMITY??????????               8 //接近
        #define SENSOR_TYPE_GRAVITY????????????              9 //重力
        #define SENSOR_TYPE_LINEAR_ACCELERATION             10//线性加速度

* 陀螺仪又叫角速度传感器,是不同于加速度计(G-sensor)的,他的测量物理量是偏转、倾斜时的转动角速度。在手机上,仅用加速度计没办法测量或重构出完整的3D动作,测不到转动的动作的,G-sensor只能检测轴向的线性动作。但陀螺仪则可以对转动、偏转的动作做很好的测量,这样就可以精确分析判断出使用者的实际动作。而后根据动作,可以对手机做相应的操作
* 代码

        //1. 获取传感器管理器SensorManager
        sm = (SensorManager) getSystemService(SENSOR_SERVICE);  
    
        //2. 获取某个传感器的引用,注册监听
        Sensor sensor = sm.getDefaultSensor(Sensor.TYPE_LIGHT);
                            获取默认传感器            光传感器
        //返回所以的传感器                        
        //List<Sensor> sensors = sm.getSensorList(Sensor.TYPE_ALL);
        listener = new MyListnener();
        //三个参数         监听事件   传感器    rate:采样率敏感度使用 该类的常量表示
        sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
    
        //3.在监听器的回调事件中进行处理
        private class MyListnener implements SensorEventListener{
            //当传感器数据变化的时候调用的方法
            @Override
            public void onSensorChanged(SensorEvent event) {
                float light = event.values[0];
                //calues能获取各种传感器参数
                System.out.println("光线强度:"+light);
            }
            //当传感器精度发生变化的时候调用的方法
            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
                
            }
        }
        
        在activity的ondetory的方法中对监听器(监听传感器的那个监听器取消监听和注册)
        sm.unregisListenter(listener);
        listener=null;
       

这篇关于Android基础图形的一些表示方法,SoundPool,VideoView,SurfaceView的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/911681

相关文章

Android实现两台手机屏幕共享和远程控制功能

《Android实现两台手机屏幕共享和远程控制功能》在远程协助、在线教学、技术支持等多种场景下,实时获得另一部移动设备的屏幕画面,并对其进行操作,具有极高的应用价值,本项目旨在实现两台Android手... 目录一、项目概述二、相关知识2.1 MediaProjection API2.2 Socket 网络

Python中__init__方法使用的深度解析

《Python中__init__方法使用的深度解析》在Python的面向对象编程(OOP)体系中,__init__方法如同建造房屋时的奠基仪式——它定义了对象诞生时的初始状态,下面我们就来深入了解下_... 目录一、__init__的基因图谱二、初始化过程的魔法时刻继承链中的初始化顺序self参数的奥秘默认

html5的响应式布局的方法示例详解

《html5的响应式布局的方法示例详解》:本文主要介绍了HTML5中使用媒体查询和Flexbox进行响应式布局的方法,简要介绍了CSSGrid布局的基础知识和如何实现自动换行的网格布局,详细内容请阅读本文,希望能对你有所帮助... 一 使用媒体查询响应式布局        使用的参数@media这是常用的

Spring 基于XML配置 bean管理 Bean-IOC的方法

《Spring基于XML配置bean管理Bean-IOC的方法》:本文主要介绍Spring基于XML配置bean管理Bean-IOC的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一... 目录一. spring学习的核心内容二. 基于 XML 配置 bean1. 通过类型来获取 bean2. 通过

Android实现悬浮按钮功能

《Android实现悬浮按钮功能》在很多场景中,我们希望在应用或系统任意界面上都能看到一个小的“悬浮按钮”(FloatingButton),用来快速启动工具、展示未读信息或快捷操作,所以本文给大家介绍... 目录一、项目概述二、相关技术知识三、实现思路四、整合代码4.1 Java 代码(MainActivi

基于Python实现读取嵌套压缩包下文件的方法

《基于Python实现读取嵌套压缩包下文件的方法》工作中遇到的问题,需要用Python实现嵌套压缩包下文件读取,本文给大家介绍了详细的解决方法,并有相关的代码示例供大家参考,需要的朋友可以参考下... 目录思路完整代码代码优化思路打开外层zip压缩包并遍历文件:使用with zipfile.ZipFil

Python处理函数调用超时的四种方法

《Python处理函数调用超时的四种方法》在实际开发过程中,我们可能会遇到一些场景,需要对函数的执行时间进行限制,例如,当一个函数执行时间过长时,可能会导致程序卡顿、资源占用过高,因此,在某些情况下,... 目录前言func-timeout1. 安装 func-timeout2. 基本用法自定义进程subp

Android Mainline基础简介

《AndroidMainline基础简介》AndroidMainline是通过模块化更新Android核心组件的框架,可能提高安全性,本文给大家介绍AndroidMainline基础简介,感兴趣的朋... 目录关键要点什么是 android Mainline?Android Mainline 的工作原理关键

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

Python中判断对象是否为空的方法

《Python中判断对象是否为空的方法》在Python开发中,判断对象是否为“空”是高频操作,但看似简单的需求却暗藏玄机,从None到空容器,从零值到自定义对象的“假值”状态,不同场景下的“空”需要精... 目录一、python中的“空”值体系二、精准判定方法对比三、常见误区解析四、进阶处理技巧五、性能优化