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

时间:2016-07-01 13:30:28

标签: java android bitmap out-of-memory

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

        }
    }


}

非常感谢任何指导。

1 个答案:

答案 0 :(得分:0)

使用decodeResource()方法直接尝试为构造的位图&amp;分配内存。可以导致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