A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小鲁哥哥 于 2016-12-9 17:44 编辑

【济南中心】Android课程同步笔记day10:Android应用开发基础

图形的位图表示方法
位图:由许多点组成的点阵图。构成位图的点称为像素。目前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
矢量图:矢量图形是通过计算机将一串线条和图形转换为一系列指令,在计算机中只存储这些指令,而不是像素。矢量图形看起来没有位图图像真实,但矢量图形的存储空间比位图图像要小得多,而且矢量图形通过拉伸、移动、放大等操作,图形不会产生实真。



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

处理方法:
思路:先获取图片的分辨率和手机的分辨率,计算出压缩比,加载时加载压缩后的图片
[AppleScript] 纯文本查看 复制代码
        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;
    }

创建一个缩放的图片
[Java] 纯文本查看 复制代码
     //加载一个图片到内存
        Bitmap srcBitmap = BitmapFactory.decodeFile("mnt/sdcard/big.jpg");
        //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);
##矩阵的缩放、平移、旋转的叠加使用
Matrix提供了四种操作:translate(平移)、rotate(旋转)、scale(缩放)、skew(倾斜)
1. pre是在队列最前面插入,post是在队列最后面追加,而set先清空队列在添加
2. 下面通过一些例子具体说明:

[Java] 纯文本查看 复制代码
        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)
[Java] 纯文本查看 复制代码
        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的监听事件
[Java] 纯文本查看 复制代码
        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
[Java] 纯文本查看 复制代码
                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为单位的,下面是将dp转化为px的方法

[Java] 纯文本查看 复制代码
        DisplayMetrics displaysMetrics = new DisplayMetrics(); 
        getWindowManager().getDefaultDisplay().getMetrics(displaysMetrics); 
        int dipValue = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 320, displaysMetrics);

保存bitmap到手机中
[Java] 纯文本查看 复制代码
        File file = new File(Environment.getExternalStorageDirectory(),
                        SystemClock.currentThreadTimeMillis() + ".jpg");
        FileOutputStream stream = new FileOutputStream(file);
        //参数分别为:图片格式,图片质量,输出流
        alterBitmap.compress(CompressFormat.JPEG, 100, stream);
        stream.close();

向手机里添加图片后,如何通知图库应用更新
1.发送一个SD卡挂载的广播
[Java] 纯文本查看 复制代码
                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_MEDIA_MOUNTED);
                intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));
                sendBroadcast(intent);

2. 发送一个通知媒体扫描器扫描文件的广播
[Java] 纯文本查看 复制代码
                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                intent.setData(Uri.fromFile(file));
                sendBroadcast(intent);

3. 直接使用MediaScannerConnection扫描文件
[Java] 纯文本查看 复制代码
                MediaScannerConnection.scanFile(this, new String[]{file.getAbsolutePath()}, null, null);

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


音乐播放状态图


网络音乐的播放prepareAsync()
播放网络上的音乐文件时,当网速较慢时,可能使界面卡住,所以要使用异步的prepare
[Java] 纯文本查看 复制代码
        //异步的准备,开启子线程去准备
        mediaPlayer.prepareAsync();
        //设置准备完毕的回调事件
        mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                        pd.dismiss();
                        mediaPlayer.start();
                }
        });

SoundPool的使用
一般要播放大量较短的音频文件时会用到SoundPool
使用方法
[Java] 纯文本查看 复制代码
                //参数分别为:声音池中声音的最大数量,声音类型,声音质量(暂时没效果)
                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控件
[XML] 纯文本查看 复制代码
                <VideoView
                android:id="@+id/vv"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

2. 代码
[Java] 纯文本查看 复制代码
                //设置视频文件
                vv.setVideoPath("/mnt/sdcard/oppo.3gp");
                //设置控制器
                MediaController mc = new MediaController(this);
                //mc控制的是那一个VideoView
                mc.setAnchorView(vv);
                //设置VideoView的控制器为mc
                vv.setMediaController(mc);
                //播放
                vv.start();

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

[Java] 纯文本查看 复制代码
                        //拿到控制器
                        SurfaceHolder holder = sv.getHolder();
                        //获得画布
                        Canvas canvas = holder.lockCanvas();
                        //在画布上画
                        canvas.drawXxx();
                        ...
                        //将画好的图形输出的屏幕上
                        holder.unlockCanvasAndPost(canvas);

SurfaceView的生命周期
SurfaceView占用的内存和cpu的开销很大,当界面完全可见的时候才被创建完毕,如果界面最小化就会被销毁
[Java] 纯文本查看 复制代码
                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. 使用隐式意图调用系统拍照界面
[Java] 纯文本查看 复制代码
        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处理结果
[Java] 纯文本查看 复制代码
                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. 使用隐式意图调用系统录视频界面

[Java] 纯文本查看 复制代码
        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处理结果
[Java] 纯文本查看 复制代码
                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)是一种检测装置,能感受到被测量的信息,并能将感受到的信息,按一定规律变换成为电信号或其他所需形式的信息输出

[XML] 纯文本查看 复制代码
        #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只能检测轴向的线性动作。但陀螺仪则可以对转动、偏转的动作做很好的测量,这样就可以精确分析判断出使用者的实际动作。而后根据动作,可以对手机做相应的操作
[Java] 纯文本查看 复制代码
                //1. 获取传感器管理器SensorManager
                sm = (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) {
                                
                        }
                }


20 个回复

倒序浏览

回帖奖励 +1 黑马币

感谢老师分享!
回复 使用道具 举报

回帖奖励 +1 黑马币

6666黑马
回复 使用道具 举报

回帖奖励 +1 黑马币

支持一个
回复 使用道具 举报

回帖奖励 +1 黑马币

谢谢资料 支持
回复 使用道具 举报

回帖奖励 +1 黑马币

谢谢分享  赞赞赞!!!!!
回复 使用道具 举报

回帖奖励 +1 黑马币

好东西!谢谢分享!谢谢!!!
回复 使用道具 举报

回帖奖励 +1 黑马币

谢谢分享!
回复 使用道具 举报
wh121 中级黑马 2017-3-24 15:32:11
9#

回帖奖励 +1 黑马币

进来学习看看
回复 使用道具 举报
wh121 中级黑马 2017-3-31 15:47:25
10#
进来学习一下看看
回复 使用道具 举报

回帖奖励 +1 黑马币

66666666666666
回复 使用道具 举报

回帖奖励 +1 黑马币

进来学习看看
回复 使用道具 举报

回帖奖励 +1 黑马币

谢谢分享!
回复 使用道具 举报

回帖奖励 +1 黑马币

楼主这个厉害了 好牛啊
回复 使用道具 举报
dhj 中级黑马 2017-6-9 11:40:29
15#

回帖奖励 +1 黑马币

快到碗里来,黑马币!!!
回复 使用道具 举报

回帖奖励 +1 黑马币

可以的 很强势
回复 使用道具 举报

回帖奖励 +1 黑马币

支持一个!
回复 使用道具 举报

回帖奖励 +1 黑马币


笔记做的很详细,很认真.,.,,//..
回复 使用道具 举报
cheat 中级黑马 2017-7-10 22:47:07
19#

回帖奖励 +1 黑马币


感谢老师,谢谢,辛苦啦,
回复 使用道具 举报

回帖奖励 +1 黑马币

多谢分享
回复 使用道具 举报
12下一页
您需要登录后才可以回帖 登录 | 加入黑马