Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
Developer
Posts: 729
Registered: ‎05-04-2011
My Device: 9700

Re: Detect SDCARD on App Startup

Hi @

 

This is a crazy thought but, are you running your application while your device is connected to USB cable?

 

If yes, then the device usually unmount the sdcard when connected to USB so you should try it while the device is unplugged.

 

Hope that helps,

 

E.

Trusted Contributor
Posts: 202
Registered: ‎11-21-2010
My Device: 9700
My Carrier: Virgin Mobile

Re: Detect SDCARD on App Startup

Thank for the reply.  Much appreciated.  I've modified the code to reflect your additions, however, now the app no longer starts up after device restarts...

 

public

class MyApp extends UiApplication

{

publicstaticvoid main(String[] args)

{

MyApp theApp = new MyApp();

 

if(ApplicationManager.getApplicationManager().inStartup())

  {

    theApp.invokeLater(

new Runnable() {

     

publicvoid run()

      {

        ApplicationManager appManager = ApplicationManager.getApplicationManager();

       

while(appManager.inStartup())

        {

         

//still booting, sleep some

         

try

          {

            Thread.sleep(1000);

          }

         

catch (Throwable error)

          {

           

// nothing

          }

        }

       

       

try

        {

          

boolean sdCardPresent = false;

           String root =null;

           Enumeration e = FileSystemRegistry.listRoots();

          

while (e.hasMoreElements() && !sdCardPresent ) {

              root = (String)e.nextElement();

             

if(root.equalsIgnoreCase("sdcard/")) {

                sdCardPresent =true;

              }

           }

          

if(sdCardPresent) {

            

//create db here if not exists

           }

          

else {

           UiApplication.getUiApplication().invokeLater(

new Runnable() {

publicvoid run() {

Dialog.alert("SD card to be present. Exiting app.");

System.exit(0);

}

});

           }

        }

       

catch(Throwable error)

        {

         

//log the error

        }

 

        System.exit(0);

      }

    });

  }

 

  theApp.enterEventDispatcher();

}

 

public MyApp() {

pushScreen(new MyAppMainScreen());

}

 

 

}

 

 

Developer
Posts: 1,041
Registered: ‎07-16-2008
My Device: ಠ_ಠ

Re: Detect SDCARD on App Startup

Don't run it in main. Start your app and run the loop in another Thread, and put whatever you need to do with the SDCard in that Thread after the loop.

Developer
Developer
Posts: 1,123
Registered: ‎02-10-2009
My Device: 8130 / 8350 / 9530 / 9550 / 9850 / PlayBook
My Carrier: Verizon

Re: Detect SDCARD on App Startup

Do as suggested and make sure the device is not in startup but instead of doing an if do a while.

 

ex.

while(ApplicationManager.getApplicationManager().inStartup()){
   sleep(500);
}

 

Once you get out of that loop you know the device is ready and the SDCard should be available. And you can do that inside your main function at the very top.

 

And you siad the code is now not working do you know where it hangs at?

Highlighted
Developer
Posts: 176
Registered: ‎11-06-2008
My Device: Not Specified

Re: Detect SDCARD on App Startup

Hi KJake,

 

Ok, I have 2 things to point out here. 

 

1: Please use the Code feature of the WYSIWYG editor when posting your code here, it makes it readable. It's at the top of the post entry text area, it looks like a clip board icon withthe letter C on top of it in a white box.

 

2: The organization of the code is a jumble. Let's break this into some different classes based on a proven design I've used for years. Here's the new code organization I propose you move to. It's not as bad as it sounds, it just gives a cleaner line of division between what code runs when the app auto starts at boot time and what code runs when the app icon is clicked.

 

 

 

First let's make a Main class that just contains the main function. Don't worry about the Arguments class I reference, I'm including that source as well, it's just a utility class that processes arguments to the application and supports traditional command line style argument lists like "-launcher=autostartup;-x=7"

 

public final class Main
{
    public static void main(String[] args)
    {
        //read any arguments
        Arguments arguments = new Arguments(args);

        //check for the launcher argument
        String launcher = arguments.getOptionValue("launcher");

        //react to the launcher argument accordingly
        if (StringUtilities.strEqual(launcher, "autostartup"))
        {
            //launcher arg is for auto start up
            //start the bg process
            //get an bg app instance
            BackgroundApp bgApp = BackgroundApp.getInstance();
            //save the args it was launched with
            bgApp._arguments = arguments;

            /*
             * now we need to initialize non static members of the bg proc's app
             * instance but since we could be booting release control by
             * invoking later
             */
            bgApp.invokeLater(new Runnable()
            {
                public void run()
                {
                    //check if the device is still booting
                    ApplicationManager appManager = ApplicationManager.getApplicationManager();
                    while (appManager.inStartup())
                    {
                        //still booting, sleep some
                        try
                        {
                            Thread.sleep(1000);
                        }
                        catch (Throwable error)
                        {
                            // nothing
                        }
                    }
                    //device is fully booted, now init app instance members 
                    BackgroundApp.getInstance().initialize();

                    //exit
                    System.exit(0);
                }
            });

            //start the proc's event dispatcher so this process stays running until the runnable set above this has time to finish and calls exit
            bgApp.enterEventDispatcher();
        }
        else
        {
            //it's not the bg proc launcher, assume it's the fg proc
            //start the fg proc
            //get a fg app instance
            ForegroundApp fgApp = ForegroundApp.getInstance();
            //save the args it was launched with
            fgApp._arguments = arguments;

            //init the instance members
            fgApp.initialize();

if (fgApp._sdCardProblem) {
//uh oh, tell the user something's not right
} else { //push a screen to the fgApp's screen stack or whatever else you need for the UI
} //start the proc's event dispatcher fgApp.enterEventDispatcher(); } } }

 

Here's the Arguments class

 

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import net.rim.device.api.system.Characters;

public final class Arguments
{
    public Hashtable _options = new Hashtable();
    public Vector _parameters = new Vector();

    public Arguments()
    {
        this(null);
    }

    public Arguments(String[] args)
    {
        parseArguments(args);
    }

    public void parseArguments(String[] args)
    {
        _options.clear();
        _parameters.removeAllElements();
        if (args != null)
        {
            for (int i = 0 ; i < args.length ; i++)
            {
                String[] argPieces = splitString(args[i], Characters.SEMICOLON, false);
                for (int ii = 0 ; ii < argPieces.length ; ii++)
                {
                    String argPiece = argPieces[ii];
                    if (argPiece.length() > 0 && (argPiece.charAt(0) == Characters.HYPHEN_MINUS || argPiece.charAt(0) == Characters.SOLIDUS))
                    {
                        // it's an option
                        if (argPiece.length() > 1)
                        {
                            int indexOfAssignment = argPiece.indexOf(Characters.EQUALS_SIGN);
                            if (indexOfAssignment == -1)
                            {
                                // stand alone flag
                                String argName = argPiece.substring(1);
                                _options.put(argName, '');
                            }
                            else if (indexOfAssignment > 1)
                            {
                                // flag has assigned value
                                if (indexOfAssignment == argPiece.length() - 1)
                                {
                                    // value is empty string
                                    String argName = argPiece.substring(1, indexOfAssignment);
                                    _options.put(argName, '');
                                }
                                else
                                {
                                    // value is not empty string
                                    String argName = argPiece.substring(1, indexOfAssignment);
                                    String argValue = argPiece.substring(indexOfAssignment + 1);
                                    if (argValue.length() > 0 && 
                                           ((argValue.charAt(0) == Characters.QUOTATION_MARK && 
                                             argValue.charAt(argValue.length() - 1) == Characters.QUOTATION_MARK) || 
                                            (argValue.charAt(0) == Characters.APOSTROPHE && 
                                             argValue.charAt(argValue.length() - 1) == Characters.APOSTROPHE)))
                                    {
                                        argValue = argValue.substring(1, argValue.length() - 1);
                                    }
                                    _options.put(argName, argValue);
                                }
                            }
                        }
                    }
                    else
                    {
                        // it's a paramter
                        _parameters.addElement(argPiece);
                    }
                }
            }
        }
    }

    public boolean hasOption(String name)
    {
        if (name == null)
        {
            return (false);
        }
        return (_options.containsKey(name));
    }

    public String getOptionValue(String name)
    {
        if (name == null || !_options.containsKey(name))
        {
            return (null);
        }
        return ((String) _options.get(name));
    }

    public Vector getOptionNames()
    {
        Enumeration keyEnum = _options.keys();
        Vector keyVector = new Vector();
        while (keyEnum.hasMoreElements())
        {
            keyVector.addElement(keyEnum.nextElement());
        }
        return (keyVector);
    }

public String[] splitString(String data, char splitChar, boolean allowEmpty)
{
if(data == null) {
return new String[0];
}
Vector v = new Vector();
int indexStart = 0;
      int indexEnd = data.indexOf(splitChar);
if (indexEnd != -1)
      {
            while (indexEnd != -1)
            {
                String s = data.substring(indexStart, indexEnd);
                if (allowEmpty || s.length() > 0)
                {
                    v.addElement(s);
                }
                indexStart = indexEnd + 1;
                indexEnd = data.indexOf(splitChar, indexStart);
            }
            if (indexStart != data.length())
            {
                // Add the rest of the string
                String s = data.substring(indexStart);
                if (allowEmpty || s.length() > 0)
                {
                    v.addElement(s);
                }
            }
}
else
{
      if (allowEmpty || data.length() > 0)
            {
v.addElement(data);
            }
}
String[] result = new String[v.size()];
v.copyInto(result);
return (result);
}
}

 

Now that you have the Arguments class let's add some arguments to the background auto starting application. In your alternate entry point set your application argument to the following string

 

-launcher=autostartup

 

For your main entry point that runs when the user clicks the icon DO NOT set any argument string. There's a technical reason to not set arguments for the main icon but that is not really important to the topic of this discussion, but I'm more than happy to explain why later if you want.

 

So now that we have arguments to distinguish how the application is starting we then have better control in the main function on what is going to execute.

 

Let's look at the background application which is what is run when the auto starting alternate entry point is executed.

 

//note this extends Application and not UiApplication
public final class BackgroundApp extends Application {
  private static BackgroundApp _instance;
  private boolean _initialized = false;
  public Arguments _arguments;

  //it's a singleton pattern so use getInstance() instead of the contructor
  private BackgroundApp()
  {
  }

  public static synchronized BackgroundApp getInstance()
  {
    if (_instance == null)
    {
      _instance = new BackgroundApp();
    }
    return (_instance);
  }

  public void initialize()
  {
    synchronized (this)
    {
      if (!_initialized)
      {
        //do your SD card check and DB creation here, but no UI work is done here

        _initialized = true;
      }
    }
  }

  public boolean isInitialized()
  {
    synchronized (this)
    {
      return (_initialized);
    }
  }
}

 

Here's the foreground application that runs when the user clicks the icon

 

public final class ForegroundApp extends UiApplication {
  private static ForegroundApp _instance;
  private boolean _initialized = false;
private boolean _sdCardProblem = false; public Arguments _arguments; //singleton private ForegroundApp() { } public static synchronized ForegroundApp getInstance() { if (_instance == null) { _instance = new ForegroundApp(); } return (_instance); } public void initialize() { synchronized (this) { if (!_initialized) {
//any initialization work goes here, but do not do UI updates inside the synchronized block
//if SDcard or DB still not found then set a flag
_sdCardProblem = true;
_initialized = true; } } } public boolean isInitialized() { synchronized (this) { return (_initialized); } } }

 

 

 

 

 

Trusted Contributor
Posts: 202
Registered: ‎11-21-2010
My Device: 9700
My Carrier: Virgin Mobile

Re: Detect SDCARD on App Startup

Thanks a lot for the time, jhw1701.  Really appreciate it.  Unfortunately I am still not able to make this work.  Don't have the code handy but still not detecting the sdcard after restart...  I'll keep playing with it.

Trusted Contributor
Posts: 202
Registered: ‎11-21-2010
My Device: 9700
My Carrier: Virgin Mobile

Re: Detect SDCARD on App Startup

Not sure i need to be concerned with if the app is auto run or clicked.  Can the code be modified to remove arguments and still function as expected?  My app should not even function if no sd card is present regardless of auto run or clicked on.  I'm attempting this now.  Thanks for all of your assistance.

Trusted Contributor
Posts: 202
Registered: ‎11-21-2010
My Device: 9700
My Carrier: Virgin Mobile

Re: Detect SDCARD on App Startup

Unfortunately no go... still not working as expected using sample provided.  I've reverted code back and am wondering if you may have any more thoughts on how this can be dome simply. Really appreciate your help on thismatter.  Thank you much.

Developer
Posts: 176
Registered: ‎11-06-2008
My Device: Not Specified

Re: Detect SDCARD on App Startup

My code sample was an attempt to provide a better separation of logic between auto-start time and user-clicking-the-icon time.  You still never answered by first question. Is there an error message logged anywhere.

Trusted Contributor
Posts: 202
Registered: ‎11-21-2010
My Device: 9700
My Carrier: Virgin Mobile

Re: Detect SDCARD on App Startup

Thanks for the rpely.  No error messages at all.