簡體   English   中英

Android / Java-Dream Service的內存不足異常

[英]Android/Java - Out of Memory Exception with Dream Service

我開發了一個使用Android的Dream Service作為各種屏幕保護程序的應用程序-它顯示圖像的幻燈片。 這些圖像以二進制格式存儲在數據庫中並進行解碼。 我意識到這不是最好的方法,但是鑒於此應用程序的特定結構和目的,這是最現實的。 此外,該類不會不斷訪問數據庫,也不會連續解碼圖像-它在啟動然后關閉資源時會執行此操作。

話雖如此,在屏幕保護程序運行了一段時間之后,我偶爾會收到“應用程序已停止工作”消息,我認為這與內存不足錯誤有關。 我發現這有點奇怪,因為據我所知,位圖僅在服務附加到窗口時解碼一次。 我看不到為什么唯一的重復操作是將位圖加載到ImageView容器中時內存會出現問題,我當然認為這不需要大量資源。 我查看了我的代碼,無法找到問題。

我究竟做錯了什么; 如何阻止這些錯誤的發生?

public class screenSaver extends DreamService {

    XmlPullParser parser;
    String storeImages = "";

    // creates messages

    public Bitmap drawText(Context c, int resource, String text) {

        Resources resources = c.getResources();
        Bitmap bitmap = BitmapFactory.decodeResource(resources, resource);
        android.graphics.Bitmap.Config config = bitmap.getConfig();
        if (config == null) {
            config = android.graphics.Bitmap.Config.ARGB_8888;

        }
        bitmap = bitmap.copy(config, true);
        Canvas canvas = new Canvas(bitmap);
        TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        float scale = resources.getDisplayMetrics().density;
        paint.setColor(Color.BLACK);
        paint.setTextSize(48 * scale);

        int textWidth = canvas.getWidth() - (int) (16 * scale);
        StaticLayout textLayout = new StaticLayout(text, paint, textWidth, Layout.Alignment.ALIGN_CENTER, 1f, 0f, false);

        int textHeight = textLayout.getHeight();
        float x = (bitmap.getWidth() - textWidth) / 2;
        float y = (bitmap.getHeight() - textHeight) / 2;

        canvas.save();
        canvas.translate(x, y);

        textLayout.draw(canvas);
        canvas.restore();

        return bitmap;
    }

    ArrayList<Bitmap> imageList = new ArrayList<Bitmap>();
    int slideCounter = 0;
    ImageView slide;
    Cursor images;
    Cursor corpImages;
    final Handler handler = new Handler(Looper.getMainLooper());

    private int counter = 0;

    private Runnable runnable = new Runnable() {
        @Override
        public void run() {

            slide.setImageBitmap(imageList.get(counter));
            if (counter == (imageList.size() - 1)) {
                counter = 0;

            } else {
                counter++;

            }

        }
    };

    public screenSaver() {

    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        setInteractive(false);
        setFullscreen(true);
        setContentView(R.layout.screen_saver);

        databaseHelper dbHelper = new databaseHelper(this);
        Intent testIntent = new Intent(this, lockActivity.class);
        testIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        this.startActivity(testIntent); // unpin screen so screen saver can load
        SQLiteDatabase db = dbHelper.getReadableDatabase();

        SharedPreferences preferences = getSharedPreferences("config", MODE_PRIVATE);
        final String store = preferences.getString("store", "");

        String managerMessageText = "";
        String mainMessageText = "";
        String districtMessageText = "";
        try {


            FileInputStream input = new FileInputStream(new File(this.getFilesDir(), "stores.xml"));
            parser = Xml.newPullParser();

            parser.setInput(input, null);

            // begin search for correct 'store' tag
            boolean elementsRemain = true;
            while (elementsRemain) {
                parser.next();
                int event = parser.getEventType();
                switch (event) {
                    case XmlPullParser.START_TAG:
                        String name = parser.getName();

                        if (name.equals("store")) {
                            Log.i("Screen Saver", "entering if store");
                            String number = parser.getAttributeValue(null, "number");
                            if (number.equals(store)) {

                                // located corresponding store, beginning parsing to find associate images and messages

                                boolean withinStore = true;
                                while (withinStore) {
                                    parser.next();

                                    if (parser.getEventType() == XmlPullParser.START_TAG) {

                                        String tag = parser.getName();
                                        if (tag.equals("images")) {
                                            parser.nextTag();

                                            while (parser.getEventType() == XmlPullParser.START_TAG && parser.getName().equals("image")) {
                                                if (parser.getAttributeValue(null, "id") != null && (!parser.getAttributeValue(null, "id").equals(""))) {
                                                    storeImages += parser.getAttributeValue(null, "id") + ",";
                                                }


                                                parser.nextTag();
                                                if (parser.getEventType() == XmlPullParser.END_TAG) {
                                                    parser.nextTag();
                                                }
                                            }
                                        }
                                        parser.next();

                                        if (parser.getEventType() == XmlPullParser.TEXT) {
                                            switch (tag) {

                                                case "message":
                                                    managerMessageText += parser.getText();
                                                    break;
                                                case "district":
                                                    districtMessageText += parser.getText();
                                                    break;
                                                case "corporate":
                                                    mainMessageText += parser.getText();
                                                    break;
                                                default:
                                                    break;
                                            }
                                        }
                                    } else if (parser.getEventType() == XmlPullParser.END_TAG && parser.getName().equals("store")) {
                                        withinStore = false;
                                    }
                                }
                                parser.next();
                            }
                        } else {

                        }
                        break;
                    case XmlPullParser.END_DOCUMENT:
                        elementsRemain = false;
                        break;


                }


            }

        } catch (Exception e) {
            Log.e("Error reading XML ", " " + e.getMessage());
        }

/*     LTO images
   try {
            File managerFile = new File(this.getFilesDir(), store + ".txt");
            File universalFile = new File(this.getFilesDir(), "universal.txt");
            File districtFile = new File(this.getFilesDir(), "district.txt");

            BufferedReader reader = new BufferedReader(new FileReader(managerFile));
            managerMessageText = reader.readLine();

            reader = new BufferedReader(new FileReader(universalFile));
            mainMessageText = reader.readLine();

            reader = new BufferedReader(new FileReader(districtFile));
            districtMessageText = reader.readLine();

        } catch (Exception e) {
            Log.e("Error opening file: ", e.getMessage());
        }*/


       /*  images = db.rawQuery("SELECT " + databaseHelper.IMAGE + " FROM " + databaseHelper.TABLE_NAME + " where " + databaseHelper.LTO + " = 1", null);
        images.moveToFirst();

        while(!images.isAfterLast()) {
            imageList.add(BitmapFactory.decodeByteArray(images.getBlob(images.getColumnIndex(databaseHelper.IMAGE)), 0, images.getBlob(images.getColumnIndex(databaseHelper.IMAGE)).length ));
            images.moveToNext();
        }
        images.close(); */


        if (storeImages.length() > 1) {
            storeImages = storeImages.substring(0, storeImages.length() - 1); // remove trailing comma
        }


        // get all images that are associated with store

        corpImages = db.rawQuery("SELECT  " + databaseHelper.SLIDE_IMAGE + " FROM " + databaseHelper.SLIDE_TABLE + " WHERE " + databaseHelper.SLIDE_ID + " IN (" + storeImages + ")", null);
        corpImages.moveToFirst();
        while (!corpImages.isAfterLast()) {
            imageList.add(BitmapFactory.decodeByteArray(corpImages.getBlob(corpImages.getColumnIndex(databaseHelper.SLIDE_IMAGE)), 0, corpImages.getBlob(corpImages.getColumnIndex(databaseHelper.SLIDE_IMAGE)).length));
            corpImages.moveToNext();
        }
        corpImages.close();
        db.close();

        // begin drawing message bitmaps

        if (managerMessageText != "") {
            imageList.add(drawText(this, R.drawable.message_background, "Manager Message: \n" + managerMessageText));
        }
        if (mainMessageText != "") {
            imageList.add(drawText(this, R.drawable.message_background, "Corporate Message: \n" + mainMessageText));
        }
        if (districtMessageText != "") {
            imageList.add(drawText(this, R.drawable.message_background, "District Manager Message: \n" + districtMessageText));
        }


        slide = (ImageView) findViewById(R.id.slider);
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {

                updateGUI();

            }
        }, 0, 8000);

    }

    ;

    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        // unpin screen so it can update
        Intent testIntent = new Intent(this, lockActivity.class);
        testIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        this.startActivity(testIntent); // unpin screen so it can update
    }


    private void updateGUI() {
        if (reminder.running || hourlyReminder.running) {

            this.finish();
        } else {
            handler.post(runnable);

        }
    }


}

非常感謝您的指導。

直接使用encodeResource()方法嘗試為構造的位圖分配內存,並可能導致OutOfMemory。 有幾種選項可以有效地解碼位圖。

將BitmapFactory.Options的inJustDecodeBounds設置為true可以避免在解碼步驟中分配內存。 看來您沒有使用此選項。

當您只需要顯示縮小/較小版本的圖像/位圖時,無需將其加載到內存中。 您可以通過設置BitmapFactory.Options的inSampleSize來控制它。 看來您也沒有使用此選項。

嘗試使用:

options.inJustDecodeBounds = true;
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

等選項,同時解碼位圖以有效處理內存。

您可以在這里找到完整的教程: https : //developer.android.com/training/displaying-bitmaps/load-bitmap.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM