Overview of Observer Design pattern:
It is used to implement the Publisher/Subscriber scenario. We need a mechanism which allows us to notify subscriber objects whenever the publisher object changes state. For observers to receive a notification, they must implement some kind of update method/listeners which the subject can call whenever it changes state. The observers must have the freedom to register and un-register from subscription to the subject at any point in time.
Here in this example the subscriber object is the Blackberry UI thread and the publisher object is the Networking/Downloading thread. Network thread has to notify the UI thread once it complete or failed to download. And then the UI thread takes the control and updates the information in UI.
Steps:
package com.javatechig.bb.java.ui;
import net.rim.device.api.ui.UiApplication;
public class DownloadMain extends UiApplication {
public static void main(String[] args) {
DownloadMain app = new DownloadMain();
app.enterEventDispatcher();
}
public DownloadMain() {
ImageDownloadScreen screen = new ImageDownloadScreen();
pushScreen(screen);
}
}
package com.javatechig.bb.java.ui;
import net.rim.device.api.system.Bitmap;
public interface DownloadListener {
// invokes if download success
public void downloadSuccess(Bitmap bitmap);
// invokes if download failed
public void errorOccured();
}
package com.javatechig.bb.java.ui;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.Dialog;
import com.span.bb.java.net.ImageDownloader;
public class ImageDownloadScreen extends LoaderScreen implements DownloadListener{
ImageDownloadScreen activeScreen = null;
public ImageDownloadScreen() {
setTitle("Download Image");
ButtonField btn = new ButtonField("Click to Download", ButtonField.CONSUME_CLICK) {
protected boolean navigationClick(int arg0, int arg1) {
setShowLoader(true);
//starting download thread
ImageDownloader download = new ImageDownloader("http://www.ciracar.com/img/girls/cute_selena_gomez/cute_selena_gomez7.jpg");
download.setDelegate(activeScreen);
//Starting download thread
new Thread(download).start();
return true;
}
}
;
//adding button to screen
add(btn);
//getting the reference of active screen
activeScreen = this;
}
// Method to perform all the UI activity, like update to UI if the download success
public void downloadSuccess(final Bitmap bitmap) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
setShowLoader(false);
if (bitmap == null) {
Dialog.alert("Failed to download Image");
}
else {
try {
BitmapField image = new BitmapField(bitmap);
activeScreen.add(image);
}
catch (Exception e) {
Dialog.alert("Got error: " + e);
}
}
}
}
);
}
//display error message if error in download
public void errorOccured() {
//Currently not being used
Dialog.alert("Failed to download Image");
}
}
package com.javatechig.bb.java.net;
import net.rim.device.api.servicebook.ServiceBook;
import net.rim.device.api.servicebook.ServiceRecord;
import net.rim.device.api.system.DeviceInfo;
import net.rim.device.api.system.RadioInfo;
import net.rim.device.api.system.WLANInfo;
public class NetRequest {
protected String updateConnSuffix() {
String connSuffix = null;
if (DeviceInfo.isSimulator()) {
connSuffix = ";deviceside=true";
}
else if ((WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED)
&& RadioInfo.areWAFsSupported(RadioInfo.WAF_WLAN)) {
connSuffix = ";interface=wifi";
}
else {
String uid = null;
ServiceBook sb = ServiceBook.getSB();
ServiceRecord[] records = sb.findRecordsByCid("WPTCP");
for (int i = 0; i < records.length; i++) {
if (records[i].isValid() && !records[i].isDisabled()) {
if (records[i].getUid() != null
&& records[i].getUid().length() != 0) {
if ((records[i].getCid().toLowerCase().indexOf("wptcp") != -1)
&& (records[i].getUid().toLowerCase().indexOf(
"wifi") == -1)
&& (records[i].getUid().toLowerCase().indexOf(
"mms") == -1)) {
uid = records[i].getUid();
break;
}
}
}
}
if (uid != null) {
// WAP2 Connection
connSuffix = ";ConnectionUID=" + uid;
}
else {
connSuffix = ";deviceside=true";
}
}
return connSuffix;
}
}
package com.javatechig.bb.java.net;
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import com.javatechig.java.ui.DownloadListener;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.component.Dialog;
public class ImageDownloader extends NetRequest implements Runnable {
// Holds the URL to download the image
StringBuffer url = null;
//holds the instance of the delegate screen
protected Object delegate;
public ImageDownloader(String url) {
// image URL
this.url = new StringBuffer();
this.url.append(url.toString());
}
//taking the instance of the delegate
//this is the object of the active screen from where the request is made
public Object getDelegate() {
return delegate;
}
public void setDelegate(Object delegate) {
this.delegate = delegate;
}
// Thread starts the execution
public void run() {
byte[] dataArray;
InputStream input;
url.append(updateConnSuffix());
HttpConnection httpConn = null;
try {
httpConn = (HttpConnection) Connector.open(url.toString());
input = httpConn.openInputStream();
dataArray = net.rim.device.api.io.IOUtilities.streamToBytes(input);
final Bitmap googleImage = Bitmap.createBitmapFromBytes( dataArray, 0, -1, 1);
((DownloadListener) delegate).downloadSuccess(googleImage);
}
catch (IOException e) {
e.printStackTrace();
Dialog.alert("Eoor in downloading image");
}
}
}
package com.javatechig.bb.java.ui;
import java.util.Timer;
import java.util.TimerTask;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.container.MainScreen;
public class LoaderScreen extends MainScreen {
Timer loadingTimer = new Timer();
TimerTask loadingTask;
int imageIndex = 0;
Bitmap loader1 = Bitmap.getBitmapResource("loader001.png");
Bitmap loader2 = Bitmap.getBitmapResource("loader002.png");
Bitmap loader3 = Bitmap.getBitmapResource("loader003.png");
Bitmap loader4 = Bitmap.getBitmapResource("loader004.png");
Bitmap loader5 = Bitmap.getBitmapResource("loader005.png");
Bitmap loader6 = Bitmap.getBitmapResource("loader006.png");
Bitmap loader7 = Bitmap.getBitmapResource("loader007.png");
Bitmap loader8 = Bitmap.getBitmapResource("loader008.png");
Bitmap loader9 = Bitmap.getBitmapResource("loader009.png");
Bitmap loader10 = Bitmap.getBitmapResource("loader010.png");
Bitmap loader11 = Bitmap.getBitmapResource("loader011.png");
Bitmap loader12 = Bitmap.getBitmapResource("loader012.png");
boolean showLoader = false;
int screenWidth = Display.getWidth();
int screenHeight = Display.getHeight();
int xAnchor = (screenWidth-200)/2;
int yAnchor = (screenHeight-40)/2;
String loaderText = "Please wait...";
public LoaderScreen() {
super();
loadingTask = new TimerTask() {
public void run() {
invalidate();
imageIndex++;
if(imageIndex == 11){
imageIndex = 0;
}
}
}
;
loadingTimer.scheduleAtFixedRate(loadingTask, 100, 100);
}
public void setShowLoader(boolean showLoader) {
this.showLoader = showLoader;
}
public boolean isShowing(){
return showLoader;
}
protected void paint(Graphics graphics) {
super.paint(graphics);
if (showLoader) {
//draw background:
graphics.setColor(0x363636);
graphics.fillRect(xAnchor, yAnchor, 200, 40);
//draw animation frame:
switch (imageIndex) {
case 0:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader1, 0, 0);
break;
case 1:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader2, 0, 0);
break;
case 2:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader3, 0, 0);
break;
case 3:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader4, 0, 0);
break;
case 4:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader5, 0, 0);
break;
case 5:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader6, 0, 0);
break;
case 6:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader7, 0, 0);
break;
case 7:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader8, 0, 0);
break;
case 8:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader9, 0, 0);
break;
case 9:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader10, 0, 0);
break;
case 10:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader11, 0, 0);
break;
case 11:
graphics.drawBitmap(xAnchor + 4, yAnchor + 4, 32, 32, loader12, 0, 0);
break;
}
graphics.setColor(0xefefef);
graphics.drawText(loaderText, xAnchor + 44, yAnchor + 6);
graphics.setColor(0xff0000);
graphics.drawRect(xAnchor, yAnchor, 200, 40);
}
}
}
I am using sequence of .png images for displaying the loading screen. You can find the images and complete source code from the Google code repository. Use this command to anonymously check out the latest project source code:
http://code.google.com/p/image-downloader-for-blackberry/
# Non-members may check out a read-only working copy anonymously over HTTP.
svn checkout http://image-downloader-for-blackberry.googlecode.com/svn/trunk/ image-downloader-for-blackberry-read-
Related Posts:
- HTTP Connection in Blackberry
- Printing logs in Blackberry
- How to recoding call in blackberry
- Observer design pattern in blackberry
- How to block incoming call in Blackberry
- Process http request and handling response in Blackberry
- How to create a custom ListField in blackberry
- Sending Email with Attachment in Blackberry
- Customizing Blackberry LabelField
- Saving Bitmap Image in Blackberry File System
Tags: BlackBerry, Code Sample, Design Patterns



How about downloading multiple list items asyncly. ? can you please provide me some samples or some idea to implement the same. I want to have a scrollable list with a icon, and two headings for each row. Any samples would help.
You have to go for thread pool design pattern. Where you have to maintain the maximum pool size and play around with the worker threads. Below are the ideas to implement the same
1. Create one
TaskWorkerfor your application (use singelton)2. Implement Task class from TaskWorker –
DownloadImageTask(simply put everything fromRunnable.run()toTask.doTask()method)3. Instead of new thread creation for every image download, just add tasks to queue TaskWorker.addTask()
You have to keep the thread safety in mind.
Nice one. It would be good if you could put some screenshots along with post.
This post is really helpful. Thank you.
Hi, I am a new bee to Blackberry development.
Can you please provide me the logic to save the image into SDCard after downloading?
Any help will be appreciated.
-Subash
Nice blog.. I will love to follow it.
I am JOY, happened to have your code from google code. But it doesnt seems to be compiled. Can you help me to understand where it is going wrong?
As i am a bignner to BB programming, my question might be a silly one.
Thanks in advance.