Android

来源:互联网 发布:career frog 知乎 编辑:程序博客网 时间:2024/06/18 08:13

1.图形的表示方法

位图:

由许多点组成的点阵图。构成位图的点称为像素。目前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

矢量图:

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

2.如何加载图片到内存中

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

3.加载大图片时存在什么问题

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

4.加载大图片的处理方法

  1. 思路
    • 先获取图片的分辨率和手机的分辨率,计算出压缩比,加载时加载压缩后的图片
  2. 实现

    Bitmap bitmap = decodeSampledBitmapFromResource("mnt/sdcard/big.jpg", screenWidth, screenHeight);iv.setImageBitmap(bitmap);/** * 获取压缩后的图片 * @param pathName 图片的路径 * @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;  }

5.如何创建一个缩放的图片

  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);

6.矩阵的缩放、平移、旋转

//缩放,参数为: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);

7.矩阵的缩放、平移、旋转的叠加使用

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)

8.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) {    }});

9.控件的触摸监听事件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;//false代表的是事件没有处理完毕,等待事件处理完毕。true代表事件已经处理完毕了,事件结束被消费掉了,继续下一个事件。    }});

10.在代码里使用dip单位

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

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

11.保存bitmap到手机中

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

12.向手机里添加图片后,如何通知图库应用更新

  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);

13.设置bitmap某个像素点为某个颜色

//设置横坐标为x,纵坐标为y的点的颜色为colorBitmap.setPixel(int x, int y, int color)

14.getX和getRawX的区别

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

15.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));canvas.drawBitmap(srcBitmap, new Matrix(), paint);iv.setImageBitmap(copyedBitmap);

16.网络音乐的播放prepareAsync()

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

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

17.SoundPool的使用场景及使用方式

  1. 使用场景
    • 大量较短的音频文件需要播放时
  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);

18.使用系统提供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控制的是那一个VideoViewmc.setAnchorView(vv);//设置VideoView的控制器为mcvv.setMediaController(mc);//播放vv.start();

19.SurfaceView的作用、实现机制、特点

  1. 作用:单位时间内完成界面的大量多次更新,一般用于游戏开发
  2. 实现机制:双缓冲机制
    • A线程—-更新ui —–后台计算—更新ui
    • B线程—-后台计算—-更新ui —后台计算
  3. 特点:可以在子线程中更新UI
  4. 使用方式

    • 使用SurfaceHolder进行控制

      //拿到控制器SurfaceHolder holder = sv.getHolder();//获得画布Canvas canvas = holder.lockCanvas();//在画布上画canvas.drawXxx();...//将画好的图形输出的屏幕上holder.unlockCanvasAndPost(canvas);

20.SurfaceView的生命周期

  • SurfaceView占用的内存和cpu的开销很大,当界面完全可见的时候才被创建完毕,如果界面最小化就会被销毁.

    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大小发生了变化");    }});

21.使用SurfaceView播放视频的步骤

  1. 给MediaPlayer指定显示的控件

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

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

    mediaPlayer.seekTo(int milliseconds);

22.调用系统相机拍照的步骤

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

23.调用系统相机录视频的步骤

  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();}

24.传感器的使用

* 传感器(英文名称: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. 获取传感器管理器SensorManagersm = (SensorManager) getSystemService(SENSOR_SERVICE);//2. 获取某个传感器的引用,注册监听Sensor sensor = sm.getDefaultSensor(Sensor.TYPE_LIGHT);listener = new MyListnener();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];        System.out.println("光线强度:"+light);    }    //当传感器精度发生变化的时候调用的方法    @Override    public void onAccuracyChanged(Sensor sensor, int accuracy) {    }}

25.总结

  1. 图片处理
    1. 加载图片到内存——为后续在内存中操作图片做准备
    2. 加载大图片到内存——加载大图片很容易出现OOM
    3. 在内存中对图片进行平移、旋转、缩放,两种特殊效果:镜面和倒影
    4. 图片操作的案例:随手涂鸦和撕衣服
    5. 对图片颜色的处理
  2. 音乐播放
    1. 多媒体播放器的状态图
    2. 同步与异步播放音乐文件
    3. SoundPool的使用
  3. 视频播放
    1. 使用系统控件VideoView播放视频
    2. 使用SurfaceView播放视频
  4. SurfaceView
    1. SurfaceView的作用、实现机制、特点
    2. SurfaceView的生命周期
    3. SurfaceView的使用方式
  5. 调用系统摄像头进行拍照和录制视频
  6. 手机中传感器的使用
原创粉丝点击