2016-07-01 5 views
0

Ich habe eine Anwendung entwickelt, die den Dream Service von Android als Bildschirmschoner verwendet - er zeigt eine Diashow mit Bildern an. Diese Bilder sind im Binärformat in einer Datenbank untergebracht und dekodiert. Ich weiß, dass dies nicht der beste Weg ist, aber angesichts der besonderen Struktur und des Zwecks dieser Anwendung ist es am realistischsten. Außerdem macht die Klasse keine ständigen Fahrten zur Datenbank oder dekodiert kontinuierlich das Bild - dies geschieht beim Start und schließt dann die Ressourcen.Android/Java - Nicht genügend Arbeitsspeicher Ausnahme mit Dream Service

Mit dem gesagt, nachdem der Bildschirmschoner für eine Weile ausgeführt wurde, erhalte ich gelegentlich eine "Anwendung hat nicht mehr funktioniert" Nachricht, die ich glaube, ist mit einem Speicherfehler verbunden. Ich finde das ein wenig merkwürdig, weil, soweit mir bekannt ist, die Bitmaps nur einmal decodiert werden - wenn der Dienst an Fenster angeschlossen ist. Ich sehe nicht, warum es Probleme mit dem Speicher geben würde, wenn die einzige sich wiederholende Aktion das Laden einer Bitmap in einen ImageView-Container ist, sicherlich nicht etwas, von dem ich glaube, dass es eine große Menge an Ressourcen erfordert. Ich habe meinen Code überprüft und konnte das Problem nicht finden.

Was mache ich falsch? Wie kann ich verhindern, dass diese Fehler auftreten?

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); 

     } 
    } 


} 

Vielen Dank für jede Anleitung.

+1

ich ziemlich sicher bin, das ein Problem mit Bitmap-Laden ist. Lesen Sie [diese] (https://developer.android.com/training/displaying-bitmaps/load-bitmap.html) –

Antwort

0

Mit der Methode decodeResource() wird direkt versucht, Speicher für die erstellte Bitmap zuzuweisen & kann OutOfMemory führen. Es gibt mehrere Möglichkeiten, Bitmaps effizient zu decodieren.

Die Einstellung von inJustDecodeBounds von BitmapFactory.Options auf true vermeidet die Speicherzuweisung im Dekodierschritt. Es scheint, dass Sie diese Option nicht verwenden.

Sie müssen kein vollständiges Bild/Bitmap in den Speicher laden, wenn Sie nur eine verkleinerte/kleinere Version davon anzeigen müssen. Sie können dies steuern, indem Sie inSampleSize von BitmapFactory.Options setzen. Es scheint, dass Sie diese Option auch nicht verwenden.

Versuchen Sie es mit:

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

usw. Optionen während Bitmaps Decodierung effizient den Speicher zu handhaben.

Sie können ein ganz Tutorial finden Sie hier: https://developer.android.com/training/displaying-bitmaps/load-bitmap.html

Verwandte Themen