×

Discussion Board

Page 1 of 2 12 LastLast
Results 1 to 15 of 19
  1. #1
    Registered User
    Join Date
    Sep 2013
    Posts
    50

    LWUIT: Loading Images on Background Thread

    I have an app that uses LWUIT for s40. The app has a large that displays images from the filesystem. Each cell of the grid is a Button that will display an image. After setting up the layout of the form, including creating all of the Buttons, I am attempting to load these images serially on a background thread. The problem is that this locks up the UI badly. It becomes slow and unresponsive until all images have finished downloading. How can I load the images in the background without impacting the UI? Here is the code that runs in the background:

    Code:
    	private class LoadImagesTask implements Runnable{
    
    		public void run() {
    			for(int i=0;i<images.size();i++){
    				ImageTag tag = (ImageTag)images.get(i);
    				Button b = (Button)buttons.get(i);
    				
                                    //Creates a FileInputStream and passes it into Image.createImage()
    				Image img =ImageUtil.getImage(tag.url);
                                    //Uses Image.subImage() to crop the image
    				img = ImageUtil.cropImageToSquare(img, size);
    				b.setIcon(img);
    				b.setPressedIcon(img);
    
    				
    			}
    		}
    		
    	}

  2. #2
    Nokia Developer Champion
    Join Date
    Mar 2013
    Posts
    686

    Re: LWUIT: Loading Images on Background Thread

    Your code actually doesnt show if your doing this on the LWUIT UI thread or not since your not showing how you use this class...
    also if this code is not done on the UI thread then u shouldnt access UI components on it (buttons etc are UI components)

    i would suggest you post a more complete code so we'll know what exactly your doing and how to advice u.

  3. #3
    Nokia Developer Moderator
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    28,751

    Re: LWUIT: Loading Images on Background Thread

    UI frameworks often dislike being accessed from background threads (this is true for many Java/Java-like environments, LCDUI, LWUIT, even for Android, and also for many non-Java things, so this is something what you always want to check).
    Display.callSerially is the method which you can use to access UI from a secondary thread. Actually the method is the same for LCDUI if you ever need it (just Display class is different). And for getting the actual instance, Display.getInstance is the method (for LWUIT. In the case of LCDUI, it is called Display.getDisplay).

  4. #4
    Registered User
    Join Date
    Sep 2013
    Posts
    50

    Re: LWUIT: Loading Images on Background Thread

    Thanks for your responses. I will try using Display.callSerially();

    The thread is simply started like this:

    new Thread(new LoadImagesTask()).start();

  5. #5
    Registered User
    Join Date
    Sep 2013
    Posts
    50

    Re: LWUIT: Loading Images on Background Thread

    I'm now using Display.callSerially, but I don't notice any difference now. Here's the full class:

    Code:
    public class ImageGridContainer extends Container{
    	
    	
    	Container gridContainer;
    	Image holder; 
    	int size;
    	ArrayList urls;
    	ArrayList buttons;
    	boolean selectImages;
    	Tabs tabBar;
    	
    	Container addTagContainer;
    	public static ImageGridContainer instance;
    	public ImageGridContainer(Tabs tabBar){
    		this.tabBar=tabBar;
    		instance=this;
    		urls=new ArrayList();
    		buttons=new ArrayList();
    		runIndexer();
    		Log.v("Indexer done");
    		setUpLayout();
    		displayGrid();
    	}
    	
    	public void runIndexer(){
    		ImageURL.purgeUrls();
            ImageURL.indexImages();
    		urls=ImageURL.fetchUrlsFromDb();
    		Log.v("numImages: "+urls.size());
    	}
    	public void setUpLayout(){
    		this.setLayout(new BorderLayout());
    		
    		size=80;
    		holder = null;
    		try {
    			holder = Image.createImage("/holder.png").scaled(size, size);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		final GridLayout gridLayout = new GridLayout(4, 3);
    		gridLayout.setAutoFit(true);
    		gridContainer = new Container(gridLayout);
    		gridContainer.setScrollableY(true);
    		gridContainer.setScrollVisible(false);
    
    		this.addComponent(BorderLayout.CENTER,gridContainer);
    		
    		addTagContainer = new Container(new BorderLayout());
    		
    		addTagContainer.setPreferredH(50);
    		addTagContainer.getStyle().setBgTransparency(255);
    		addTagContainer.getStyle().setBgColor(PicTag.PICTAG_TEAL);
    		
    		Image addTagIcon = null;
    		try {
    			addTagIcon = Image.createImage("/tagAddButtonHighlight.png");
    			
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		Image addTagPressedIcon = null;
    		try {
    			addTagPressedIcon = Image.createImage("/tagAddButtonHighlight.png");
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		Button addTagButton = new Button(addTagIcon);
    		Style bstyle = new Style();
    		bstyle.setMargin(0, 5, 0, 0);
    		bstyle.setBgTransparency(0);
    		Style bstylePressed = new Style();
    		bstylePressed.setMargin(0, 5, 0, 0);
    		bstylePressed.setBgTransparency(0);
    		addTagButton.setPressedIcon(addTagPressedIcon);
    		addTagButton.setPressedStyle(bstylePressed);
    		addTagButton.setUnselectedStyle(bstyle);
    		addTagButton.setSelectedStyle(bstylePressed);
    		addTagButton.getStyle().setAlignment(CENTER);
    		addTagButton.getUnselectedStyle().setAlignment(CENTER);
    		addTagButton.getPressedStyle().setAlignment(CENTER);
    		addTagButton.setDisabledStyle(addTagButton.getStyle());
    		addTagContainer.addComponent(BorderLayout.CENTER,addTagButton);
    		
    		addTagButton.addActionListener(new ActionListener(){
    
    			public void actionPerformed(ActionEvent arg0) {
    				
    				//TODO: start AddTagFrom with selected images
    				
    			}
    			
    		});
    		
    		this.setScrollableY(true);
    		this.setScrollVisible(false);
    		
    	}
    
    
    	
    	public void displayGrid(){
    		for(int i=0;i<urls.size();i++){
    			final int index=i;
    			final PicTagRecord url = (PicTagRecord)urls.get(i);
    
    			Log.v(url.getFilePath());
    			final Button b = new Button();
    			b.getStyle().setMargin(0, 0, 0, 0);
    			b.getStyle().setPadding(0, 0, 0, 0);
    			b.setSelectedStyle(b.getStyle());
    			b.setUnselectedStyle(b.getStyle());
    			b.setPressedStyle(b.getStyle());
    			b.setDisabledStyle(b.getStyle());
    			b.setIcon(holder);
    			b.setPressedIcon(holder);
    			b.addActionListener(new ActionListener(){
    
    				public void actionPerformed(ActionEvent evt) {
    					
    					ImageViewForm f = new ImageViewForm(urls, index);
    					BackStack.getInstance().forward(HomeTabForm.instance, f);
    					
    				}
    				
    			});
    			buttons.add(b);
    			gridContainer.addComponent(b);
    	
    		
    		}
    		
    		
    		new Thread(new LoadImagesTask()).start();
    	}
    	
    	public void startSelectImagesMode(){
    		selectImages=true;
    		tabBar.hideTabs();
    		
    		this.addComponent(BorderLayout.SOUTH, addTagContainer);
    		
    	}
    	
    	public void endSelectImagesMode(){
    		
    	}
    	
    	private class LoadImagesTask implements Runnable{
    
    		public void run() {
    			for(int i=0;i<urls.size();i++){
                    PicTagRecord tag = (PicTagRecord)urls.get(i);
    				Button b = (Button)buttons.get(i);
    				
    				Image img =ImageUtil.getImage(tag.getFilePath());
    				img = ImageUtil.cropImageToSquare(img, size);
    				
    	
    				
    				SetImagesTask task = new SetImagesTask(b,img);
    				Display.getInstance().callSerially(task);
    				
    
    				
    				
    			}
    		}
    		
    	}
    	
    	private class SetImagesTask implements Runnable {
    		Button b;
    		Image i;
    		public SetImagesTask(Button b, Image i){
    			this.b=b;
    			this.i=i;
    		}
    
    		public void run() {
    			b.setIcon(i);
    			b.setPressedIcon(i);
    			
    		}
    		
    	}

  6. #6
    Nokia Developer Champion
    Join Date
    Mar 2013
    Posts
    686

    Re: LWUIT: Loading Images on Background Thread

    Do you have some metrics that you have measured?
    for instance how many files are you trying to loading? what is the avg size of each file? how much time the entire process takes? etc.

    So we'll know if your definition of "slow" is indeed slow and there is a problem with the code or is it considered normal for your situation.

  7. #7
    Registered User
    Join Date
    Sep 2013
    Posts
    50

    Re: LWUIT: Loading Images on Background Thread

    Right now I'm loading around 70 images, around 1mb each. By "slow" I mean that the UI is completely unresponsive (I can't scroll) until all images are finished loading.

    My real requirement is that I match the behavior of the Nokia Gallery app. With the same images, it seems to load almost instantly and there's no UI sluggishness.

  8. #8
    Nokia Developer Champion
    Join Date
    Mar 2013
    Posts
    686

    Re: LWUIT: Loading Images on Background Thread

    Are you targeting new Asha platform? if so you can use the ImageScale API to generate smaller thumbnails of the file system images and load them which should be MUCH faster.
    I dont think you will ever manage to get the full speed of the native gallery app since its native and your running on top of a jvm.

  9. #9
    Registered User
    Join Date
    Sep 2013
    Posts
    50

    Re: LWUIT: Loading Images on Background Thread

    Thanks Shai, I'll give that a shot!

  10. #10
    Registered User
    Join Date
    Sep 2013
    Posts
    50

    Re: LWUIT: Loading Images on Background Thread

    I'm not sure ImageScale will work for us. We need to scale the image down, then crop the image to a 80x80 square. Before we can crop, we need to know the dimensions of the image so we know whether to scale the width to 80 or the height to 80. We need to load the image first to access this. So if we have to load the full size image with Image.createImage() , it doesn't seem like ImageScaler would save us anything.

  11. #11
    Registered User
    Join Date
    Sep 2013
    Posts
    50

    Re: LWUIT: Loading Images on Background Thread

    Although I guess we could just scale one width to 80, another height to 80, load them both with Image.createImage() then check to see which is correct. I'm guessing that would still be a lot faster. I'll try that next.

  12. #12
    Nokia Developer Champion
    Join Date
    Mar 2013
    Posts
    686

    Re: LWUIT: Loading Images on Background Thread

    Why do you even want to crop and not just scale down to 80 pixels? i dont think the native gallery app crop any of the thumbnails.

  13. #13
    Registered User
    Join Date
    Sep 2013
    Posts
    50

    Re: LWUIT: Loading Images on Background Thread

    Quote Originally Posted by shai.i View Post
    Why do you even want to crop and not just scale down to 80 pixels? i dont think the native gallery app crop any of the thumbnails.
    They do crop them. The images appear in the grid as squares (without the aspect ratio distorted at all). For example, for a portrait image, the top and bottom are cropped in the grid.

  14. #14
    Registered User
    Join Date
    Sep 2013
    Posts
    50

    Re: LWUIT: Loading Images on Background Thread

    I am having trouble with ImageScaler. The scale operation seems to complete successfully. I can view the scaled image at the destination filepath. Yet when I try to do Image.createImage on this filepath, it says that the image cannot be found.

  15. #15
    Registered User
    Join Date
    Sep 2013
    Posts
    50

    Re: LWUIT: Loading Images on Background Thread

    It looks like the Gallery app is using something like ImageScaler also. I noticed that when you start the gallery app, a new folder is created in _my_pictures called "sp-thumbs," and it contains a scaled down copy of each image. I have a few questions about this:

    1. How does the Gallery app create a new folder for the images? If I give ImageScaler a destination path with a currently non-existent directory, rather than just creating a directory at that path like I hoped, it crashes with an error about the directory not existing.

    2. How does the Gallery app know to skip over the images in this sp-thumbs folder? Just by checking the name of the folder?

    3. When I try to do Image.createImage for image that I have scaled using ImageScaler, it tells me the file does not exist, even though I can easily verify that the image does in fact exist at the destination path I specified. Why?

Similar Threads

  1. Issue in loading images into command in lwuit for nokia s40
    By rchadalawada in forum Mobile Java General
    Replies: 13
    Last Post: 2013-03-08, 09:31
  2. Lwuit circle loading bar
    By mjagadeeshbabu in forum Mobile Java General
    Replies: 0
    Last Post: 2011-05-06, 13:17
  3. loading midlet from lwuit
    By simsimlhr in forum Mobile Java General
    Replies: 1
    Last Post: 2008-11-03, 19:56
  4. Tip: Loading modules in a background thread
    By bercobeute in forum Symbian
    Replies: 1
    Last Post: 2006-02-27, 05:19
  5. Loading 2 Images Loading Problem
    By nimbus_cloud in forum Symbian Media (Closed)
    Replies: 1
    Last Post: 2005-08-26, 05:51

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×