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

小结

程序员文章站 2022-07-14 18:34:55
...

1:关于内存泄漏的一点点总结。
以前写项目,对于内存的泄漏不太注重,直到有一天。有个朋友写得一个拍照然后裁剪的小demo。为了保证演示的时候,没有问题,他就测试了上百次。就是拍照。然后去裁剪。裁剪完成写个自定义的view把bitmap显示出来。测试了几十次的时候。。崩溃了。。。一看日志,oom..呀。。这个问题有点棘手啊。。于是我们开始了找bug之旅。
拍照的代码:

  private void takePhoto() {

        File dir=new File(Environment.getExternalStorageDirectory() + "/"+"test");
        if(!dir.exists())dir.mkdirs();
        Intent intent=new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        localTempImgFileName="test.jpg";
        File f=new File(dir, localTempImgFileName);//localTempImgDir和localTempImageFileName是自己定义的名字
        Uri u=Uri.fromFile(f);
        intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, u);
        startActivityForResult(intent, CODE_TAKE_PICTUE);
    }

a;因为裁剪用的是ucrop这个三方的裁剪库。这个库支持传个uri进去,我们在一开始是直接用拍照时候传进去的u,但是经过测试,在6.0的系统上这个u有时候会为null,于是我们是在onActivityResult里面直接用之前传进的路劲,然后拿到的uri.传进ucrop里面。
代码:

 if (requestCode == CODE_TAKE_PICTUE) {
            File f = new File(Environment.getExternalStorageDirectory()
                    + "/" + "test" + "/" + localTempImgFileName);
            Log.e("zmm", "path-->" + f.getAbsolutePath());

            Uri u =
                    Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(),
                            f.getAbsolutePath(), null, null));
            Log.e("zmm", "uri-->" + u.toString())

        }

但是我们拍照拿到的uri是原始的图片的uri,所以,我们想要不。我们拿到uri以后先稍微压缩下。然后再传给ucrop。代码:

//压缩
                        photoBmp = UriUtils.getBitmapFormUri(MainActivity.this, Uri.fromFile(f));
                        int degree = UriUtils.getBitmapDegree(f.getAbsolutePath());
                        /**
                         * 把图片旋转为正的方向
                         */
                        Bitmap newbitmap = UriUtils.rotateBitmapByDegree(photoBmp, degree);

                        String comPath = Environment.getExternalStorageDirectory()
                                + "/" + "test";
                        String path = UriUtils.saveBitmap(newbitmap, comPath);
                        Log.e("zmm", "path--->" + path);
//                    File comfile=new File(path);
                        Uri comu =
                                Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(),
                                        path, null, null));
                        //去裁剪
                        UCropUtils.startCropActivity(this, comu);

结果很失望。。并不是这个原因。
b:我们又想到有没有可能使我们的bitmap用的太多,而且没有recycle.
于是我们在bitmap用完以后把bitmap都回收了;
回收代码:

  if (mBitmap != null && !mBitmap.isRecycled()) {
            mBitmap.recycle();
        }

这样做了以后,,稳定了一点,跑到了100多次才崩溃。所以,bitmap用完以后一定要回收。不要觉得一次两次没关系。我们要养成这个思想,因为如果你的app是一天24小时运行着的话。资源的不回收。肯定会oom的。
c:但是我们的问题并没有解决。因为还是崩溃了。这个时候,我们学着去看运行时的memory,以前都没看过,不看不要紧。。一看吓半死。。以为。我们可以清楚的看到,每次拍完照,裁剪完成以后返回我们的主界面把该图片显示出来。这个内存都会升高一点。。而且不会下来,,一直升高。。直到oom…所以,,这个问题就很扎心了。。是我们资源没有回收,且一直创建新的对象。。大概知道问题,我们开始找代码里面的致命的错误。终于,我们找到了。。,,我之前说过,我们主界面是一个自定义的view,然后把裁剪完成的图片用canvas画上去的。。我们在代码里面是

MyView myview=new  MyView(context);
mylayout.addview(myview)

mylayout是个framLayout,问题就出现在myview。。我们把myview=null。以为就是资源回收了。。每次裁剪完成以后,我们都是

myview=null;
MyView myview=new MyView(context);mylayout.addview(myview);

你讲气不气。。。我们竟然没有把子view从viewgroup里面移除。。。而是直接myview=null。。。。后来我们进到viewgroup.addview方法里面就可以看到,其实viewgroup里面是用的数组来保存所有的子view,我们在addview的时候。viewgroup已经把该view加到数组里面了。所以,我们把view=null.没有任何作用,找到问题以后,我们就好解决了。。我们用viewgroup.removeView这个方法就可以了。这样修改了以后,内存果然下来了。。不过还是会增长一点。这是因为,我们自定义view里面的canvas和画笔什么的都没有回收。这都是优化的问题了。。
至此问题就解决了。。所以,以后我们还是得注意回收资源。。。
2:我们如果遇到负责界面类似电商的很复杂的界面。。那我们应该怎么处理。肯定不能嵌套。。那样会卡顿。阿里有个开源的控件:vlayout.具体的用法请自行搜索。。
3:进行机顶盒开发的时候。用recycleView的时候。请注意,当更新数据的时候。,我们可能会调用adapter.notifydatasetchanged();这个方法,你会发现这样的话。焦点就丢失了。。所以,如果我们是对部分数据进行更新。我们可以调用。adapter.notifyItemChanged();这样焦点就不会丢失。。。
嗯。。每日一语录:
后来,明白。*不是想做什么就做什么,而是, 不想做什么就不做什么。。。哈哈可是我们活在这个世界上。如果大家都随着自己的性子来,这个世界会变成什么样??所以,,我们还是需要世俗一点,还是要看下别人的眼光,听下别人的看法。。愿,大家都能好好的过自己的生活。每天开心的睡着,有所期待的醒来。。。加油吧。。
单曲循环:《钟无艳》

相关标签: 内存泄露