Welcome to the Official BlackBerry® Support Community Forums. This is your resource to discuss support topics with your peers, and learn from each other. New to the forum? Please visit the ‘Getting Started’ link below.
inside custom component

Java Development

Reply
New Developer
brent_glad
Posts: 66
Registered: 11-23-2009

Telling my thread what to do

Hi,

 

I created an application that creates an object that extends mainscreen.

 

that object creates an object that extends Thread.

 

THAT object gets intantiated and i do a .start() on it.

 

Naturally, that runs the run() function of that class that extends Thread, right?

 

I have that run() function do all the steps of creating a media player, prefetching and playing.

 

Now, how do I control that player with the menu buttons or UI buttons?

 

the object is called playerThread. Why can't I go playerThread.stopPlaying(); inside the run() of my menuItem???

 

 

class myApp extends UiApplication {
    public static void main(String[] args)
    {
        // Create a new instance of the application.
        myApp theApp = new myApp();

        // To make the application enter the event thread and start processing messages, 
        // we invoke the enterEventDispatcher() method.
        theApp.enterEventDispatcher();
    }

    private myApp()
    {
        // Push the main screen instance onto the UI stack for rendering.
        pushScreen(new myAppScreen());
    }    
}

class myAppScreen extends MainScreen
{
    private String murl;
    private String currentUrlToPlay;
    private HttpConnection conn;
    private InputStream is;
    private SharedInputStream readAhead;
    private Player _player;

    myAppScreen() {
        boolean whereAmI = UiApplication.getUiApplication().isEventThread();
        System.out.println("Am I in the event thread?" + whereAmI);

        PlayerThread playerThread = new PlayerThread();
        playerThread.start();
    }
    
    class PlayerThread extends Thread {

        void startPlayer() {
            UiApplication.getUiApplication().invokeLater(new Runnable() {
                public void run() {
                    Status.show("invoked message.");
                }
            });

            murl = "http://www.myhost.com/mp3stream;deviceside=true;interface=wifi";
                try
                {
                    conn = (HttpConnection) Connector.open(murl, Connector.READ_WRITE);
                }
                catch (Exception e)
                {
                    murl = "http://www.myhost.com/mp3stream;deviceside=true";
                    try {
                        conn = (HttpConnection) Connector.open(murl, Connector.READ_WRITE);
                    }
                    catch (Exception f) {
                    }
                }
                try
                {
                    is = conn.openInputStream();
                    readAhead = SharedInputStream.getSharedInputStream(is);
                    _player = Manager.createPlayer(readAhead, "audio/mpeg");
                    _player.realize();
                    _player.prefetch();
                    _player.start();
                }
                catch (Exception e) {
            UiApplication.getUiApplication().invokeLater(new Runnable() {
                public void run() {
                    Status.show("failure.");
                }
            });
                }
        }

        void stopPlaying() {
            _player.stop();
        }

        public void run() {
            startPlayer();
        }
    }

    private MenuItem playItem = new MenuItem("Play", 200000, 10) {
    public void run() {
        Status.show("Connecting...");
    }
    };

    private MenuItem pauseItem = new MenuItem("Pause", 200000, 10) {
    public void run() {
        Status.show("Pausing...");
        playerThread.stopPlaying();
    }
    };

 

 

Please use plain text.
Developer
peter_strange
Posts: 14,614
Registered: 07-14-2008

Re: Telling my thread what to do

I presume this is a "proof of concept" rather than a piece of production code, so I won't comment on things like missing closes for connections.

 

I've rewritten it a little as follows to give you some hints as to how it might be done and the issues (especially timing when the stop is called before the player has even started), that you will face.  My code is only suitable for a proof of concept.

 

class myAppScreen extends MainScreen
{
    private String murl;
    private String currentUrlToPlay;
    private HttpConnection conn;
    private InputStream is;
    private SharedInputStream readAhead;
    private Player _player;
    PlayerThread _playerThread

    myAppScreen() {
        boolean whereAmI = UiApplication.getUiApplication().isEventThread();
        System.out.println("Am I in the event thread?" + whereAmI);

        _playerThread = new PlayerThread();
        _playerThread.start();
    }
    
    private MenuItem playItem = new MenuItem("Play", 200000, 10) {
    public void run() {
        Status.show("Connecting...");
    }
    };

    private MenuItem pauseItem = new MenuItem("Pause", 200000, 10) {
    public void run() {
        Status.show("Pausing...");
        _playerThread.stopPlaying();
    }
};

   class PlayerThread extends Thread {

boolean _stopped = false;
        void startPlayer() {
            UiApplication.getUiApplication().invokeLater(new Runnable() {
                public void run() {
                    Status.show("invoked message.");
                }
            });

            murl = "http://www.myhost.com/mp3stream;deviceside=true;interface=wifi";
                try
                {
                    conn = (HttpConnection) Connector.open(murl, Connector.READ_WRITE);
                }
                catch (Exception e)
                {
                    murl = "http://www.myhost.com/mp3stream;deviceside=true";
                    try {
                        conn = (HttpConnection) Connector.open(murl, Connector.READ_WRITE);
                    }
                    catch (Exception f) {
                    }
                }
if ( conn == null ) {
return;
}
                try
                {
                    is = conn.openInputStream();
                    readAhead = SharedInputStream.getSharedInputStream(is);
                    _player = Manager.createPlayer(readAhead, "audio/mpeg");
if ( !_stopped ) {
                    _player.realize();
                    _player.prefetch();
                    _player.start();
}
                }
                catch (Exception e) {
            UiApplication.getUiApplication().invokeLater(new Runnable() {
                public void run() {
                    Status.show("failure.");
                }
            });
                }
        }

        void stopPlaying() {
_stopped = true;
if ( _player != null ) {
            _player.stop();
}
        }

        public void run() {
            startPlayer();
        }
    }

 

Please use plain text.
New Developer
brent_glad
Posts: 66
Registered: 11-23-2009

Re: Telling my thread what to do

Thanks for the solution!

 

I had to run a makemenu on the bottom and add those items in there.

 

It works great on my 9000 and 9000 simulator, but crashes on my 9700. Is this the correct way to have a thread running a player?

Please use plain text.
Developer
peter_strange
Posts: 14,614
Registered: 07-14-2008

Re: Telling my thread what to do

It is pretty much the way that I do it.  When you say crashes, what do you mean?

Please use plain text.
New Developer
brent_glad
Posts: 66
Registered: 11-23-2009

Re: Telling my thread what to do

 

/*
 * myApp.java
 *
 * Confidential and proprietary.
 */

package myApp;

import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;

import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.RichTextField;

import javax.microedition.io.*;
import java.io.*;
import net.rim.device.api.io.SharedInputStream;
import net.rim.device.api.ui.component.Status;
import javax.microedition.media.Player;
import javax.microedition.media.Manager;


class myApp extends UiApplication {
    public static void main(String[] args)
    {
        // Create a new instance of the application.
        myApp theApp = new myApp();

        // To make the application enter the event thread and start processing messages, 
        // we invoke the enterEventDispatcher() method.
        theApp.enterEventDispatcher();
    }

    private myApp()
    {
        // Push the main screen instance onto the UI stack for rendering.
        pushScreen(new myAppScreen());
    }    
}

/**
 * Create a new screen that extends MainScreen, which provides default standard
 * behavior for BlackBerry applications.
 */
/*package*/

class myAppScreen extends MainScreen
{
    private String murl;
    private String currentUrlToPlay;
    private HttpConnection conn;
    private InputStream is;
    private SharedInputStream readAhead;
    private Player _player;
    PlayerThread _playerThread;

    myAppScreen() {
        boolean whereAmI = UiApplication.getUiApplication().isEventThread();
        System.out.println("Am I in the event thread?" + whereAmI);

        _playerThread = new PlayerThread();
        _playerThread.start();
    }
    
    private MenuItem playItem = new MenuItem("Play", 200000, 10) {
    public void run() {
        Status.show("Playing...");
        _playerThread.startPlayer();
    }
    };

    private MenuItem pauseItem = new MenuItem("Pause", 200000, 10) {
    public void run() {
        Status.show("Pausing...");
        _playerThread.stopPlaying();
    }
};

    class PlayerThread extends Thread {

    boolean _stopped = false;
        void startPlayer() {
            UiApplication.getUiApplication().invokeLater(new Runnable() {
                public void run() {
                    Status.show("Connecting...");
                }
            });

            murl = "http://homepage.mac.com/brentris/my_song.mp3;deviceside=true;interface=wifi";
                try
                {
                    conn = (HttpConnection) Connector.open(murl, Connector.READ_WRITE);
                }
                catch (Exception e)
                {
                    murl = "http://homepage.mac.com/brentris/my_song.mp3;deviceside=true";
                    try {
                        conn = (HttpConnection) Connector.open(murl, Connector.READ_WRITE);
                    }
                    catch (Exception f) {
                    }
                }
            if ( conn == null ) {
            return;
            }
                try
                {
                    is = conn.openInputStream();
                    readAhead = SharedInputStream.getSharedInputStream(is);
                    _player = Manager.createPlayer(readAhead, "audio/mpeg");
                    _player.realize();
                    _player.prefetch();
                    _player.start();
                }
                catch (Exception e) {
                    UiApplication.getUiApplication().invokeLater(new Runnable() {
                        public void run() {
                            Status.show("failure.");
                        }
                    });
                }
        }

        void stopPlaying() {
            _stopped = true;
            if ( _player != null ) {
                try {_player.stop();} catch (Exception e) {}
            }
        }

        public void run() {
            startPlayer();
        }
    }

    protected void makeMenu(Menu menu, int instance) {
        menu.add(playItem);
        menu.add(pauseItem);
    }    
}

 

 

The only problem is that sometimes the stream doesn't start playing. I need to put in failsafes here. In the startPlayer function, should I use invokeLater to present a Status.show(""), and then System.exit(0)?

 

It is only failing to connect sometimes. It will be fine if I just have safeguards that prevent it from locking up. I need it to present a message and then close out.

Please use plain text.
Developer
peter_strange
Posts: 14,614
Registered: 07-14-2008

Re: Telling my thread what to do

As I noted initially, there are a number of places that need tidying up, so I would focus on making sure you always close everything (like the connection) and be aware that the connection may fail, even part way through, etc. etc.  I would also separate the processing to get the data completely from the player code, so you can reuse the player code if you have another source of data.  I'm not sure of the best way to tell the user there has been a problem, depends on what you are trying to achieve.  But it seems like you will be able to play with this to get it the way you want anyway.  So good luck.

Please use plain text.