欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

安卓基础:多媒体、图片、音视频、摄像头、传感器

程序员文章站 2022-04-12 20:37:56
编程">多媒体编程 图片处理 加载大图片 Android 模拟器默认为每个应用分配的堆内存空间是16M 当加载大图片时,加载图片需要的内存空间不是按图片的大小来算的,而是按像...

图片处理

加载大图片

Android 模拟器默认为每个应用分配的堆内存空间是16M 当加载大图片时,加载图片需要的内存空间不是按图片的大小来算的,而是按像素点的多少来算的 图片加载到内存中需要把每一个像素都加载到内存中,容易造成OOM(OutOfMemoryError) 内存溢出致命错误

采用缩放方式加载图片

    public void click(View v) {
        //创建一个位图工厂的配置参数 
        BitmapFactory.Options options = new  Options();
        //解码器不去真正的解析位图   但是还能够获取图片的宽和高信息
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg",options);
        //[2]获取图片的宽和高信息 
        int imgWidth = options.outWidth;
        int imgHeight = options.outHeight;
        System.out.println("图片的宽和高:"+imgWidth+"----"+imgHeight);
        //[3]计算缩放缩放比 
        int scale = 1;
        int scaleX = imgWidth/width;
        int scaleY = imgHeight/height;
        if (scaleX>=scaleY && scaleX>scale) {
            scale = scaleX;
        }
        if (scaleY > scaleX && scaleY>scale) {
            scale = scaleY;
        }
        System.out.println("缩放比==:"+scale);
        //[4]安装缩放比进行显示 生物学  丁磊 
        options.inSampleSize = scale;  
        //[5]安装缩放比 进行解析位图 
        options.inJustDecodeBounds = false;
        Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg",options);
        //[6]把bitmap显示iv上
        iv.setImageBitmap(bitmap);  
    }

创建一个原图的副本

public class MainActivity extends Activity {

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

        //显示原图 
        ImageView iv_src = (ImageView) findViewById(R.id.iv_src); 
        //显示副本 
        ImageView iv_copy = (ImageView) findViewById(R.id.iv_copy);
        //[1]先把tomcat.png 图片转换成bitmap 显示到iv_src
        Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tomcat);

        //[1.1]操作图片 
//      srcBitmap.setPixel(20, 30, Color.RED);
        iv_src.setImageBitmap(srcBitmap);

        //[2]创建原图的副本    

        //[2.1]创建一个模板  相当于 创建了一个大小和原图一样的 空白的白纸 
        Bitmap copybiBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
        //[2.2]想作画需要一个画笔 
        Paint paint = new Paint();
        //[2.3]创建一个画布  把白纸铺到画布上 
        Canvas canvas = new Canvas(copybiBitmap);
        //[2.4]开始作画  
        canvas.drawBitmap(srcBitmap, new Matrix(), paint);
        //[2.5]操作画出来的小猫图片 
        for (int i = 0; i < 20; i++) {
            copybiBitmap.setPixel(20+i, 30, Color.RED);
        }
        //[3]把copybimap显示到iv_copy上
        iv_copy.setImageBitmap(copybiBitmap);   
    }
}

图片操作API

图片的特效包括,图形的缩放、镜面、倒影、旋转、位移等。图片的特效是将原图的图形矩阵乘以一个特效矩阵,形成一个新的图形矩阵来实现 Matrix 维护了一个3*3 的矩阵去更改像素点的坐标

旋转,缩放,平移,镜面,倒影

public class MainActivity extends Activity {

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

        //显示原图 
        ImageView iv_src = (ImageView) findViewById(R.id.iv_src); 

        //显示副本 
        ImageView iv_copy = (ImageView) findViewById(R.id.iv_copy);

        //[1]先把tomcat.png 图片转换成bitmap 显示到iv_src
        Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tomcat);

        //[1.1]操作图片 
//      srcBitmap.setPixel(20, 30, Color.RED);
        iv_src.setImageBitmap(srcBitmap);

        //[2]创建原图的副本    

        //[2.1]创建一个模板  相当于 创建了一个大小和原图一样的 空白的白纸 
        Bitmap copybiBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
        //[2.2]想作画需要一个画笔 
        Paint paint = new Paint();
        //[2.3]创建一个画布  把白纸铺到画布上 
        Canvas canvas = new Canvas(copybiBitmap);
        //[2.4]开始作画  
        Matrix matrix = new Matrix();

        //[2.5]对图片进行旋转 
        //matrix.setRotate(20, srcBitmap.getWidth()/2, srcBitmap.getHeight()/2);

        //[2.5]对图片进行缩放
//      matrix.setScale(0.5f, 0.5f);

        //[2.6]对图片进行平移
//      matrix.setTranslate(30, 0);

        //[2.7]镜面效果  如果2个方法一起用 
//      matrix.setScale(-1.0f, 1);
        //post是在上一次修改的基础上进行再次修改  set 每次操作都是最新的 会覆盖上次的操作
//      matrix.postTranslate(srcBitmap.getWidth(), 0);

        //[2,7]倒影效果
        matrix.setScale(1.0f, -1);
        //post是在上一次修改的基础上进行再次修改  set 每次操作都是最新的 会覆盖上次的操作
        matrix.postTranslate(0, srcBitmap.getHeight());
        canvas.drawBitmap(srcBitmap,matrix , paint);

        //[3]把copybimap显示到iv_copy上
        iv_copy.setImageBitmap(copybiBitmap);

    }
}

模拟画图功能

原理:
Android 中只有View 才可以捕获到用户触摸的事件
ImageView 控件可以设置一个触摸事件的监听器来监听触摸事件,重写OnTouchListener 的onTouch 方法,结合Canvas 类,即可实现随手涂鸦的画板功能

TIPS:
onTouch 方法的返回值默认是false 的,必须设置为true,否则触摸事件将不会被处理

触摸事件:
MotionEvent.ACTION_DOWN 按下
MotionEvent.ACTION_MOVE 移动
MotionEvent.ACTION_UP 抬起

代码

public class MainActivity extends Activity {

    private Bitmap srcBitmap;
    private ImageView iv;
    private Bitmap copyBitmap;
    private Paint paint;
    private Canvas canvas;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 用来显示我们画的内容

        iv = (ImageView) findViewById(R.id.iv);
        // [1]获取原图 bg
        srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg);    

        // [2]获取原图的副本 相当于是一个空白 的白纸
        copyBitmap = Bitmap.createBitmap(srcBitmap.getWidth(),
                srcBitmap.getHeight(), srcBitmap.getConfig());
        // 创建画笔
        paint = new Paint();
        // 创建一个画布
        canvas = new Canvas(copyBitmap);
        // 开始作画
        canvas.drawBitmap(srcBitmap, new Matrix(), paint);
        // canvas.drawLine(20, 30, 50, 80, paint);
        iv.setImageBitmap(copyBitmap);

        // [3]给iv设置一个触摸事件
        iv.setOnTouchListener(new OnTouchListener() {
            int startX = 0;
            int startY = 0;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // 获取当前事件类型
                int action = event.getAction();
                switch (action) {
                case MotionEvent.ACTION_DOWN: // 按下
                    System.out.println("摸view");
                    // 获取开始位置 (划线)

                    startX = (int) event.getX();
                    startY = (int) event.getY();

                    break;

                case MotionEvent.ACTION_MOVE:// 移动
                    System.out.println("移动");
                    // 获取结束位置
                    int stopX = (int) event.getX();
                    int stopY = (int) event.getY();
                    // [不停的画线]
                    canvas.drawLine(startX, startY, stopX, stopY, paint);
                    // 在次显示到iv上
                    iv.setImageBitmap(copyBitmap);

                    // 更新一下开始坐标和结束坐标
                    startX = stopX;
                    startY = stopY;

                    break;

                case MotionEvent.ACTION_UP:// 抬起
                    System.out.println("抬起");
                    break;
                }

                // True if the listener has consumed the event, false otherwise
                return true; // true 监听器处理完事件了
            }
        });

    }

    // 点击按钮 改变画笔的颜色
    public void click1(View v) {
        paint.setColor(Color.RED);
    }

    // 点击按钮 对画笔加粗
    public void click2(View v) {
        paint.setStrokeWidth(15);
    }

    // 点击按钮 对画笔加粗
    public void click3(View v) {

        /**
         * format 保存图片的格式
         * quality 保存图片的质量 
         * SystemClock.uptimeMillis() 这个是当前手机的开机时间
         */
        try {
            File file = new File(Environment.getExternalStorageDirectory().getPath(),SystemClock.uptimeMillis()+".png");
            FileOutputStream fos = new FileOutputStream(file);      
            copyBitmap.compress(CompressFormat.PNG, 100, fos);

            //发送一条广播 欺骗系统图库的应用 
            Intent intent = new Intent();
            //设置action
            intent.setAction(Intent.ACTION_MEDIA_MOUNTED);
            intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));
            //发送一条广播
            sendBroadcast(intent);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

撕衣服案例

原理:
一张图片有衣服,一张图片没有衣服。
没有衣服的图片放置在下面,有衣服的图片放置在上面,
为在上面的ImageView 设置触摸的事件,
当手指触摸到图片上时,将手指触摸的点周边的上层图片的像素点设置为透明的,就会出现一个撕衣服的效果。

代码

public class MainActivity extends Activity {

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

        //用来显示 操作后的图片
        final ImageView iv = (ImageView) findViewById(R.id.iv);

        //[1]获取要操作图片 原图
        Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pre19);

        //[2]创建一个副本   相当于有一个和原图大小的白纸
        final Bitmap alterBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
        //创建画笔
        Paint paint = new Paint();
        //创建画布   把白纸铺到画布上
        Canvas canvas = new Canvas(alterBitmap);
        //开始作画 
        canvas.drawBitmap(srcBitmap, new Matrix(), paint);

        iv.setImageBitmap(alterBitmap);

        //[3]给vi设置一个触摸事件 
        iv.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //[4]具体判断一下触摸事件 
                switch (event.getAction()) {

                case MotionEvent.ACTION_MOVE://移动事件

                    for (int i = -7; i < 7; i++) { //增加X轴坐标

                        for (int j = -7; j < 7; j++) {
                                                   //增加Y轴坐标

                            //为了良好的用户体验  撕一个圆 
                            if (Math.sqrt(i*i+j*j)<7) {
                                try {
                                    alterBitmap.setPixel((int)event.getX()+i, (int)event.getY()+j, Color.TRANSPARENT);
                                } catch (Exception e) {
                                }
                            }

                        }
                    }

                    //更新一下iv
                    iv.setImageBitmap(alterBitmap);
                    break;
                }
                return true;
            }
        }); 
    }
}

音频播放

MediaPlayer

流程图
安卓基础:多媒体、图片、音视频、摄像头、传感器
该播放器同时只能播放一个音乐文件,文件大小并没有限制

SoundPool

SoundPool 和其他声音播放类相比,其特点是可以自行设置声音的品质、音量、播放比率等参数。并且它可以同时管理多个音频流,每个流都有独自的ID,对某个音频流的管理都是通过ID 进行的。

应用场景

程序中有些很短小音频需要经常播放,例如:游戏音效 如果使用MediaPlayer 每次加载音频、播放、再释放,这样很费事 我们可以使用音频池一次性加载多个音频,需要哪个就直接播放 SoundPool 最大只能申请1M 的内存空间,这就意味着我们只能用一些很短的声音片段 SoundPool 提供了pause 和stop 方法,把缓冲区里的数据播放完才会停下来,也许会多播放一秒钟

使用步骤

创建SoundPool 实例, 第一个参数用于指定最大可以加载声音个数
SoundPool soundPool=new SoundPool(3,AudioManager.STREAM_MUSIC, 0);
加载不同的声音文件,生成各自的声音id
int shoot1ID = soundPool.load(this, R.raw.shoot1, 1);
int shoot2ID = soundPool.load(this, R.raw.shoot2, 1);
int shoot3ID = soundPool.load(this, R.raw.shoot3, 1);
根据load 方法获取的id 播放对应的声音
soundPool.play(shoot1ID, 1, 1, 1, 0, 1);
soundPool.play(shoot2ID, 1, 1, 1, 0, 1);
soundPool.play(shoot3ID, 1, 1, 1, 0, 1);

模拟实现音频播放器

TIPS:
播放网络音乐应使用异步播放,设置一个准备完成的监听

public class MainActivity extends Activity {


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

    //点击按钮 播放一个音频文件 
    public void click(View v) {
        //[1]初始化mediaplayer 
        final MediaPlayer mediaPlayer = new MediaPlayer();
        //[2]设置要播放的资源位置  path 可以是网络 路径 也可是本地路径
        try {
            mediaPlayer.setDataSource("https://192.168.11.86:8080/xpg.mp3");
            //[3]准备播放
            mediaPlayer.prepareAsync();

            //[3.1]设置一个准备完成的监听 
            mediaPlayer.setOnPreparedListener(new OnPreparedListener() {

                @Override
                public void onPrepared(MediaPlayer mp) {

                    //[4]开始播放
                    mediaPlayer.start();
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
        }   
    }
}

模拟播放器代码

public class MainActivity extends Activity implements OnSeekBarChangeListener {
    private EditText et_path;
    private SeekBar sb;
    private TextView tv_time;
    private MediaPlayer player;
    private int duration;
    private boolean isUpdateBar;
    // 播放器的几个状态
    private static final int PLAYING = 1;// 播放状态
    private static final int PAUSING = 2;// 暂停状态
    private static final int STOPPING = 3;// 停止状态
    private int CURRENT = 0;// 当前状态

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 初始化界面控件
        et_path = (EditText) findViewById(R.id.et_path);
        sb = (SeekBar) findViewById(R.id.sb);
        // 给SeekBar 绑定滑动事件
        sb.setOnSeekBarChangeListener(this);
        tv_time = (TextView) findViewById(R.id.tv_time);
    }

    // 播放音乐
    public void play(View view) {
        if (player != null) {
            if (CURRENT == PLAYING) {
                return;
            } else if (CURRENT == PAUSING) {
                player.start();
                CURRENT = PLAYING;
                updateSeekBar();
                return;
            } else if (CURRENT == STOPPING) {
                player.reset();
                player.release();
            }
        }
        try {
            // 创建一个播放器对象
            player = new MediaPlayer();
            // 获取音乐路径
            String path = et_path.getText().toString();
            // 给播放器设置音乐路径
            player.setDataSource(path);
            // 设置音乐格式
            player.setAudioStreamType(AudioManager.STREAM_MUSIC);
            // 准备
            player.prepare();
            // 获取音乐最大长度(毫秒单位)
            duration = player.getDuration();
            // 给SeekBar 设置最大值
            sb.setMax(duration);
            // 格式化输出音乐长度
            String lastString = formatTime(duration);
            tv_time.setText("00:00/" + lastString);
            // 音乐开始播放
            player.start();
            // 更新SeekBar
            updateSeekBar();
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(this, "音乐播放失败" + e, 0).show();
        }
    }

    // 暂停
    public void pause(View view) {
        if (player != null && CURRENT == PLAYING) {
            player.pause();
            stopSeekBar();
            CURRENT = PAUSING;
        }
    }

    // 停止播放
    public void stop(View view) {
        if (player != null) {
            if (CURRENT == PLAYING || CURRENT == PAUSING) {
                player.stop();
                stopSeekBar();
                sb.setProgress(0);
                tv_time.setText("00:00/" + formatTime(duration));
                CURRENT = STOPPING;
            }
        }
    }

    // 重新播放
    public void replay(View view) {
        if (player != null) {
            stopSeekBar();
            CURRENT = STOPPING;
            play(view);
        }
    }

    // 停止SeekBar 更新
    private void stopSeekBar() {
        isUpdateBar = false;
    }

    // 更新SeekBar
    private void updateSeekBar() {
        isUpdateBar = true;
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (isUpdateBar) {
                    // 每秒更新一次
                    SystemClock.sleep(1000);
                    if (player != null && CURRENT == PLAYING) {
                        sb.setProgress(player.getCurrentPosition());
                        // 在主线程中运行如下代码更新EditText
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                String current = formatTime(player
                                        .getCurrentPosition());
                                String durationString = formatTime(duration);
                                tv_time.setText(current + "/" + durationString);
                            }
                        });
                    }
                }
            }
        }).start();
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
            boolean fromUser) {
        if (player != null) {
            player.seekTo(progress);
        }
    }

    // 开始拖动SeekBar 时停止更新SeekBar
    public void onStartTrackingTouch(SeekBar seekBar) {
        stopSeekBar();
    }

    // 停止拖动SeekBar 的时候将音乐定位到相应位置
    public void onStopTrackingTouch(SeekBar seekBar) {
        if (player != null) {
            player.seekTo(seekBar.getProgress());
            updateSeekBar();
        }
    }

    // 工具函数格式化播放时间
    private String formatTime(int current) {
        int second = current / 1000;
        int minute = second / 60;
        second = second - minute * 60;
        StringBuilder sb = new StringBuilder();
        sb.append(minute > 10 ? minute + "" : "0" + minute);
        sb.append(":");
        sb.append(second > 10 ? second : "0" + second);
        return sb.toString();
    }
}

视频播放

使用MediaPlayer+SurfaceView 播放视频

代码

public class MainActivity extends Activity {

    private MediaPlayer mediaPlayer;
    private int currentPosition; //当前视频播放的位置
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //[0]找到控件用来显示播放视频的内容
        final SurfaceView sfv = (SurfaceView) findViewById(R.id.sfv);

            //获取holder 对象 用来维护视频播放的内容
            SurfaceHolder holder = sfv.getHolder();

            //[0.1]添加holder 生命周期 方法 
            holder.addCallback(new Callback() {
                //当surface view 销毁 
                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {
                    System.out.println("surfaceDestroyed");
                    //停止播放视频 
                    if (mediaPlayer!=null && mediaPlayer.isPlaying()) {

                        //获取到当前播放视频的位置 

                        currentPosition = mediaPlayer.getCurrentPosition();
                        mediaPlayer.stop();
                    }   
                }

                //这个方法执行了 说明sufaceView准备好了 
                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                    //[1]初始化mediaplayer 
                    System.out.println("surfaceCreated");
                     mediaPlayer = new MediaPlayer();
                    //[2]设置要播放的资源位置  path 可以是网络 路径 也可是本地路径
                    try {
                        mediaPlayer.setDataSource("https://192.168.11.86:8080/cc.MP4");
                        //[3]准备播放
                        mediaPlayer.prepareAsync();

                        //[3.0]设置显示给sfv sufraceholder 是用来维护视频播放的内容
                        mediaPlayer.setDisplay(holder);

                        //[3.1]设置一个准备完成的监听 
                        mediaPlayer.setOnPreparedListener(new OnPreparedListener() {

                            @Override
                            public void onPrepared(MediaPlayer mp) {

                                //[4]开始播放
                                mediaPlayer.start();

                                //[5]继续上次的位置继续播放
                                mediaPlayer.seekTo(currentPosition);

                            }
                        });

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width,
                        int height) {
                }
            });
    }

}

使用vitamio控件播放

控件清单文件初始化配置

    
        
            
                

                
            
        




        

    

使用全命名的标签

    

代码

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 
           //  插件vitamio框架检查是否可用
           if (!LibsChecker.checkVitamioLibs(this)) {
                return;
            }
            final VideoView vv = (VideoView) findViewById(R.id.vv);
            vv.setVideoPath("https://192.168.11.86:8080/aa.avi");
            vv.setOnPreparedListener(new OnPreparedListener() {

                @Override
                public void onPrepared(MediaPlayer mp) {
                    vv.start();

                }
            });
            //设置video的控制器
            vv.setMediaController(new MediaController(this));
    }
}

摄像头

调用系统摄像头进行拍照和摄像,只需知道系统摄像头的action 和category 就可以调用系统摄像头。
Camera 类的action 和category




VideoCamera 类的action 和category




TIPS
由于希望在调用拍照或摄像功能后回到当前应用的界面,且得知拍照或摄像的结果如何,是否成功,所以在开启Activity 时不能使用startActivity 方法,而是使用startActivityForResult 方法开启Activity,并重写onActivityResult方法处理回传的数据。

代码示例

public class MainActivity extends Activity {

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

    //点击按钮进行照相
    public void click1(View v){

          Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
          File file = new File(Environment.getExternalStorageDirectory().getPath(),"haha.png");
          intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); // 保存图片的位置
            // start the image capture Intent
          startActivityForResult(intent, 1);

    }


    //点击按钮进行录像
        public void click2(View v){

              Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
              File file = new File(Environment.getExternalStorageDirectory().getPath(),"heheh.MP4");
              intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); // 保存图片的位置
                // start the image capture Intent
              startActivityForResult(intent, 2);

        }

    //当开启的Activity关闭的时候调用
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        System.out.println("哈哈哈");
        super.onActivityResult(requestCode, resultCode, data);
    }

}

传感器

Android 手机中内置了很多传感器,其主要类型有:方向、加速度(重力)、光线、磁场、距离(临近性)、温度等

方向传感器Sensor.TYPE_ORIENTATION 加速度(重力)传感器Sensor.TYPE_ACCELEROMETER 光线传感器Sensor.TYPE_LIGHT 磁场传感器Sensor.TYPE_MAGNETIC_FIELD 距离(临近性)传感器Sensor.TYPE_PROXIMITY 温度传感器Sensor.TYPE_TEMPERATURE

获取传感器管理器SensorManager:
SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);
通过传感器管理器对象获得指定类型的传感器
Sensor sensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
通过传感器管理器对象获得手机中所有的传感器:

        //获取手机支持的所有传感器
        List sensorList = sm.getSensorList(Sensor.TYPE_ALL);
        for (int i = 0; i < sensorList.size(); i++) {
            Sensor sensor = sensorList.get(i);
            // 获取传感器名称
            String name = sensor.getName();
            // 获取传感器厂商
            String vendor = sensor.getVendor();
            // 获取传感器版本号
            int version = sensor.getVersion();
        }

使用传感器管理器对象注册传感器来使一个传感器工作

        /*
         * 注册一个传感器 第二个参数Sensor 是具体某个传感器对象 第三个参数是设定传感器采样频率
         */
        sm.registerListener(new SensorEventListener() {
            // 当传感器值改变时触发该函数
            @Override
            public void onSensorChanged(SensorEvent event) {
                Toast.makeText(MainActivity.this, "" + event.accuracy, 0)
                        .show();
            }

            // 当传感器精确度更改是触发该函数
            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
                Toast.makeText(MainActivity.this, "" + accuracy, 1).show();
            }
        }, sensor, SensorManager.SENSOR_DELAY_NORMAL);
listener :传感器事件监听器 sensor :要被注册的传感器对象 rate :采样率,分为最快、游戏、普通、用户界面几种当应用程序请求特定的采样率时,其实只是对传感器子系统的一个建议,不保证特定的采样率可用。

采样率的四种类型详解:
最快: SensorManager.SENSOR_DELAY_FASTEST
最低延迟,一般不是特别敏感的处理不推荐使用,该种模式可能造成手机电力大量消耗,由于传递的为原始数据,算法不处理好将会影响游戏逻辑和UI 的性能
游戏: SensorManager.SENSOR_DELAY_GAME
游戏延迟,一般绝大多数的实时性较高的游戏都使用该级别
普通: SensorManager.SENSOR_DELAY_NORMAL
标准延迟,对于一般的益智类或EASY 级别的游戏可以使用,但过低的采样率可能对一些赛车类游戏有跳帧现象
用户界面: SensorManager.SENSOR_DELAY_UI
一般对于屏幕方向自动旋转使用,相对节省电能和逻辑处理,一般游戏开发中我们不使用

案例手机防盗

当手机从衣服兜里被掏出时,手机响铃报警
原理:
使用距离传感器,当距离从0 变为1 时,使用MediaPlayer 播放声音文件报警

继承SensorEventListener 并覆写抽象方法

    public void onSensorChanged(SensorEvent event) {
        // 获取距离传感器的值
        float value = event.values[0];
        if (value > 0) {
            try {
                // 如果距离大于0 则播放音乐
                player.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            // 如果距离等于0 暂停音乐
            player.pause();
        }
    }