小結

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();這樣焦點就不會丟失。。。
嗯。。每日一語錄:
後來,明白。自由不是想做什麼就做什麼,而是, 不想做什麼就不做什麼。。。哈哈可是我們活在這個世界上。如果大家都隨着自己的性子來,這個世界會變成什麼樣??所以,,我們還是需要世俗一點,還是要看下別人的眼光,聽下別人的看法。。願,大家都能好好的過自己的生活。每天開心的睡着,有所期待的醒來。。。加油吧。。
單曲循環:《鍾無豔》

發佈了53 篇原創文章 · 獲贊 61 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章