Having trouble with multiple handlers in Android - java

So, I have an activity with a handler.
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
if(LiveAPI.getStatus() == 1){
matches = LiveAPI.getMatches();
listAdapter.notifyDataSetChanged();
}
LivePage.this.mHandler.postDelayed(m_Runnable, 5000);
}
};
Here I get some data and update my list with it. It works.
When I click on an item of my list, this functon is called
private void showLiveMatch(int position) {
Intent i = new Intent(this, LiveMatch.class);
i.putExtra("match", matches.get(position));
startActivity(i);
}
My new activity appears, wich also contains another handler:
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
if(LiveAPI.getStatus() == 1){
match = LiveAPI.getMatch(match.getId());
displayCommentaries();
}
LiveMatch.this.mHandler.postDelayed(m_Runnable, 5000);
}
};
Sometimes this works as I want.
But in some cases it seems like in second activity is still called LiveAPI.getMatches() from the first handler rather than LiveAPI.getMatch(match.getId());
Every function displays a console text, and that's how I figure it out what function is called.
Can someone explain me why?

Once you post either m_Runnable (from LivePage or LiveMatch), it does its stuff and then schedules itself to run in 5 seconds. Basically, each time you start one with a click, it creates an infinite loop. Enough clicks and you will have the logic for each of these running constantly. (That is, unless you have some other code that periodically calls mHandler.removeCallbacks(m_Runnable); that you haven't shown us.) Without knowing more about what you're trying to do, it's hard to recommend how to fix this, but you should somehow avoid creating these kind of infinite loops.
Be aware that all handlers you create on the UI thread simply feed Runnable objects into the (single) MessageQueue for the thread. So there's no such thing as something being called from one handler or another.

Related

How to delay Adding elements to Recyclerview adapter?

I'm trying to create a chat bot. I need to simulate an interactive response from app.The response doesn't come from sever it's embedded inside app.
I'm using recycleview to implement chat UI, I need to delay every message for a specific time so user feels that someone is actually talking to him.
private void displayNewMessage(ArrayList<ChatMessage> messages) {
for (int i = 0; i < messages.size(); i++) {
chatMessages.add(messages.get(i));
}
adapter.notifyDataSetChanged();
}
The previous method is used to push an array of messages to user, how can I delay adding every element to adapter. or push them all to adapter and delay displaying them in adapter it self?
I tried to use Handler but it didn't work, it delays all messages and pushes them all together.
It's a logical question more than programming.
At first why it delays all messages and pushes them all together - because the for loop, it will add them to adapter at once.
An alternative solution is to use handler on some where else suppose on user sending message thread.
assume we have the user sendMessageButton we can make some nice logic there.
We will add message and a time for wait, you can make it Random time, e.g:
sendMessageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
chatMessages.add(newMessage);
adapter.notifyDataSetChanged();
}
},random);
}
});
In your for loop after adding data to arrat put delayedpost on recycler and call notify inside the run method, this will simulate delay for each message, instead of delay and then showing all messages at once
You can use Handler.post delay(new Runnable(),3000);
You put your code under their runnable interface run method it will start with after delay seconds.

Java: Stuck in the while loop in the background thread

I'm using LibGDX AsyncExecutor and the following function is called in a background thread. 'tasksForTheMainThread' is the static array of Runnable, which executes its not yet executed elements during each call of the update function in the main thread. The function 'createBox' of 'modelBuilder' creates and returns an object of the class 'Model'.
Briefly explaining, this code executes in the second thread and sends a piece of code (function 'run()') to be used in the first thread. After it's sent, the second thread is frozen until the moment the code in "run()" is completed and the Model object is created (or at least it's supposed to be like that).
However, it works as expected only when the while loop (which just waits until the object is created in the main thread) contains the logging bit (Gdx.app.log("TAG","2");). When it's empty, the second thread freezes forever and never reaches 'point A' even after the creation of the Model object.
Why and how logging can influence that? And why isn't the programme working without it?
void secondThreadFunction()
{
Model model = null;
ChunkManager.tasksForTheMainThread.add(new Runnable()
{
#Override
public void run()
{
model = modelBuilder.createBox(size.x, size.y, size.z, GL20.GL_LINES,
new Material(ColorAttribute.createDiffuse(Color.YELLOW)),
VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal);
}
});
while (model == null)
{
//Gdx.app.log("TAG","2");
}
//point A
}
You cannot modify a local variable that has been captured to an inner class. Since it has been "captured", you will operate on a copy of the value and it will never be non-null, causing the endless loop. Also note that you are busy-waiting in a tight loop. It might be better to use a Future of some kind.
void secondThreadFunction()
{
AtomicReference<Model> model = new AtomicReference<Model>();
ChunkManager.tasksForTheMainThread.add(new Runnable()
{
#Override
public void run()
{
model.set(modelBuilder.createBox(size.x, size.y, size.z, GL20.GL_LINES,
new Material(ColorAttribute.createDiffuse(Color.YELLOW)),
VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal));
}
});
while (model == null)
{
//Gdx.app.log("TAG","2");
}
//point A
}

What is better for instructions at roughly the same time: multiple Handlers with single Runnable each, or single Handler with multiple Runnables?

So I want several things to go off exactly at once while trying to maintain a light resource load. For example, play sound and updating GUI at the same time. Is it better to have multiple handlers with single runnables or a single handler with multiple runnables running in parallel?
I'm aware that the below implementation won't actually run at the same time and be offset due to instructions in runnable1 potentially being longer than runnable2 thus (runnable1 execution time + 3000) vs (runnable2 time + 6000), etc. But let's just say 3000 and 6000 are substitutes for calculated time to make it run every three seconds (take the difference in milliseconds of next interval [e.g. 00:00:03.000, 00:00:06.000] and the current time).
private Handler handler1 = new Handler();
private Handler handler2 = new Handler();
protected void onStart() {
super.onStart();
Runnable runnableH1 = new Runnable() {
#Override
public void run() {
/* playSound A,B,C, etc every three seconds */
handler1.postDelayed(this, 3000);
}
}
};
Runnable runnableH2 = new Runnable() {
#Override
public void run() {
/* change GUI A,B,C, etc every six seconds */
handler2.postDelayed(this, 6000);
}
}
};
handler1.postDelayed(runnableH1, 0);
handler2.postDelayed(runnableH2, 0);
}
vs
private Handler handler1 = new Handler();
protected void onStart() {
super.onStart();
Runnable runnable1 = new Runnable() {
#Override
public void run() {
/* playSound A,B,C, etc every three seconds */
handler1.postDelayed(this, 3000);
}
}
};
Runnable runnable2 = new Runnable() {
#Override
public void run() {
/* change GUI A,B,C, etc every six seconds */
handler1.postDelayed(this, 6000);
}
}
};
handler1.postDelayed(runnable1, 0);
handler1.postDelayed(runnable2, 0);
}
I'm aware that there are similar questions:
Android: one handler for all runnables?
But the answers say you can only use one handler when from my reading of the Android documentation it sounds like you can implement multiple handlers w/o issue (else the IDE would complain, which it doesn't) to have multiple threads.
It doesn't really matter if in the end all you are doing with the handlers is changing views or any other task that will be added to the main UI, you can have a single handler attached to the main Looper and or several of them, in the end all of your handlers(or your single handler) will be piping messages into a single queue, "the main thread UI queue", so, there's no real advantage from a "parallelism/multithreading" stand point.
Personally I would avoid having several handlers because it would be error prone and chances to get leaks are higher...
On the other hand, if you are not pushing your messages to the main thread and in stead you are just doing some work in parallel, then several threads is the way to go, not necessarily several handlers since you actually don't really need them unless you need to publish something into the main thread.
Hope it helps!
Regards

Adding a repeat function to a simple MIDI player

I am trying to implement a repeat function on a custom MIDI player, but I am unable to implement a repeat function. Here are the classes I am using:
NotePlayer - Plays MIDI notes using Java's MIDI package.
GuitarTunerGUI
Interface to the NotePlayer class.
Provides six JButtons for each guitar string, a JComboBox for selecting the desired tuning, and a JCheckBox for toggling the repeat function.
Provides toggleRepeat() for toggling the repeatEnabled field, a private field of the GuitarTunerGUI class.
I created a SwingWorker that is responsible for playing a MIDI note in a separate thread. This solves the issue of keeping the GUI responsive while the note is being played.
However, a problem arises when repeat is enabled and the user pushes more than one button.
When the user pushes one of the six JButtons the listener does the following:
public void actionPerformed(ActionEvent event) {
// The note param is a private field of the listener object
MusicianWorker clapton = new MusicianWorker(note);
clapton.execute();
}
The execute method does the following:
protected Void doInBackground() throws Exception {
do {
NotePlayer.playNote(thisNote);
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
System.out.println(ex.getMessage());
}
} while (repeatEnabled);
return null;
}
An issue arises when the user pushes multiple buttons without toggling repeat. For example, when the 'A' button and the 'E' button are pushed sequentially, two threads are created and the 'A' and 'E' notes are both played repeatedly until repeatEnabled is toggled off. When the user pushes a JButton I need to first determine if any worker threads are currently executing and, if so kill those threads before playing the specified note. Thanks in advance for your time and feedback.
You need to maintain shared state between your workers. Introduce new boolean variable "playing". Before execution check whether playing flag is set to true, after execution set it to false again.
The code you have given is great, it just needs to be tweaked a little bit. When you create your SwingWorker, you should keep track of it in an instance variable (maybe in a List if you are going to be wanting to play multiple notes at some point?). Then, before playing a new note you check to see if the last note has finished, and if not, you cancel it.
Whether or not cancellation will have any effect on your MusicianWorker is up to you. The worker thread will be interrupted, which would mean that your Thread.sleep method would prematurely terminate if it is running - you would have to check your docs to see what effect it would have on NotePlayer.
Lastly, it seems that you don't actually need to be using the SwingWorker at all, since your background task is not interacting with the UI. You might want to investigate Executors.
You could try something like this:
public class AlbertHall {
private final ExecutorService es = Executors.newSingleThreadExecutor();
// No longer a local variable in the listener
private Future<Void> clapton; // ... or maybe a Collection of Futures
private class Listener implements ActionListener {
private final Note note;
public Listener(Note note) {
this.note = note;
}
public void actionPerformed(ActionEvent event) {
// Watch out, Clapton may finish after you have asked if he is done
// but before you call cancel
if (clapton != null && !clapton.isDone()) clapton.cancel(true);
// You may need to have a wait loop here if Clapton takes a while
// to leave the stage
// Next note
clapton = es.submit(new MusicianWorker(note));
}
}
static class MusicianWorker implements Runnable {
private final Note note;
public MusicianWorker(Note note) {
this.note = note;
}
public void run() {
boolean cancelRequested = false;
do {
NotePlayer.playNote(thisNote);
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
// Looks like we got cancelled
cancelRequested = true;
}
} while (repeatEnabled && !cancelRequested);
}
}
}

ProgressBar countdown with Handlers in an Android application

I first want to say I used google a lot to find a progress bar that fills itself when time passes. All results I found where either with a thread or with an Asynctask. As being new to Android, I thought it was easier to accomplish with an extra Handler that handles the updates of the progressbar.
However, I did not find anyone doing it my way. Does it maybe violate Android rules? For example, can I use multiple Handlers at the same time?
My code looks like:
public void restarttimebar()
{
stoptimebar();
for(int i=1;i<12;i++)
{
Message msg = timebarhandler.obtainMessage(0,i,0);
timebarhandler.sendMessageDelayed(msg, i*250);
}
};
public void stoptimebar()
{
timebarhandler.removeMessages(0);
Message msg = timebarhandler.obtainMessage(0,0,0);
timebarhandler.sendMessage(msg);
};
Handler timebarhandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
ProgressBar progressbar = (ProgressBar)findViewById(R.id.timebar);
if (msg.arg1 == 0)
{
progressbar.setProgress(0);
}
if (msg.arg1 > 0)
{
progressbar.setProgress(msg.arg1*9);
}
}
};
Now one can call restarttimebar(); to (re)start the progress bar. It will fill over 3 seconds with increments at each 0.25 second. Any remarks greatly appreciated!!
EDIT: Also added a stoptimebar(); to just stop the progressbar. Also, the standard size of a progressbar is 100. So I just make the twelve updates times 9. It is almost 100 ;) The bar does not have to be THAT very precise in my application.
As far as i know, the threads you create and Asynctasks (Non-UI-Threads) should not touch UI-stuff like your progressbar. If you need your task communicate with the progressbar, use Asynctask and make sure that UI related actions are done in onPostExecute(). This method will be also called by the main UI Thread.
I guess my method of updating the progress bar can be seen as correct. So for anyone who googles and has the same kind of question: Use the code in the question!

Categories

Resources