Wielowątkowość - Czy dobrze ją pojmuję?

0

Witam,

Otóż, posiadam problem z wywołaniem danej funkcji (wątku). Otóż nie jestem pewny czy to jest osobny wątek czy też coś robię źle. To tak, mam sobie dwie klasy, jedna to jest Timer która tworzy nowy obiekt nowej klasy przy inicjalizacji timera - tą klasą jest klasa odgrywająca dźwięki - oczywiście dziedziczy po Thread. I teraz jak utworzę sobie w tej klasie metodę która ma jeden parametr (np i) to czy to będzie działać w osobnym wątku ta metoda? To i jest potrzebne do ustalenia który rodzaj dźwięku ma być odegrany jeżeli jest np równe zero to "tik" a jeżeli równe jeden to "tok".

W Timerze wygląda to tak:

 
    public void run() {
        playThisSound.run(i);
        ++i;
        if(i==metrum)
            i=0;
    }

Natomiast w klasie która dziedziczy po thread i odhrywa dźwięki tak:

 
    
    public void run(int i) {
        try {
            if(i==0) {
                playTock.start();
            }
            else {
                playTick.start();
            }
        }catch(Exception ex) {}
    }
0

Cześć.
Podeślij kod całych klas.

Na pierwszy rzut oka, to jest mały błąd:

Klasa do odtwarzania muzyki nie może mieć metody run(int).
Gdyż takiej metody nie ma w Thread i nie będzie ona wywoływana wewnątrz wątku.

Rozwiązaniem powinno być utworzenie nowego obiektu Playera - przekazanie mu przez konstruktor, lub settera wartości i.
Następnie wywołanie metody start() z klasy bazowej Thread.

np.:

 public class MyThread implements Runnable{

     private int i;
     
     public MyThread(int i){
        this.i = i;
      }

     public void run(){
        funckaj(i);
     }
} 

A w kodzie wywołującym:


MyThread thread = new MyThread(12);
Thread starter = new Thread(thread);
starter.start();
 
0

Z tym tworzeniem run(int) było tak jak się obawiałem - przebudowałem trochę kod - niestety nie wykorzystałem Twojej propozycji - jednak trochę inną, bo odtwarzanie dźwięku jest cykliczne i występuje w odstępach mniej niż 1 sekunda, więc ciągłe tworzenie nowego obiektu bardzo spowalniałoby działanie aplikacji - zobaczę jak z wydajnością jest na telefonie - jeśli wszystko będzie równo to problem został rozwiązany.

Niestety - to nie do końca działa wygląda na to że wątek wykonywany jest raz. Oto kod timera i klasy grającej:

Timer:

import java.util.TimerTask;

/**
 * @author Damian
 */
public class MetronomeTimerEvent extends TimerTask{        
    
    public MetronomeTimerEvent(byte metr) {
        i = 0;
        metrum = metr;
        playThis = new PlayTik();
        playThisStart = new Thread(playThis);
    }

    public void run() {
        playThisStart.start();
        i++;
        if(i==metrum)
            i=0;
    }
    
    private byte i;
    private PlayTik playThis;
    private Thread playThisStart;
    public byte metrum;
}

 

PlayTik

import javax.microedition.media.control.*;
import javax.microedition.media.*;

/**
 * @author Damian
 */
public class PlayTik implements Runnable {
    
    public PlayTik() {
        try {
            playTick = Manager.createPlayer(getClass().getResourceAsStream("/1.wav"), "audio/x-wav");
            playTick.realize();
            playTick.prefetch();
        } catch(Exception ex) { }
        VolumeControl volumeV = (VolumeControl)playTick.getControl("VolumeControl");
        volumeV.setLevel(99);
        try {
            playTock = Manager.createPlayer(getClass().getResourceAsStream("/2.wav"), "audio/x-wav");
            playTock.realize();
            playTock.prefetch();
        } catch(Exception ex) { }
        VolumeControl volumeV1 = (VolumeControl)playTock.getControl("VolumeControl");
        volumeV1.setLevel(99);
    }
    
    public void run() {
            try {
                if(i==0) {
                    playTock.start();
                }
                else {
                    playTick.start();
                }
            }catch(Exception ex) {}
    }
    
    public void changeVariableI(byte changedVariable) {
        i = changedVariable;
    }
    
    public byte i;
    private Player playTick;
    private Player playTock;
}

 
0

Cześć.
Pomoże Ci klasa java.util.Timer i jej metoda schedule(TimerTask task, Date firstTime, long period)

W ten sposób ustawisz co ile ma się wykonywać TimerTask.

0

Dam pozostałe klasy dla pewności, bo właśnie to co podałem - to jest klasa z timerem wystartowanym który działa z częstotliwością obliczoną na podstawie podanej ilości bpm przez użytkownika.

Klasa główna:

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

/**
 * @author Damian
 */
public class Main extends MIDlet implements CommandListener {
    
    public Main() {
        design = new InterfaceDesign();
        Command exit = new Command("Koniec", Command.EXIT, 0);
        design.addCommand(exit);
        startButton = new Command("Start/Stop", Command.OK, 0);
        design.addCommand(startButton);
        design.setCommandListener(this);
        Display mobileDisplay = Display.getDisplay(this);
        mobileDisplay.setCurrent(design);
        
    }

    public void startApp() {
    }
    
    public void pauseApp() {
    }
    
    public void destroyApp(boolean unconditional) {
    }
    
    public void commandAction(Command c, Displayable s) {
        if(c.getCommandType() == Command.EXIT)
            notifyDestroyed();
        
        if(c.getCommandType() == Command.OK) {
            design.changeState();
        }
    }
    
    private InterfaceDesign design;
    private Command startButton;
}

 

Klasa w której startuje timer, rysuje gui i takie tam.

import javax.microedition.lcdui.*;
import java.util.Timer;

/**
 * @author Damian
 */
public class InterfaceDesign extends Canvas implements CommandListener {

    /**
     * constructor
     */
    public InterfaceDesign() {
        metronomState = "Start";
        isWorking = Boolean.FALSE;
        bpmString = "90";
        howManyBpm = 90;
        calculateInterval = 60000/(howManyBpm);
        timer = new Timer();
        metrum = 3;
        metrumString = "3";
        try {
            // Set up this canvas to listen to command events
            setCommandListener(this);
            // Add the Exit command
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * paint
     */
    public void paint(Graphics g) {
        Font f1 = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE);  
        Font f2 = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM);  
        Font f3 = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
        g.setColor(255, 255, 255);
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(0, 0, 0);
        g.drawString(metronomState, getWidth()/2, getHeight()/2, Graphics.TOP | Graphics.LEFT);
        g.drawString("BPM: " + bpmString, getWidth()/2, (getHeight()/2)-20, Graphics.TOP | Graphics.LEFT);
        g.drawString("Metrum: " + metrumString, getWidth()/2, (getHeight()/2)-40, Graphics.TOP | Graphics.LEFT);
        g.drawString("Metronom v3.0\nDamian Smilgin(C)", 0, 0, Graphics.TOP | Graphics.LEFT);
    }

    /**
     * Called when a key is pressed.
     */
    protected void keyPressed(int keyCode) {
        if(keyCode == -5) {
            changeState();
            repaint();
        }
        else if(keyCode == -1 && isWorking == Boolean.FALSE) {
            howManyBpm++;
            bpmString = Integer.toString(howManyBpm);
            repaint();
        }
        else if(keyCode == -2 && isWorking == Boolean.FALSE) {
            howManyBpm--;
            bpmString = Integer.toString(howManyBpm);
            repaint();
        }
        else if((keyCode == -4) && (isWorking == Boolean.FALSE)) {
            metrum++;
            metrumString = Integer.toString(metrum);
            repaint();
        }
        else if((keyCode == -3) && (isWorking == Boolean.FALSE) && (metrum > 2)) {
            metrum--;
            metrumString = Integer.toString(metrum);
            repaint();
        }
    }
    
    public void changeState() {
        if(isWorking == Boolean.FALSE) {
            isWorking = Boolean.TRUE;
            metronomState = "Stop";
            startMetronome();
        }
        else if(isWorking == Boolean.TRUE) {
            isWorking = Boolean.FALSE;
            metronomState = "Start";
            stopMetronome();
        }
        repaint();
    }
    
    protected void startMetronome() {
        calculateInterval = 60000/(howManyBpm);
        startTimerEvents = new MetronomeTimerEvent(metrum);
        timer.schedule(startTimerEvents, 1000, calculateInterval);
        
    }
    
    protected void stopMetronome() {
        startTimerEvents.cancel();
    }

    /**
     * Called when a key is released.
     */
    protected void keyReleased(int keyCode) {
    }

    /**
     * Called when a key is repeated (held down).
     */
    protected void keyRepeated(int keyCode) {
    }

    /**
     * Called when the pointer is dragged.
     */
    protected void pointerDragged(int x, int y) {
    }

    /**
     * Called when the pointer is pressed.
     */
    protected void pointerPressed(int x, int y) {
    }

    /**
     * Called when the pointer is released.
     */
    protected void pointerReleased(int x, int y) {
    }

    /**
     * Called when action should be handled
     */
    public void commandAction(Command command, Displayable displayable) {
    }
    
    private String metronomState;
    public Boolean isWorking;
    private int howManyBpm;
    private String bpmString;
    private int calculateInterval;
    private Timer timer;
    private MetronomeTimerEvent startTimerEvents;
    public byte metrum;
    public String metrumString;
}

 

Więc nie bardzo wiem jak dodać ten drugi timer w istniejącym już timerTask i jeszcze by działał cyklicznie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1