Failed to allocate timer 0: no slots left and unable to set dynamic row height

风流意气都作罢 提交于 2020-01-06 19:59:39

问题


I have a screen which call a listfield.

public class Main_AllLatestNews extends MainScreen {
private Database_Webservice webservice;
private String[] title, category, date, imagepath = {"no picture", "no picture", "no picture", "no picture","no picture","no picture","no picture","no picture","no picture", "no picture"};
private int[] newsid;
private List_News newslist;

public Main_AllLatestNews(final boolean needdownload) {
    super(USE_ALL_WIDTH);
    webservice = new Database_Webservice();
    add(new Custom_TopField(this, 0, -1, "", 1, 1));
    add(new Custom_BottomField(this, 0));
    add(new Custom_HeaderField(Config_GlobalFunction.latest));
    if (needdownload){
        Main.getUiApplication().pushScreen(
                new Custom_LoadingScreen(30));
        webservice.UpdateAllCatNews();          
    }else {
        webservice.LoadtodayNews(); 
        newsid = new int[webservice.news.size()];
        title = new String[webservice.news.size()];
        category = new String[webservice.news.size()];
        date = new String[webservice.news.size()];
        //imagepath = new String[webservice.news.size()];

        for (int i = 0; i < webservice.news.size(); i++) {
            newslist = (List_News) webservice.news.elementAt(i);
            newsid[i] = newslist.getID();
            title[i] = newslist.getNtitle();
            category[i] = newslist.getNewCatName();
            date[i] = newslist.getNArticalD();
            //imagepath[i] = newslist.getImagePath();
        }
        add(new Custom_ListField(newsid, title, date, category, imagepath, true));
    }
}
}

When I add custom_listfield then I get:

Failed to allocate timer 0: no slots left

Here is my listfield

public Custom_ListField(int newsid[], String title[], String date[],
        String category[], String imagepath[], boolean islatest) {
    super(0, ListField.MULTI_SELECT);
    this.newsid = newsid;
    setCallback(this);
    setBackground(Config_GlobalFunction.loadbackground("background.png"));
    this.islatest = islatest;
    rows = new Vector();

    for (int x = 0; x < title.length; x++) {
        TableRowManager row = new TableRowManager();

        titlelabel = new Custom_LabelField(title[x],
                LabelField.USE_ALL_WIDTH | DrawStyle.LEFT);
        titlelabel.setFont(Font.getDefault().derive(Font.BOLD, 23));
        row.add(titlelabel);

        datelabel = new Custom_LabelField(date[x], DrawStyle.ELLIPSIS
                | LabelField.USE_ALL_WIDTH | DrawStyle.LEFT);
        datelabel.setFont(Font.getDefault().derive(Font.BOLD, 18));
        datelabel.setFontColor(Color.GRAY);
        row.add(datelabel);

        categorylabel = new Custom_LabelField(category[x],
                DrawStyle.ELLIPSIS | LabelField.USE_ALL_WIDTH
                        | DrawStyle.LEFT);
        categorylabel.setFont(Font.getDefault().derive(Font.BOLD, 18));
        categorylabel.setFontColor(Color.RED);
        row.add(categorylabel);

        /*Bitmap imagebitmap = null;
        if (!imagepath[x].toString().equals("no picture")) {
            imagebitmap = Util_ImageLoader.loadImage(imagepath[x]);
        } else {
            imagepath[x] = "image_base.png";
            imagebitmap = Bitmap.getBitmapResource(imagepath[x]);
        }
        image = new BitmapField(imagebitmap, Field.FIELD_HCENTER
                | Field.FIELD_VCENTER);
        row.add(image);*/

        //setRowHeight(image.getBitmapHeight() + 10);
        setRowHeight(70);
        rows.addElement(row);
    }
    setSize(rows.size());
}

In this list, it will call 10 images or more. First I will check got link send to it else load local images. So the row height must be not same, however, it does not auto set row height for each row but set a same height to all row. I think out of memory because i call too many images? but I call in android also no problem.

This is my imageloader.

public class Util_ImageLoader {

public static Bitmap loadImage(String url) {
    HttpConnection connection = null;
    InputStream inputStream = null;
    EncodedImage bitmap;
    byte[] dataArray = null;

    try {
        // can use this for BlackBerry 5.0+ :
        // connection = (HttpConnection) (new
        // ConnectionFactory()).getConnection(url).getConnection();
        connection = (HttpConnection) Connector
                .open(url + Util_GetInternet.getConnParam(),
                        Connector.READ, true);
        int responseCode = connection.getResponseCode();
        if (responseCode == HttpConnection.HTTP_OK) {
            inputStream = connection.openDataInputStream();
            dataArray = IOUtilities.streamToBytes(inputStream);
        }
    } catch (Exception ex) {
    } finally {
        try {
            inputStream.close();
            connection.close();
        } catch (Exception e) {
        }
    }

    if (dataArray != null) {
        bitmap = EncodedImage.createEncodedImage(dataArray, 0,
                dataArray.length);
        return bitmap.getBitmap();
    } else {
        return null;
    }
}
}

1) What can I do to reduce the use of memory?

2) How to set different row height? I am set bitmap.getbitmapheight() but different bitmap will have different height.

//Updated//

I am running on simulator 9930 OS 7.0 and 8520 OS 5.0. Both also same result. Real Device cannot run because after signing the key also prompt the warning message try to Secure APi. I am completely commented all the images also same. I did not call neither online nor local image. I think is the data problem?

@AlanLai, can you tell us which device this is being run on, and which OS? Is it a simulator, or real hardware? Why don't you try commenting out the image completely. Don't show any images (network images, or local images). See if you still get the problem. Let's try to narrow down where exactly the code is that's causing your problem. Note: please post the information about which device you're testing on above, in the question, not as a comment response here. Thanks


回答1:


How about to have only one TableRowManager and every drawRow set values with layout with specific values?




回答2:


There's a lot of things you can do to reduce memory usage. For one, try to avoid keeping objects in memory longer than you really need them. One way this happens is if you keep member variables in your class, that could really be local variables in a method. Keeping member variables may lead to objects living longer than they need to, preventing the release of the memory they occupy.

Util_ImageLoader

For example, in Util_ImageLoader, you do almost all the work in the constructor. But then, you keep the result around (the Bitmap) in a static member variable (_bmap), which keeps it in memory. I know you do this so that you can call getBitmap(). But, you could change the class to be like this:

public class Util_ImageLoader { 

   public static Bitmap loadImage(String url) {       
      HttpConnection connection = null; 
      InputStream inputStream = null; 
      EncodedImage bitmap; 
      byte[] dataArray = null; 

      try { 
         // can use this for BlackBerry 5.0+ :
         // connection = (HttpConnection) (new ConnectionFactory()).getConnection(url).getConnection();
         connection = (HttpConnection) Connector.open(url + Util_GetInternet.getConnParam(),  Connector.READ, 
               true); 
         int responseCode = connection.getResponseCode(); 
         if (responseCode == HttpConnection.HTTP_OK) { 
            inputStream = connection.openDataInputStream();
            dataArray = IOUtilities.streamToBytes(inputStream);            
         } 
      } catch (Exception ex) { 
      } 
      finally { 
         try { 
            inputStream.close(); 
            connection.close(); 
         } catch (Exception e) { 
         } 
      } 

      if (dataArray != null) {
         bitmap = EncodedImage.createEncodedImage(dataArray, 0, dataArray.length);        
         return bitmap.getBitmap(); 
      } else {
         return null;
      }
   } 
} 

Because your Util_ImageLoader class doesn't really have any state associated with it, you can probably make it a class with just one static method. The static method does not require you to create an instance of Util_ImageLoader to use it. Just do this:

Bitmap img = Util_ImageLoader.loadImage("http://domain.com/path/image.png");

This allows the image that's loaded to be released as soon as the UI is done with it. The existing code keeps that image in memory for the life of the program.

Also, I replaced your custom code that uses a byte[] buffer, with the useful IOUtilities.streamtoBytes() method. Let the built-in libraries do the work of optimizing for you. Most of the time, they will do a pretty good job of that.

You also had some fixed point scaling code in your Util_ImageLoader class that wasn't doing anything. It was creating a scaled image of the same size as the original. So, I just removed that code. That can only help your memory usage. Image manipulation can be expensive.

Finally, I checked the web server return code (HTTP_OK) before I created any of the large objects needed for this method. If the network request fails, you certainly don't want to waste memory for no reason.

Custom_ListField

Again, you are keeping some objects around, possibly longer than needed. Let's go through your member variables:

private Bitmap bg = Bitmap.getBitmapResource("background.png"),          
    imagebitmap; 

I don't know how many instances of Custom_ListField you will have in your app, but if you are going to assign bg to a constant app resource image, you should at least make it a static member variable, so that if there are 10 instances of Custom_ListField, you will only be keeping one bg variable in memory:

private static Bitmap bg = Bitmap.getBitmapResource("background.png"),          
    imagebitmap;

But, in your case, I don't think you need to keep that member variable at all. You can simply replace it where it's used, like this:

Background background = BackgroundFactory.createBitmapBackground(Bitmap.getBitmapResource("background.png")); 

Then, the imagebitmap member can also be replaced with a local variable:

 Bitmap imageBitmap = null;
 if (!imagepath[x].toString().equals("no picture")) {            
        imageBitmap = Util_ImageLoader.loadImage(imagepath[x]);            
        imageBitmap = loader.getbitmap();            
 } else {            
        imagepath[x] = "image_base.png";            
        imageBitmap = Bitmap.getBitmapResource(imagepath[x]);            
 }            
 image = new BitmapField(imageBitmap, Field.FIELD_HCENTER | Field.FIELD_VCENTER);        

imageBitmap only needs to be a local variable, not a member variable.

Debugging memory usage usually requires having the whole program, running, and profiling it. With only some of your code, I can't see all the other code that uses it. How many of each class is created is important? Which images are the large ones, and which are small? These are all questions you need to ask yourself to get your memory usage down.

But, hopefully, the general techniques I showed example of above can help you get started.




回答3:


The problem was the Custom_ListField. This should extends listfield instead of custom extends manager

public class Custom_ListField extends ListField {
private String[] title, category, date, imagepath;
private int[] newsid, catsid;
private List_News newslist;
private Bitmap imagebitmap[], localimage = Bitmap
        .getBitmapResource("image_base.png");
private BrowserField webpage;
private Custom_BrowserFieldListener listener;
private boolean islatest;

private Vector content = null;
private ListCallback callback = null;

private int currentPosition = 0;

public Custom_ListField(Vector content, boolean islatest) {
    this.content = content;
    this.islatest = islatest;
    newsid = new int[content.size()];
    title = new String[content.size()];
    category = new String[content.size()];
    date = new String[content.size()];
    imagepath = new String[content.size()];
    catsid = new int[content.size()];
    imagebitmap = new Bitmap[content.size()];

    for (int i = 0; i < content.size(); i++) {
        newslist = (List_News) content.elementAt(i);
        newsid[i] = newslist.getID();
        title[i] = newslist.getNtitle();
        category[i] = newslist.getNewCatName();
        date[i] = newslist.getNArticalD();
        imagepath[i] = newslist.getImagePath();

        if (!imagepath[i].toString().equals("no picture")) {
            imagebitmap[i] = Util_ImageLoader.loadImage(imagepath[i]);
        } else {
            imagebitmap[i] = localimage;
        }
        catsid[i] = newslist.getCatID();
    }

    initCallbackListening();
    this.setRowHeight(localimage.getHeight() + 10);
}

private void initCallbackListening() {
    callback = new ListCallback();
    this.setCallback(callback);
}

private class ListCallback implements ListFieldCallback {

    public ListCallback() {
        setBackground(Config_GlobalFunction
                .loadbackground("background.png"));
    }

    public void drawListRow(ListField listField, Graphics graphics,
            int index, int y, int width) {
        currentPosition = index;
        graphics.drawBitmap(
                Display.getWidth() - imagebitmap[index].getWidth() - 5,
                y + 3, imagebitmap[index].getWidth(),
                imagebitmap[index].getHeight(), imagebitmap[index], 0, 0);
        graphics.setColor(Color.WHITE);
        graphics.drawRect(0, y, width, imagebitmap[index].getHeight() + 10);



        graphics.setColor(Color.BLACK);
        graphics.setFont(Font.getDefault().derive(Font.BOLD, 20));
        graphics.drawText(title[index], 5, y + 3, 0, Display.getWidth()
                - imagebitmap[index].getWidth() - 10);

        System.out.println(Display.getWidth()
                - imagebitmap[index].getWidth() - 10);

        graphics.setColor(Color.GRAY);
        graphics.setFont(Font.getDefault().derive(Font.BOLD, 15));
        graphics.drawText(date[index], 5, y + 6
                + Font.getDefault().getHeight() + 3);

        if (islatest) {
            graphics.setColor(Color.RED);
            graphics.setFont(Font.getDefault().derive(Font.BOLD, 15));
            graphics.drawText(category[index], Font.getDefault()
                    .getAdvance(date[index]) + 3, y + 6
                    + Font.getDefault().getHeight() + 3);
        }
    }

    public Object get(ListField listField, int index) {
        return content.elementAt(index);
    }

    public int getPreferredWidth(ListField listField) {
        return Display.getWidth();
    }

    public int indexOfList(ListField listField, String prefix, int start) {
        return content.indexOf(prefix, start);
    }
}

public int getCurrentPosition() {
    return currentPosition;
}

protected boolean navigationClick(int status, int time) {
    int index = getCurrentPosition();
    if (catsid[index] == 9) {
        if (Config_GlobalFunction.isConnected()) {
            webpage = new BrowserField();
            listener = new Custom_BrowserFieldListener();
            webpage.addListener(listener);

            MainScreen aboutus = new Menu_Aboutus();
            aboutus.add(webpage);
            Main.getUiApplication().pushScreen(aboutus);

            webpage.requestContent("http://www.orientaldaily.com.my/index.php?option=com_k2&view=item&id="
                    + newsid[index] + ":&Itemid=223");
        } else
            Config_GlobalFunction.Message(Config_GlobalFunction.nowifi, 1);
    } else
        Main.getUiApplication().pushScreen(
                new Main_NewsDetail(newsid[index]));
    return true;
}
}


来源:https://stackoverflow.com/questions/11463636/failed-to-allocate-timer-0-no-slots-left-and-unable-to-set-dynamic-row-height

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!