I'm writing an application that is creating audio players dynamically. By pressing a button, I want all handlers to stop and start again when I call them. The handlers, basically, are responsible for updating the seek-bar of the audio player. the seek-bar and the play button are being creating into a linearlayout, and this linear layout is being adding into a parent linearlayout. this way, for example, if I decide by code to create 4 audio players and I want them to be able to play the audio together, I put in a loop the creation of a 4 linearlayouts and add them to the parent linearlayout. the code more or less looks like this (this is just the relevant part, not the real code...):
for (int i = 0; i < 4; i++)
{
LinearLayout audioLayout = new LinearLayout(this);
audioLayout.setOrientation(LinearLayout.HORIZONTAL);
audioLayout.setPadding(20, 20, 20, 20);
final Button btnAudioPlay = new Button(this);
btnAudioPlay.setBackgroundResource(R.drawable.play);
LinearLayout.LayoutParams playButtonParams = new LinearLayout.LayoutParams(50, 50);
playButtonParams.setMargins(20, 0, 20, 0);
audioLayout.addView(btnAudioPlay, playButtonParams);
final SeekBar sbAudioPosition = new SeekBar(this);
LinearLayout.LayoutParams seekbarParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
seekbarParams.setMargins(20, 0, 20, 0);
audioLayout.addView(sbAudioPosition, seekbarParams);
parentLayout.addView(audioLayout);
final MediaPlayer mpAudio = MediaPlayer.create(this, Uri.fromFile(audFile));
mpAudio.setLooping(false);
mpAudio.seekTo(0);
int totalTime = mpAudio.getDuration();
sbAudioPosition.setMax(totalTime);
sbAudioPosition.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
if (fromUser)
{
mpAudio.seekTo(progress);
sbAudioPosition.setProgress(progress);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
mpAudio.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
btnAudioPlay.setBackgroundResource(R.drawable.play);
sbAudioPosition.setProgress(0);
}
});
btnAudioPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!mpAudio.isPlaying()) {
mpAudio.start();
btnAudioPlay.setBackgroundResource(R.drawable.pause);
final Handler handler = new Handler();
runOnUiThread(new Runnable() {
#Override
public void run() {
sbAudioPosition.setMax((int) mpAudio.getDuration());
int currentPossition = mpAudio.getCurrentPosition();
sbAudioPosition.setProgress(currentPossition);
handler.postDelayed(this, 0);
}
});
}
else {
mpAudio.pause();
btnAudioPlay.setBackgroundResource(R.drawable.play);
}
}
});
}
When I press a button, I'm updating the view, and I want all handlers to stop, but it doesn't happening... I tried to declare, before the onCreate the Handler handler = null; (instead of the final handler) and then in the linearlayout make it new and it worked, but in the method of the button I called handler.removeCallbacksAndMessages(null); and it didn't work. I tried to declare the runable as well and call handler.removeCallbacks(runOnUiThread);, but my application crashes... :(
What do I need to do to solve it?
If I want that one audio play will stop the current audio playing, is it possible? will it solve my problem?
Sorry for the length and thanks for the helpers. :)
You can use the Handler as a member of your Activity something like:
private Handler mHandler = new Handler();
private Runnable mRunnable = new Runnable() {
#Override
public void run() {
sbAudioPosition.setMax((int) mpAudio.getDuration());
int currentPossition = mpAudio.getCurrentPosition();
sbAudioPosition.setProgress(currentPossition);
mHandler.post(this);
}
};
Then use the mHandler when you make execute mHandler.postDelayed(runnable,delay). And then you can call mHandler.removeCallbacks(null); when you want to remove them all.
Note: You can remove specific runnables like this: mHandler.removeCallbacks(mRunnable);
Related
Is it possible to generate a TextView inside a for loop in the main activity? I have to run a thread from another Java class "multithread." When this class runs, I will know how many clients connected to, I will run the insider thread to generate TextViews according to the number of the clients, and display the received messages in these TextViews.
But I am obtaining an error. If you know any better way to run a thread inside the main activity, please let me know, thanks.
Here is the method:
public void toggleButtonConnectToClientsFunction(View view) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//Multithread here
multicastthreadRun.run();
for(int counter=0;counter<multicastthreadRun.ClientIpArrayList.size();counter++) {
TextView textView=new TextView(this);//i am obtaining error here
linearLayoutSecondaryTexts.addView(textView);
runOnUiThread(new Runnable() {
#Override
public void run() {
//in this case we can change the user interface
}
});
}//end of the for loop
}
});t.start();
new Runnable is an anonymous class and this is pointing to that anonymous class. To create a textview, you need to pass context (either activity or context) so in order to do that, use specific reference to class with className as
TextView textView=new TextView(YourContainerActivityClassName.this);
// e.g TextView textView=new TextView(MainActivity.this);
Note: since it's a click listener so seems like this is in an activity directly
and you cannot update the UI from worker threads so do it like
public void toggleButtonConnectToClientsFunction(View view) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//Multithread here
multicastthreadRun.run();
for(int counter=0;counter<multicastthreadRun.ClientIpArrayList.size();counter++) {
// use proper context
TextView textView=new TextView(YourActivityNamethis);//i am obtaining error here
runOnUiThread(new Runnable() {
#Override
public void run() {
// Update UI
linearLayoutSecondaryTexts.addView(textView);
}
});
}//end of the for loop
}
});t.start();
}
TextView textView = new TextView(this);//i am obtaining error here
TextView textView = new TextView(getBaseContext());// textview expect context object NOT runnable object.
And instead of using loop you can just use Recursion.
public void toggleButtonConnectToClientsFunction(View view) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//Multithread here
multicastthreadRun.run();
makeTextView ( 0,multicastthreadRun.ClientIpArrayList.size());
}
});
t.start();
}
private void makeTextView(final int count, final int max){
if (count>= max)
return; // end of Loop
TextView textView = new TextView(getBaseContext());// Use can you this here as it will refer to your activity object.
runOnUiThread(new Runnable() {
#Override
public void run() {
//in this case we can change the user interface
linearLayoutSecondaryTexts.addView(textView);
makeTextView(count+1, max);
}
});
}
In your code TextView(this) will not work because it is inside on Thread.
You have to specify the context exactly. Check below code:
TextView tv = new TextView(YOUR_ACTIVITY.this);
tv.setText("What to do");
Thanks :)
I have developed an app in which I have a textview whose text keeps scrolling automatically. I also have an imageview whose image keeps changing automatically after every four seconds. To accomplish this I have created a new runnable having 4 seconds time. Suppose there are 5 images which gets displayed. The problem is every time a new image is loaded in imageview the text of textview gets reset and it starts scrolling from beginning and this happens only for the first iteration of all the images. After all images are displayed once then from the next iteration onwards the textview starts behaving properly and the text doesn't resets. I don't know what is the problem. Here is the code
//In onCreate
headlinesText = (TextView) findViewById(R.id.text_news);
headlinesText.setSelected(true);
//This is a separate method
public void settingAds() {
myRef.child("Advertisements").addValueEventListener(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
imageUrl.clear();
for (com.google.firebase.database.DataSnapshot eachAdUrl : dataSnapshot.child("Adurls").getChildren()) {
imageUrl.add(String.valueOf(eachAdUrl.getValue()));
}
headlineFromFirebase = String.valueOf(dataSnapshot.child("News").getValue());
adTimer = (long) dataSnapshot.child("Time").getValue();
headlinesText.setText(headlineFromFirebase);
/*headlinesText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, NewsList.class));
}
});*/
//Randomly shuffling the array list
Collections.shuffle(imageUrl);
for(int i=0;i<imageUrl.size();i++) {
Picasso.with(MainActivity.this)
.load(imageUrl.get(i))
.fetch();
}
//runnable code was here
if(handler != null) {
handler.removeCallbacks(runnable);
}
handler = new Handler();
runnable = new Runnable() {
int imageCounter=0;
public void run() {
Picasso.with(MainActivity.this)
.load(imageUrl.get(imageCounter))
.fit()
.centerCrop()
.into(mAdsView);
imageCounter++;
if (imageCounter > imageUrl.size()-1) {
imageCounter = 0;
}
handler.postDelayed(this,adTimer);
}
};
handler.postDelayed(runnable, 250);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I have a button in xml. On button press I wish to rapidly change the background and Text on that button.
I normally would use a code like this for the final result:
String rndm[] = {"A","B","C","D"};
{rnd = rndm[(int) (Math.random() * rndm.length)];}
{Button btn = (Button) findViewById(R.id.button1);
btn.setText(String.valueOf(rnd));
btn.setTextColor(Color.parseColor("#000000"));}
Before that is called though I would like perhaps a second or two of a "shuffling" effect.
I have tried using java.util.timer like this:
#Override
public void onClick(View v) {
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
String rndm[] = {"A","B","C","D"};
{rnd = rndm[(int) (Math.random() * rndm.length)];}
{Button btn = (Button) findViewById(R.id.button1);
btn.setText(String.valueOf(rnd));
btn.setTextColor(Color.parseColor("#000000"));}
}}}, 100 );
Then making a few of these with different backgrounds to fire one after the other. I just can't seem to get the hang of it.
I may need a whole new method to do what I want to do, but I am not sure what the best wat to accomplish what I need is.
You should use Handler and make sure that the code that you want to run is in the runnable method :-)
Try something like this from your Activity
Handler handler = new Handler();
....
#Override
public void onClick(View v) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
// set your button color here, no need to use runOnUiThread()
// as this run() method is executed on Main thread
}
}, 100);
}
I have tried so many ways of solving my problem, but still no success.I have a method, which returns me a string value and I am using it to update TextView on my screen like this:
outCPU.setText(getCpuInfo());
Which would be fine, but I need to update this TextView until back button was pressed.
I guess i have need a while loop which starts after activity has been created and stops after back button was pressed. This loop should be in a new thread, because:- I have to load the activity first and execute the loop in another thread so the executing won't affect main thread and loading of the activity.
As I've already said, I don't know how to do this properly even though i have spent few hours on it.
Could someone show me an example how to get this done? Thanks...!!
EDITED - WORKING:
private Handler mHandler;
private int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_systeminfo);
outCPU = (TextView) findViewById(R.id.outCPU);
outMEM = (TextView) findViewById(R.id.outMEM);
outTASKS = (TextView) findViewById(R.id.outTASKS);
i = 0;
mHandler = new Handler();
mHandler.post(mUpdate);
}
private Runnable mUpdate = new Runnable() {
#Override
public void run() {
outCPU.setText(getCpuInfo());
outMEM.setText(getMemInfo());
outTASKS.setText(getTasksInfo());
i++;
mHandler.postDelayed(this, 1000);
}
};
#Override
public void onBackPressed() {
mHandler.removeCallbacks(mUpdate);
super.onBackPressed();
Log.i("MSG", "Going back");
finish();
}
You can use AsyncTask to perform operations on UI Thread while being in a Thread. Or you can use 'my favorite' , the combination of Thread and Handler. To make sure the thread is stopped when back is pressed, you can use handler.removeCallBacks(Runnable) The following example could solve your problem:
//Global
Handler h = new Handler();
private static boolean flag = true;
public void updateTextView(){
// call thread here
h.post(thread);
}
// take this thread out side so that it can be stopped with handler
Thread thread = new Thread(){
public void run(){
while(flag)
outCPU.setText(getCpuInfo());
}
}
public void onBackPressed(){
flag = false;
h.removeCallBacks(thread);
super.onBackPressed();
}
Use a shared flag somewhere in your app:
private volatile boolean wasPressed = false;
In while loop, check this flag:
while (!wasPressed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
outCPU.setText(getCpuInfo());
}
});
// sleep for a while
}
On button click listener, switch wasPressed to true.
I am creating an android application and have run into a problem.
There is 12 buttons. A button is to change color and then the user has one second to click the button, otherwise the button changes back to the original color and a different button changes color.
I would like to repeat this until the user misses a certain amount of button clicks.
I have discovered how to do the changing in colors, however I am not sure how to do an infinite loop in android or how to wait for one second.
Thanks for your help. This is my first attempt at an android application.
You can implement a timer by posting a Runnable object to run on a Handler with a specified delay. If you don't stop it from running, then the Runnable executes. However, you can also stop it from running before that:
private static final long ONE_SECOND = 1000L;
private static final int MISS_LIMIT = 10;
int misses = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
final Handler handler = new Handler();
final Runnable timer = new Runnable() {
#Override
public void run() {
// user too late: increment miss counter
if (++misses >= MISS_LIMIT) {
//TODO miss limit reached
finish(); // close this activity
}
}
};
final View btn1 = findViewById(R.id.button1);
final View btn2 = findViewById(R.id.button2);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// change color of other button, and start timer
btn2.setBackgroundResource(R.color.new_color);
handler.removeCallbacks(timer);
handler.postDelayed(timer, ONE_SECOND);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// user clicked button in time: restore color and stop timer
btn2.setBackgroundResource(R.color.orig_color);
handler.removeCallbacks(timer);
}
});
}
Firstly create a method something like this to change the color of button..
public void changeButton(int i){
switch (i) {
case 0:
button0.setClickable(true);
button0.setBackgroundResource(color1);
break;
case 1:
button0.setClickable(false);
button0.setBackgroundResource(color2);
button1.setClickable(true);
button1.setBackgroundResource(color1);
break;
case 2:
button1.setClickable(false);
button1.setBackgroundResource(color2);
button2.setClickable(true);
button2.setBackgroundResource(color1);
break;
.....
case 11:
button10.setClickable(false);
button10.setBackgroundResource(color2);
button11.setClickable(true);
button11.setBackgroundResource(color1);
break;
default:
break;
}
}
then you can implement a Runnable with some delay to call that method in loop like this..
Handler handler=new Handler();
int j=0;
final Runnable r = new Runnable()
{
public void run()
{
changeButton(j);
j++;
// next button color change
if(j<12){
handler.postDelayed(this, 1000);
}
else{
j=0;
handler.postDelayed(this, 1000);
}
}
};
handler.post(r)