皮皮网

【直播模块源码】【鸿蒙作业项目源码】【源码时代合作高校】安卓bitmap源码详解_android bitmapfactory

2024-11-15 06:55:05 来源:潮流社区源码

1.android picture.draw占用多大内存
2.BitMap原理与实现
3.android 如何将drawable中的图片保存到系统相册中

安卓bitmap源码详解_android bitmapfactory

android picture.draw占用多大内存

       ã€€ã€€Android的setImageViewBitmap(Bitmap bm)方法的源码中没有建立新的bitmap,而是用引用的方式来使用bm的,这就导致bm被多处引用)。

       ã€€ã€€é‚£ä¸€å¹…图片占用的内存大概多大呢?这篇博文主要是记录了我在测试一副图片占用字节数时查阅的一些资料和测试结果。

       ã€€ã€€1.图片的表示方法

       ã€€ã€€Android的Bitmap.Config给出了bitmap的一个像素所对应的存储方式,有RGB_,ARGB_,ARGB_,ALPHA_8四种。RGB_表示的是红绿蓝三色分别用5,安卓直播模块源码6,5个比特来存储,一个像素占用了5+6+5=个比特。RGB_表示红绿蓝和半透明分别用8,8,8,8个比特来存储,一个像素占用了8+8+8+8=个比特。这样的话如果图片是以RGB_读入的,那么占用内存的大小将是RGB_读入方式的2倍。

       ã€€ã€€é€šå¸¸æˆ‘们给Imagview加载图片是通过setDrawable或者在xml文件中用android:src来设置,从BitmapFactory.Options.inPreferredConfig的说明文档可以看出,默认的加载图片大小的方式是以RGB_读入的。

       ã€€ã€€2.获取bitmap占用的字节数

       ã€€ã€€API 以上可以直接获取,以下则是通过获取高和行所占字节相乘得到的。

       ã€€ã€€protected int sizeOf(Bitmap data) {        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) {            return data.getRowBytes() * data.getHeight();        } else {            return data.getByteCount();        }    }

       ã€€ã€€3.以RGB_方式读入图片

       ã€€ã€€public  Bitmap readBitMap(Context context, int resId){          BitmapFactory.Options opt = new BitmapFactory.Options();          opt.inPreferredConfig = Bitmap.Config.RGB_;          opt.inPurgeable = true;         opt.inInputShareable = true;            //获取资源图片         InputStream is = context.getResources().openRawResource(resId);        return BitmapFactory.decodeStream(is,null,opt);     }

       ã€€ã€€4.获取ImageView和其中drawable的大小

       ã€€ã€€èŽ·å–ImageView和其中drawable大小需要在onWindowFocusChanged获取,在oncreate中返回的结果是0.

       ã€€ã€€public void onWindowFocusChanged(boolean hasFocus){ ImageView imageView=(ImageView)findViewById(R.id.test1); Log.v("Testresult","width= "+imageView.getWidth()+" height= " +imageView.getHeight()); Log.v("Testresult","drawawidth= "+imageView.getDrawable().getBounds().width()+ " drawableheight= " +imageView.getDrawable().getBounds().height()); }

       ã€€ã€€5.Oncreate()中的测试代码

       ã€€ã€€protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                ImageView imageView=(ImageView)findViewById(R.id.test1);        Drawable drawable = imageView.getDrawable();        int bitmapWidth = drawable.getIntrinsicWidth(); //this is the bitmap's width        int bitmapHeight = drawable.getIntrinsicHeight(); //this is the bitmap's height        Log.v("Testresult","bitmapwidth= "                +bitmapWidth+" bitmapHeight= "+bitmapHeight);                Bitmap bitmap=((BitmapDrawable)imageView.getDrawable()).getBitmap();        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) {            Log.v("Testresult","bitmap bytes are"+bitmap.getRowBytes()*bitmap.getHeight());        } else {            Log.v("Testresult", "bitmap bytes are"+bitmap.getByteCount());        }                bitmap=readBitMap(this, R.drawable.pic__);        //api 之上可以直接获取bitmap所占用的字节数        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) {            Log.v("Testresult","bitmap bytes are"+bitmap.getRowBytes()*bitmap.getHeight());        } else {            Log.v("Testresult", "bitmap bytes are"+bitmap.getByteCount());        }            }

       ã€€ã€€6.测试结果

       ã€€ã€€å…¶ä¸­åŽŸå›¾ç‰‡å¤§å°æ˜¯*,手机屏幕的分辨率是*.从图中可以看出,采用android:src的加载方式占用的字节数是采用RGB_加载方式的2倍。且=2**字节。并且虽然在手机中显示的时候bitmap被缩小显示了,但是drawable的长宽所占字节是和图片的尺寸相一致的。

BitMap原理与实现

        比较经典的问题是: 在只能够使用2G的内存中,如何完成以下操作:

        ①:对亿个不重复的整数进行排序。

        ②:找出亿个数字中重复的数字。

        无论是排序还是找重复的数字都需要将这亿个数字加入到内存中在去进行操作,很明显,题目给出的2G内存限制说明了在这样的场景下是不能够将所有数都加入到内存中的

        * 4/(* * ) = 3.G

        那么这时候就需要用到 BitMap结构了

        bitMap使用一个bit为0/1作为map的value来标记一个数字是否存在,而map的key值正是这个数字本身。

        相比于一般的数据结构需要用4个byte去存储数值本身,相当于是节省了 4*8:1 = 倍的内存空间

        bitMap不一定要用bit数组,可以使用 int,long等等的基本数据类型实现,因为其实质都是在bit位上存数据,用哪种类型只是决定了最终实现出来的BitMap的内置数组中单个元素存放数据的多少

            例如:java中的BitSet使用Long数组

        BitMap的实现当然少不了位运算,先来明确几个常见位运算,这是实现BitMap的基础:

        set(bitIndex): 添加操作

            1 .确定该数处于数组中的哪个元素的位上

             int wordIndex = bitIndex >> 5;

        因为我用的是int[]实现,所以这里右移 5 位(2^5 = )

            2 .确定相对于该元素中的位置偏移

             int bitPosition = bitIndex & ((1 << 5) - 1);

        这里相当于是 bitIndex % (1<<5)的取模运算,因为当取模运算的除数是2的次幂,所以可以使用以下的位运算来计算,提升效率(对比HashMap的容量为什么总是2的幂次方的问题,HashMap求下标时也是使用 hash&(n-1))

        tips: 位运算的优先级是低于+,-等等的,所以要加上括号,防止发生不可描述的错误

            3 .将该位置1

             bits[wordIndex] |= 1 << bitPosition;

        相当于是将指定位置处的bit值置1,其他位置保持不变,也就是将以这个bitIndex为key的位置为1

        tips: 这里是参考了网上的各位大佬的文章,取余 + 按位或,又对比了下BitSet的源码:

             words[wordIndex] |= (1L << bitIndex);

        没有取余操作,直接|,这两个一样吗?答案当然是一样的

        举个栗子:

             1 << == 1<<     

             1L << ==1L<<

        即对于int和long型数据,直接左移其位数相当于是附带了对其的取模操作

        总结:使用Bit-map的思想,我们可以将存储空间进行压缩,而且可以对数字进行快速排序、去重和查询的操作。

        Bloom Fliter是Bit-map思想的一种扩展,它可以在允许低错误率的场景下,大大地进行空间压缩,是一种拿错误率换取空间的数据结构

        当一个元素加入布隆过滤器中的时候,会进行哪些操作:

        当我们需要判断一个元素是否存在于布隆过滤器的时候,会进行哪些操作:

        然后,一定会出现这样一种情况:不同的字符串可能哈希出来的位置相同(可以适当增加位数组大小或者调整我们的哈希函数来降低概率),因此:布隆过滤器可能会存在误判的情况

        总结来说就是: 布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在。

        Bloom Filter的应用: 常用于解决缓存穿透等场景。

android 如何将drawable中的图片保存到系统相册中

       android 将drawable中的图片保存到系统相册中的原理比较简单,获取到的bitmap,然后通过的compress方法写到一个fileoutputstream中. 再通知MediaScannerService有图片文件加入就可以了.

       ä¿å­˜å›¾ç‰‡çš„核心代码如下:

       Bitmap bitmap= BitmapFactory.decodeResource(getResources(), R.drawable.icon);

       MediaStore.Images.Media.insertImage(context.getContentResolver(), bitmap, name, "");

       æˆ–者

       FileOutputStream fos = openFileOutput("image", Context.MODE_PRIVATE);

       bitmap.compress(Bitmap.CompressFormat.JPEG, , fos);

       fos.flush();

       fos.close();

       //发送系统通知消息

       context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));

       å¦ä¸€ç§æ–¹æ³•æ˜¯ç›´æŽ¥ä½¿ç”¨æ–‡ä»¶æµè¯»å†™ï¼š

       InputStream is = mContext.getResources().openRawResource(PicID);

       FileOutputStream fos = new FileOutputStream(LogoFilePath);

       byte[] buffer = new byte[];

       int count = 0;

        while((count=is.read(buffer)) > 0)

        {

        fos.write(buffer, 0, count);

        }

       fos.close();

       is.close();

       è¿™é‡Œè¦æ³¨æ„ç›®å½•æƒé™é—®é¢˜ï¼šåœ¨åº”用程序AndroidManifest.xml中的manifest节点中加入android:sharedUerId="android.uid.system"这个属性。然后放在源码环境中编译,并通过adb install 的方式进行安装。mk文件中的属性改为LOCAL_CERTIFICATE :=platform。