Android/Java -内存不足的梦服务异常



我开发了一个应用程序,它使用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);
        }
    }

}

非常感谢您的指导

使用decoderresource()方法直接尝试为构造的位图分配内存&会导致OutOfMemory。有几个选项可以有效地解码位图。

设置BitmapFactory的inJustDecodeBounds。选项true避免在解码步骤中分配内存。你似乎没有使用这个选项。

你不需要加载一个完整的图像/位图到内存中,当你只需要显示它的缩小/缩小版本。你可以通过设置BitmapFactory.Options的inSampleSize来控制它。你似乎也没有使用这个选项。

尝试使用:

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

等。选项,在解码位图时有效地处理内存。

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

最新更新