RemoteViews for widget update exceeds max bitmap memory usage error
Asked Answered
B

3

12

I have a widget that parses xml feed and display its title and image.In this widget I am using a service that periodically changes the contents(ie, title and image).For this I am using timer class.When we run this widget, some contents are displayed without any problem but after sometime it force closes and shows an error like "RemoteViews for widget update exceeds maximum bitmap memory usage(used:2465280 max:2304000) The total memory can't exceed that required to fill the device's screen once". Please some one help me to solve this issue...Thanks in advance

Here is my AppwidgetProvider=>

 public class myappwidgetprovider extends AppWidgetProvider {
    public static String urls="http://www.abc.com/en/rssfeeds/9/latest/rss.xml";
    // XML node keys
    static final String KEY_HEAD = "item"; // parent node
    //static final String KEY_TITLE = "title";
    static final String KEY_DATE = "pubDate";
    public static String headflag="english";
    public static String[] Title;
        public static String[] Description;
        public static String[] Tit;
        public static String[] Tit2;
        public static String[] Desc;
        public static String[] Desc2;
        public static String[] image;
    public static TextView flashnews;

    public static int i=0;

     public void onUpdate( Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds )
        {

         Log.i("Tag", "onCreateView");
         parse();


           RemoteViews remoteViews;
                        ComponentName thisWidget = new ComponentName(context,myappwidgetprovider .class);

                int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);

                Intent intent = new Intent(context.getApplicationContext(),
                        Updatewidget.class);
                    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
                            context.startService(intent);

               }





     public static void parse()
     {

            URL url;

            try {

                url = new URL(urls);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                if((conn.getResponseCode() == HttpURLConnection.HTTP_OK)){
                      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                      DocumentBuilder db = dbf.newDocumentBuilder();
                      Document doc;
                      doc = db.parse(url.openStream());
                      doc.getDocumentElement().normalize();

                      NodeList itemLst = doc.getElementsByTagName("item");
                      Description = new String[itemLst.getLength()];//........
                      Title = new String[itemLst.getLength()];
                      Tit=new String[itemLst.getLength()];
                      Tit2=new String[itemLst.getLength()];
                      Desc=new String[itemLst.getLength()];
                      Desc2=new String[itemLst.getLength()];
                      image= new String[itemLst.getLength()];

                      for(int i=0; i < itemLst.getLength(); i++){

                            Node item = itemLst.item(i);
                            if(item.getNodeType() == Node.ELEMENT_NODE){
                                  Element ielem = (Element)item;
                                  NodeList title = ielem.getElementsByTagName("title");
                                  NodeList date = ielem.getElementsByTagName("pubDate");
                                  NodeList description = ielem.getElementsByTagName("description");
                                  Tit[i]= title.item(0).getChildNodes().item(0).getNodeValue();
                                  Desc[i]= description.item(0).getChildNodes().item(0).getNodeValue();
                                  Tit2[i]=Translate.title(Tit[i]);
                                  Desc2[i]=Translate.description(Desc[i]);
                                  if(headflag=="malayalam")
                                    {
                                      Desc2[i]=Desc2[i].replace("read more","IqSpXÂ");
                                    }
                                  Title[i] =Tit2[i];
                                  if (Desc2[i].contains("<img ")){
                                      String img  = Desc2[i].substring(Desc2[i].indexOf("<img "));
                                      String cleanUp = img.substring(0, img.indexOf(">")+1);
                                      img = img.substring(img.indexOf("src=") + 5);
                                      int indexOf = img.indexOf("'");
                                      if (indexOf==-1){
                                          indexOf = img.indexOf("\"");
                                        }
                                      img = img.substring(0, indexOf);

                                //setImgLink(img);
                                    if(headflag=="malayalam")
                                    {
                                        String img2=img.replace("files","files/imagecache/android_320");
                                        Description[i]=Desc2[i].replace(img,img2);
                                        image[i]=img2;
                                    }

                                else
                                {
                                    String img2=img.replace("files","files/imagecache/android_1_img");
                                    Description[i]=Desc2[i].replace(img,img2);
                                    image[i]=img2;
                                }
                                  }
                                else
                                {
                                    Description[i] =Desc2[i];
                                }



                            }

                          }

                        }
            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (DOMException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ParserConfigurationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SAXException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
     }

}

And Here is my service=>

public class Updatewidget extends Service {
    static String UPDATEMOOD ="UPDATEMOOD";
    public Intent newintent;
    public AppWidgetManager app;
    public RemoteViews newviews;
    public int[] newappid;
    int i=0;
    @Override
    public void onStart(final Intent intent, int startId) {

         Log.i("Tag", "Service Called!!!!!!!!!!!!!");

         newintent=intent;
                 int[] allWidgetIds = intent
                    .getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
         newappid=allWidgetIds;

         final AppWidgetManager appWidgetMan = AppWidgetManager.getInstance(this);
         app=appWidgetMan;
         final RemoteViews views = new RemoteViews(this.getPackageName(),R.layout.widget_main);
         newviews=views;
         views.setTextViewText(R.id.title, myappwidgetprovider.Title[0]);
         Bitmap bitmap;
            try {
                bitmap = BitmapFactory.decodeStream((InputStream)new URL(myappwidgetprovider.image[0]).getContent());


                views.setImageViewBitmap(R.id.imageView4, bitmap);
            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
         appWidgetMan.updateAppWidget(allWidgetIds, views); 

         new ProgressAsyncTask().execute();








    }



     public class ProgressAsyncTask extends 
        AsyncTask<Void, Integer, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            // TODO Auto-generated method stub
             int delay = 5000; // delay for 5 sec.

             int period = 5000; // repeat every sec.

             Timer timer = new Timer();
              timer.scheduleAtFixedRate(new TimerTask() {

                     public void run() {
                         i++;
                         if(i==5)
                         {
                             i=0;
                         }

                         int[] allWidgetIds = newintent
                                    .getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
                                 newviews.setTextViewText(R.id.title, myappwidgetprovider .Title[i]);
                         Bitmap bitmap;
                            try {
                                bitmap = BitmapFactory.decodeStream((InputStream)new URL(myappwidgetprovider .image[i]).getContent());


                                newviews.setImageViewBitmap(R.id.imageView4, bitmap);
                            } catch (MalformedURLException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                         app.updateAppWidget(allWidgetIds, newviews); 
                                 }


                     }, delay, period);
            return null;
        }
     }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }





}
Bearer answered 21/11, 2012 at 13:58 Comment(0)
S
10

I just solved a similar problem. But I wasn't loading any content from web. My widget was displaying different images for different widget sizes. And for some screens there was the same error as yours displaying widget 4x4.

That what I've found at developer.google.com:

The total Bitmap memory used by the RemoteViews object cannot exceed that required to fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.

So I was able just to put a restriction on my bitmap size in widget to fit this requirement.

In your particular case the error occures when a bitmap loading from stream is larger than possible.

I think the ussage of

public static Bitmap decodeStream (InputStream is, Rect outPadding, BitmapFactory.Options opts)

with proper options should help. (possible you need to use inSampleSize option).

Hope my post was helpful.

Sophy answered 6/3, 2013 at 3:21 Comment(4)
I think I have solved that issue. Anyway, Thanks for this :)Bearer
@Rusanovskiy Artem: How do you know exactly which options to pass to decodeStream()? If you have, say, four bitmaps in the widget, and you don't know which size the source images have, how do you know which sampleSize you have to use to prevent that Exception?Potman
@BasimSherif Could you explain how you solved this problem?Thank you!Erikaerikson
My screen is 3088 x 1440: 3088 x 1440 * 4 * 1.5 = 27 Megabytes will be taken up in RAM. Instead of 1 picture and up to 1 Megabyte of RAM. + CPU time to compress pictures and change data in memory. If we throw resources around like that, there won't be enough for anything. This is not professional.Subulate
S
3

To demonstrate the second part of RusArtM response

val bitmapOptions = BitmapFactory.Options()
bitmapOptions.inSampleSize = 4
val bitmap = BitmapFactory.decodeFile(codeData.imagePath, bitmapOptions)

Should probably solve the issue. inSampleSize with a value superior to one, shrink the image. With an inSampleSize = 4, we get an image that is 1/4 of the width/height of the image

Here is the documentation

Schertz answered 19/3, 2022 at 13:20 Comment(6)
Of course, it reduces quality, the issue is that the image is too big, so the easiest way of solving that is to reduce the size. I'm just giving an example of the accepted answer.Schertz
I'm just showing a way of reducing an image size. I don't think this is harmful. If you can show me why it's harmful, I will be very grateful. And in that case, you might want to comment the accepted answerSchertz
The processor will be busy compressing images, which takes resources. Other programmers will go the same way and do it the easy way, not the right way. Their applications will consume more RAM and CPU time because of this. This is all very harmful. I recommend that you delete your reply. Other than that, your answer does not answer the question. Why did the memory overflow happen? The correct answer is a memory leak. How to fix it, I wrote below.Subulate
I get your point, I think you're a bit extreme, but that's an interesting point of view. Yes, my answer is just a demonstration of what the accepted answer recommend, I should have comment this answer instead of creating my own. I'm not going to delete it. I think it's still valuable, and our tiny debate in the comment section can make people think, so I think it's great. And I don't think people are going to blindly copy/paste and answer with a downvote.Schertz
If you fetch images from a server and those images are big enough, you'll end up with the same problem even with a clean cache. So in that case you do need to scale the images down. I suggest next time you try to be a bit more polite and less fixated on your own opinion, @Master.Holocene
These are local pictures that are stored in their original quality. And it is only one picture. What are you talking about?Subulate
S
0

Google invented a funny picture cache. I do not know why, but it greatly increases the load on the system. That's why I do it every time and don't store the picture history:

        contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.notification_media);
        Intent notify = new Intent(getApplicationContext(), MainActivity.class);
        PendingIntent butt = PendingIntent.getActivity(getApplicationContext(), 0, notify, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
        contentView.setOnClickPendingIntent(R.id.ibShowApp, butt);
        contentView.setTextViewText(R.id.tvTitle, title);
        if (coverArt != null) {
            if (coverCache != null) coverCache.recycle();
            try {
                coverCache = BitmapFactory.decodeFile(coverArt);
            } catch (Throwable throwable) {
                coverCache = null;
            }
            contentView.setImageViewBitmap(R.id.ivCover, coverCache);
        } else if (coverCache != null) {
            contentView.setImageViewBitmap(R.id.ivCover, null);
            coverCache.recycle();
            coverCache = null;
        }
        mBuilder.setContentTitle(title)
                .setCustomBigContentView(contentView)
                .setContent(contentView);
        Notification not = mBuilder.build();
        not.flags |= Notification.FLAG_NO_CLEAR;
        startForeground(Constants.NOTIFICATION_ID, not);
Subulate answered 31/10, 2022 at 23:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.