I have an activity (not my main activity) that plays some sounds and draw some graphics in a runnable thread. There is an imagebutton with which I'm supposed to suspend and resume the thread. But whatever I try the thread just runs on. I'm totally stuck! Please help.
public class PlayInterval extends Activity {
private Handler customHandler;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_playinterval);
final ImageButton playPauseButton = (ImageButton) findViewById(R.id.playPauseButton);//Play/Pause
playPauseButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
onPlayPauseClicked(playPauseButton,(String)playPauseButton.getTag());
}
});
customHandler = new Handler();
new Thread(new Task()).start();
}
#Override
public void onBackPressed() {
customHandler.removeCallbacksAndMessages(null);
finish();
}
class Task implements Runnable {
#Override
public void run() {
// Do really cool stuff
// and even cooler stuff
customHandler.postDelayed(this, 100);
}
}
private void onPlayPauseClicked(ImageButton playPauseButton, String status) {
if (status == "playing") {
playPauseButton.setTag("paused");
customHandler.removeCallbacksAndMessages(null); //TODO suspend here not working!
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
playPauseButton.setImageResource(getResources().getIdentifier("pause_image", "drawable", getPackageName()));
} else {
playPauseButton.setImageDrawable(getDrawable(getResources().getIdentifier("pause_image", "drawable", getPackageName())));
}
} else {
playPauseButton.setTag("playing");
customHandler.postDelayed(this, 100); //TODO resume here not working!
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
playPauseButton.setImageResource(getResources().getIdentifier("play_image", "drawable", getPackageName()));
} else {
playPauseButton.setImageDrawable(getDrawable(getResources().getIdentifier("play_image", "drawable", getPackageName())));
}
}
}
}
I never did get an answer so after trial and error I came up with this. I've red quite alot here on StackOverflow and what I understand this is NOT the way it is supposed to be done. But it is working very well, so if anyone could explain why one shouldn't use syncronized methods like this and provide a better answer I would be thankful.
Cheers
public class PlayInterval extends Activity {
private Handler customHandler;
Boolean isRunning;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_playinterval);
final ImageButton playPauseButton = (ImageButton)findViewById(R.id.playPauseButton);//Play/Pause
playPauseButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
onPlayPauseClicked(playPauseButton);
}
});
customHandler = new Handler();
isRunning=true;
new Thread(new Task()).start();
}
#Override
public void onBackPressed() {
customHandler.removeCallbacksAndMessages(null);
finish();
}
class Task implements Runnable {
#Override
public void run() {
if (isRunning == true){
// Do really cool stuff
// and even cooler stuff
} else {
// it is paused
}
customHandler.postDelayed(this, 100);
}
private syncronized void onPlayPauseClicked(ImageButton playPauseButton) {
if (isRunning==true) {
isRunning=false;
playPauseButton.setImageResource(getResources().getIdentifier("play_image", "drawable", getPackageName()));
} else {
isRunning=true;
playPauseButton.setImageResource(getResources().getIdentifier("pause_image", "drawable", getPackageName()));
}
}
}
Related
So I made a media Player that works fine but I have one big problem, after pressing play, if I close the activity or app, the music continues to play, if I click again, the music plays on the other one, and I don't know how to fix it. I just want the music to stop after closing the activity or app without any problem.
Here is the full code:
public class m1 extends AppCompatActivity {
ImageView backm1, replay, forward, btPlay, btPause;
TextView playerPosition, playerDuration;
CircularSeekBar seekBar;
MediaPlayer mediaPlayer;
Handler handler = new Handler();
Runnable runnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_m1);
backm1 = (ImageView) findViewById(R.id.backm1);
backm1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
m1.super.onBackPressed();
}
});
playerPosition = findViewById(R.id.playerPosition);
playerDuration = findViewById(R.id.playerDuration);
replay = findViewById(R.id.replay);
forward = findViewById(R.id.forward);
seekBar = findViewById(R.id.seekBar);
btPause = findViewById(R.id.btPause);
btPlay = findViewById(R.id.btPlay);
mediaPlayer = MediaPlayer.create(this,R.raw.ding_dong);
runnable = new Runnable() {
#Override
public void run() {
seekBar.setProgress(mediaPlayer.getCurrentPosition());
handler.postDelayed(this,500);
}
};
int duration = mediaPlayer.getDuration();
String sDuration = convertFormat(duration);
playerDuration.setText(sDuration);
btPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
btPlay.setVisibility(View.GONE);
btPause.setVisibility(View.VISIBLE);
mediaPlayer.start();
seekBar.setMax(mediaPlayer.getDuration());
handler.postDelayed(runnable, 0);
}
});
btPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
btPause.setVisibility(View.GONE);
btPlay.setVisibility(View.VISIBLE);
mediaPlayer.pause();
handler.removeCallbacks(runnable);
}
});
forward.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int currentPosition = mediaPlayer.getCurrentPosition();
int duration = mediaPlayer.getDuration();
if(mediaPlayer.isPlaying() && duration != currentPosition){
currentPosition = currentPosition + 10000;
playerPosition.setText(convertFormat(currentPosition));
mediaPlayer.seekTo(currentPosition);
}
}
});
replay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int currentPosition = mediaPlayer.getCurrentPosition();
if (mediaPlayer.isPlaying() && currentPosition > 10000){
currentPosition = currentPosition - 10000;
playerPosition.setText(convertFormat(currentPosition));
mediaPlayer.seekTo(currentPosition);
}
}
});
seekBar.setOnSeekBarChangeListener(new CircularSeekBar.OnCircularSeekBarChangeListener() {
#Override
public void onProgressChanged(CircularSeekBar circularSeekBar, float v, boolean b) {
if (b) {
mediaPlayer.seekTo((int) v);
}
playerPosition.setText(convertFormat(mediaPlayer.getCurrentPosition()));
}
#Override
public void onStopTrackingTouch(CircularSeekBar circularSeekBar) {
}
#Override
public void onStartTrackingTouch(CircularSeekBar circularSeekBar) {
}
});
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
btPause.setVisibility((View.GONE));
btPlay.setVisibility(View.VISIBLE);
mediaPlayer.seekTo(0);
}
});
}
#SuppressLint("DefaultLocale")
private String convertFormat(int duration) {
return String.format("%02d:%02d"
,TimeUnit.MILLISECONDS.toMinutes(duration)
,TimeUnit.MILLISECONDS.toSeconds(duration) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)));
}
#Override
protected void onDestroy() {
super.onDestroy();
if(mediaPlayer !=null){
mediaPlayer.stop();
mediaPlayer.release();
}
}
}
I added onDestroy but I think in a wrong way and this error came out:
2021-03-08 10:13:40.843 419-4716/? E/AudioSystem: invalid attributes { Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_UNKNOWN Source: -1 Flags: 0x800 Tags: } when converting to stream
2021-03-08 10:13:40.906 28868-28868/com.example.diligent E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.diligent, PID: 28868
java.lang.IllegalStateException
at android.media.MediaPlayer.getCurrentPosition(Native Method)
I added this:
private void stopPlayer() {
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
Toast.makeText(this, "MediaPlayer released", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onStop() {
super.onStop();
stopPlayer();
}
And the following error:
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.media.MediaPlayer.getCurrentPosition()' on a null object reference
Any other suggestions are welcome.
Thank you in advance.
Stop and release media resources on onDestroy of activity.
#Override
protected void onDestroy() {
super.onDestroy();
if(mediaPlayer !=null){
mediaPlayer.stop();
mediaPlayer.release();
}
}
MediaPlayer player; //MediaPlayer object
*Function to stop media Player *
private void stopPlayer() {
if (player != null) {
player.release();
player = null;
Toast.makeText(this, "MediaPlayer released", Toast.LENGTH_SHORT).show();
}
}
Call the function in onStop() callback
#Override
protected void onStop() {
super.onStop();
stopPlayer();
}
This question already has answers here:
Running code in main thread from another thread
(17 answers)
Closed 5 years ago.
I'm trying to dynamically update an android LinearLayout in the main thread.
Unfortunately I'm having a lot of trouble ascertaining anything from the tutorials online. None of them seem to provide a complete picture of how to communicate between threads.
My idea is something like this:
public class MainActivity extends AppCompatActivity {
private LinearLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layout = new LinearLayout(this);
setContentView(layout);
Updater updater = new Updater();
Thread workerThread = new Thread(updater);
//somehow update layout
The updater class would look something like this:
public class Updater implements Runnable {
private int count = 0;
public Updater() {}
#Override
public void run()
{
for (int i = 0; i < 10; i ++){
try {
count++;
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
I know I need a Handler in order to communicate messages between the threads, but I don't know how to set that up.
I would like to avoid anonymous classes, and dynamically create new TextViews whenever Updater has a new message.
create WorkerThreadListener interface:
public interface WorkerThreadListener {
void onUpdate(int counter);
}
Change your Updater class:
public class Updater implements Runnable {
private final WorkerThreadListener mWorkerThreadListener;
private final Handler mHandler;
private int count = 0;
public Updater(final WorkerThreadListener workerThreadListener) {
this.mWorkerThreadListener = workerThreadListener;
this.mHandler = new Handler();
}
#Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
count++;
mHandler.post(new Runnable() {
#Override
public void run() {
mWorkerThreadListener.onUpdate(count);
}
});
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Change MainActivity class:
public class MainActivity extends AppCompatActivity {
private LinearLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layout = new LinearLayout(this);
setContentView(layout);
Updater updater = new Updater(new WorkerThreadListener() {
#Override
public void onUpdate(int counter) {
//update layout here
}
});
Thread workerThread = new Thread(updater);
workerThread.start();
}
}
Hi please check my below answer hope it helps you.
public class ProgressTestActivity extends Activity {
private ProgressBar progress;
private TextView text;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
progress = (ProgressBar) findViewById(R.id.progressBar1);
text = (TextView) findViewById(R.id.textView1);
}
public void startProgress(View view) {
// do something long
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
doFakeWork();
progress.post(new Runnable() {
#Override
public void run() {
// here you can add any view or anyof your logic which is related to UI put it into here.
text.setText("Updating");
progress.setProgress(value);
}
});
}
}
};
new Thread(runnable).start();
}
// Simulating something timeconsuming
private void doFakeWork() {
SystemClock.sleep(5000);e.printStackTrace();
}
}
Other ways are also possible.if you have any doubt please comment below post i will explain you in details.
If you just want to use a tick timer and set progress to ui thread . You can use CountDownTimer.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView textView;
private CountDownTimer countDownTimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new);
textView = (TextView) findViewById(R.id.textView);
findViewById(R.id.b2).setOnClickListener(this);
}
public void processData() {
countDownTimer = new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
textView.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
textView.setText("done!");
}
}.start();
}
#Override
protected void onStop() {
super.onStop();
if (countDownTimer != null) {
countDownTimer.cancel();
}
}
#Override
public void onClick(View v) {
processData();
}
}
Apart from that to post a callback on UI thread you can use Handler .
Handler mainThreadHandler = new Handler(Looper.getMainLooper());
mainThreadHandler.post(new Runnable() {
#Override
public void run() {
}
});
I want to add a button in my application that turns off the music but I don't know how to approach it, I have an idea but I'm sure it's far from best so I want to consult with you. The situation is as follows:
public class MainActivity extends Activity implements OnClickListener {
MediaPlayer easysong;
MediaPlayer normalsong;
MediaPlayer hardsong;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.land_main);
mContext = this;
restartButton = (Button)findViewById(R.id.restartButton);
restartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
easysong = MediaPlayer.create(MainActivity.this, R.raw.arideniro);
normalsong = MediaPlayer.create(MainActivity.this, R.raw.junior);
hardsong = MediaPlayer.create(MainActivity.this, R.raw.ketsathis);
counter = 101;
i = 500 - dif;
new Thread(new Runnable() {
public void run() {
if(i==500){
easysong.start();}
else if(i==375){
normalsong.start();
}else if(i==250){
hardsong.start();
}
while (counter > 0) {
try {
Thread.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter--;
runOnUiThread(new Runnable() {
#Override
public void run() {
scoreText.setText(Integer.toString(counter));
}
});
if(i>150){
i/=1.01;}
else if(i>90-(dif/10)){
i-=1;
}
}if (counter==0) {
mChronometer.stop();
if(easysong.isPlaying()) {
easysong.stop();
easysong.release();
easysong = null;
}else if(normalsong.isPlaying()){
normalsong.stop();
normalsong.release();
normalsong = null;
}else if(hardsong.isPlaying()){
hardsong.stop();
hardsong.release();
hardsong = null;
}
This is the main class of my app where the mediaplayer is used, now I deleted much of the code because it was irrelevant to the mediaplayer and the question, so don't look for the missing brackets and such. And this here is the main menu class where the Switch that will turn on and off the music will be located:
public class MainMenu extends Activity{
private Button easy;
private Button normal;
private Button hard;
private Button scores;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_menu);
easy = (Button) findViewById(R.id.btn_easy);
scores = (Button) findViewById(R.id.btn_highscores);
easy.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dif = 0;
startGame();
}
});
}
public void startGame() {
Intent intent = new Intent(MainMenu.this, MainActivity.class);
startActivity(intent);
}
So my idea is simnple, to add a variable in MainActivity like "int p;" and from the MainMenu class to change it's state between 0 and 1, then I will add around each line that starts music an if(p==1) but is this a good approach ? Also I would like the value of the int to be saved when the app is closed
I was creating a splash screen in android using Thread.sleep(). (I know the another method - using handler, but I have to use this method for now.)
My code is as follows:
public class SplashScreen extends Activity {
Thread t;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_spash_screen);
new myclass();
}
class myclass implements Runnable{
myclass()
{
t = new Thread();
t.start();
}
public void run()
{
try{
Thread.sleep(1000);
Intent i = new Intent(getApplicationContext(), MainActivity.class);
startActivity(i);
finish();
}
catch(InterruptedException e){
System.out.println("thread interrupted");
}
}
}
}
It does not show any error, but splash screen stuck to the screen.
After 1s, it did not start another intent.
If you know the mistake then please help me.
run method of runnable is not called because you are not passing runnable to Thread constructor. so pass it as:
t = new Thread(this);
Try this,I always use this code in my Splash Activities.
public class SplashScreen extends Activity
{
private Thread mSplashThread;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen);
mSplashThread = new Thread()
{
#Override
public void run()
{
try
{
synchronized (this)
{
wait(2000);
}
}
catch(InterruptedException ex) {
ex.printStackTrace();
}
finish();
startActivity(new Intent(getApplicationContext(),MainActivity.class));
}
};
mSplashThread.start();
}
#Override
public boolean onTouchEvent(MotionEvent evt)
{
if (evt.getAction() == MotionEvent.ACTION_DOWN)
{
synchronized (mSplashThread)
{
mSplashThread.notifyAll();
}
}
return true;
}
}
I am creating a sound board and after clicking about 30 different sounds it stops working; I believe android is running out of memory. Below is my code. How can I implement .release() so that when the sound is done playing it is released? I don't really care if two things play at the same time; the clips are t0o short for this to be possible. I would just like to get my code set.
public class soundPageOne extends Activity {
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.soundsone);
final MediaPlayer pg1 = MediaPlayer.create(this, R.raw.peter1);
Button playSound1 = (Button) this.findViewById(R.id.peter1Button);
playSound1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pg1.start();
}
});
I have done a lot of searching around but due to my lack of java/android knowledge I have not been able to get anything to work. Thanks in advance, let me know if anyone needs anymore code.
I left a comment, but I'll post an answer to show what I mean anyway...
The idea is that you have a set number of MediaPlayer instances that you can use. That way you never exceed the maximum number of instances. The array should be the length of the number of concurrent sounds you expect to be able to hear. If the sounds are local files, the length of time it takes to prepare the sounds should be almost negligible, so calling create inside the click handler should not result in terrible performance. Each of your buttons is associated with a particular resource, I suppose, so I set up a helper method to create and play the sounds for each button in the same way.
public class soundPageOne extends Activity {
private MediaPlayer[] mPlayers = new MediaPlayer[2];
private int mNextPlayer = 0;
#Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.soundsone);
Button playSound1 = (Button)this.findViewById(R.id.peter1Button);
playSound1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startSound(R.raw.peter1);
}
});
}
public void onDestroy() {
super.onDestroy(); // <---------------------- This needed to be there
for (int i = 0; i < mPlayers.length; ++i)
if (mPlayers[i] != null)
try {
mPlayers[i].release();
mPlayers[i] = null;
}
catch (Exception ex) {
// handle...
}
}
private void startSound(int id) {
try {
if (mPlayers[mNextPlayer] != null) {
mPlayers[mNextPlayer].release();
mPlayers[mNextPlayer] = null;
}
mPlayers[mNextPlayer] = MediaPlayer.create(this, id);
mPlayers[mNextPlayer].start();
}
catch (Exception ex) {
// handle
}
finally {
++mNextPlayer;
mNextPlayer %= mPlayers.length;
}
}
}
Create a class, say AudioPlayer with a SoundPool variable. Setup a constructor to initialise the AudioPlayer object and create a Play method. SoundPool works better for short sounds played many times and does not require you to release.
public class AudioPlayer {
private SoundPool sPool = new SoundPool(Integer.MAX_VALUE, AudioManager.STREAM_MUSIC, 0);
public AudioPlayer(Context c, int id){
sounds.put("1",sPool.load(c, id, 1));
}
public void play(Context c) {
sPool.play("1", 1, 1, 1, 0, 1f);
}
}
So your class should look like
public class soundPageOne extends Activity {
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.soundsone);
final AudioPlayer ap = new AudioPlayer(this, R.raw.sound);
Button playSound1 = (Button) this.findViewById(R.id.peter1Button);
playSound1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ap.play();
}
});
Could you use a MediaPlayer.OnCompletionListener?
Something like:
public class soundPageOne extends Activity implements MediaPlayer.OnCompletionListener {
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.soundsone);
final MediaPlayer pg1 = MediaPlayer.create(this, R.raw.peter1);
//***set the listener here***
pg1.setOnCompletionListener(this);
Button playSound1 = (Button) this.findViewById(R.id.peter1Button);
playSound1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pg1.start();
}
});
}
//***this code will be executed once the sound finishes playing***
#Override
public void onCompletion(MediaPlayer mp) {
//log messages, other things can go here
mp.release();
}
Try something like this
Your activity class:
public class soundPageOne extends Activity {
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.soundsone);
final AudioPlayer pg1 = new AudioPlayer();
Button playSound1 = (Button) this.findViewById(R.id.peter1Button);
playSound1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pg1.play(this, R.raw.sound);
}
});
}
This is another Java Class:
public class AudioPlayer {
private MediaPlayer mPlayer;
public void stop() {
if (mPlayer != null) {
mPlayer.release();
mPlayer = null;
}
}
public void play(Context c, int sound) {
stop();
mPlayer = MediaPlayer.create(c, sound);
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
stop();
}
});
mPlayer.start();
}
public boolean isPlaying() {
return mPlayer != null;
}
}