use SurfaceView addCallback() in another method instead of using in onCreate() - java

I want to get paths for videos from server and then play them using a surfaceView.
I can do it if I use another activity class to play videos after received paths. But I am trying to play in the same activity.
I am getting paths in the background using an AsyncTask. This AsyncTask is executed in onCreate() method. After got paths in onPostExecute(), I want to play videos in SurfaceView.
But SurfaceView is created before I receive those paths. So I tried to use SurfaceView's addCallback() in onPostExecute(). But it looks not possible.
How I do this? Using SurfaceView, is there no way to play videos on the same activity after got resource paths from server?

Oh yeah, I found a solution. I will post it here so that it will help to someone like me. Because everywhere I check a solution for this, didn't followed this way.
Your activity class:
public class PlayActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceHolder sh;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//getResource is your AsyncTask
//I will not post it here because it is not the problem we had
getResource _gR = new attemptGetStream(p1, p2);
_gR.execute();
//initiate components
SurfaceView sV = (SurfaceView) findViewById(R.id.main);
assert null != sV : "Surface is null";
sV.getHolder().addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder sHolder) {
//this is the solution.
//only assign holder to a variable but don’t initiate MediaPlayer here
//because we don’t have resource paths yet
//we will initiate MediaPlayer in postExecute method and
//attach to this holder from there
sh = sHolder;
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
log("Surface changed");
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
log("Surface destroyed");
}
//this is our method called from onPostExecute() in our getResource AsyncTask
public void play(String path){
//here initiate the MediaPlayer and assign dataSource
//attach the player to sh(which is our surface holder
try{
MediaPlayer mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDisplay(sh);//sh is the surface holder
mMediaPlayer.setDataSource(getApplicationContext(), path);//path is what we got from onPostExecute method in AsyncTask
mMediaPlayer.prepareAsync();//i use prepareAsync method here so it will not hog the phone
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mP.start();
}
});
}catch (Exception e){//use exception types as you like
e.printStackTrace();
}
}
}

Related

How to prepare sound after reset MediaPlayer?

I'm trying to make app like soundboard. Now I have small problem with playing the same sound after reset after playing 1st time.
final MediaPlayer SoundOne = MediaPlayer.create(this, R.raw.somesound);
final Button play_SoundOne = (Button) this.findViewById(R.id.play_SoundOne);
play_SoundOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SoundOne.start();
}
});
SoundOne.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
SoundOne.reset();
}
});
Can I get help how can I prepare that sound to play again after reset (I do reset to make space in memory for next sounds) but SoundOne.prepare() doesn't work if I put that before .start(). Any advice?
Based on the documentation:
It is a programming error to invoke methods such as getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioAttributes(AudioAttributes), setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(long, int), prepare() or prepareAsync() in the Idle state for both cases. If any of these methods is called right after a MediaPlayer object is constructed, the user supplied callback method OnErrorListener.onError() won't be called by the internal player engine and the object state remains unchanged; but if these methods are called right after reset(), the user supplied callback method OnErrorListener.onError() will be invoked by the internal player engine and the object will be transfered to the Error state.
You cannot immediately start() or prepare after reset(). Based on the documentation for reset:
Resets the MediaPlayer to its uninitialized state. After calling this method, you will have to initialize it again by setting the data source and calling prepare().
The solution would be
Initialize the MediaPlayer again -> set the Data Source -> call prepare.
Alternatively you can avoid performing reset onCompletion. Instead, release the MediaPlayer onStop()
You can update your as follows:
MediaPlayer soundOne = null;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
....
play_SoundOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
soundOne.start();
}
});
}
#Override
protected void onStart() {
super.onStart();
if(soundOne == null){
soundOne = MediaPlayer.create(this, R.raw.somesound);
soundOne.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
//Don't reset
}
});
}
}
#Override
protected void onStop() {
super.onStop();
soundOne.release();
soundOne = null;
}

My android App stop playing sound on button tap after some time

Hello there, i have just created a basic android app which plays different musics on button tap..
The app just worked fine for the first couple of seconds but when i just keep on tapping and tapping , at some point it stops playing the music and just crashed...
I am unable to figure out what the problem is ..Please help me make it work..
Thanks.
Here is my code :-
public class MainActivity extends AppCompatActivity {
MediaPlayer mediaPlayer;
public void PlayMusic(View view)
{
int ID = view.getId();
String NameID = view.getResources().getResourceEntryName(ID);
int sound= getResources().getIdentifier(NameID,"raw","com.example.pickachu.mypatatap");
mediaPlayer = MediaPlayer.create(this,sound);
mediaPlayer.start();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
The sound is not playing after multiple taps because you must be getting IllegalStateException because you are not releasing the Mediaplayer object and Mediaplayer Lifecycles are not managed properly when you tap multiple times.
You can use setOnCompletionListener(MediaPlayer.OnCompletionListener listener) to release mediaPlayer after completion of sound as:
mediaPlayer = MediaPlayer.create(this,sound);
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.reset();
mp.release();
mediaplayer = null;
}
});
mediaPlayer.start();
pass uri instead string
mediaPlayer= MediaPlayer.create(this, Uri.parse(Environment.getExternalStorageDirectory().getPath()+ "/Music/music.mp3"));
mediaPlayer.setLooping(true);
mpintro.start();

calling a method after starting an activity

I'm making an Android whack a mole game. I have the main activity which is basically the launcher, when you press the Play button the game activity starts. This works fine as it shows the background image and all molehills but I don't know how to call the method to start the game.
I've tried to call it from inside onCreate() but this ends up "playing the game" itself.
I've tried to call it right after the startActivity(intent) but the app crashes. And also I've tried to create an instance of the game class and call the play() method after the start activity but it doesn't work aswell. I don't know how to start the game method once the game activity is loaded.
I hope I explained well, thank you.
public class MainActivity extends AppCompatActivity {
ImageButton btnStart;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide TitleBar
try { this.getSupportActionBar().hide();}
catch (NullPointerException e){}
setContentView(R.layout.activity_main);
btnStart = (ImageButton)findViewById(R.id.btnStart);
btnStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), GameView.class);
startActivity(intent);
}
});
}
And this is the code for the game_activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide TitleBar
try { this.getSupportActionBar().hide();}
catch (NullPointerException e){}
setContentView(R.layout.activity_game_view);
game();
}
The game() method is a typical game loop.
public void game() {
Random random = new Random();
int index;
/*
* Casting array to store all ImageView on the game
*/
imgViewArray[0] = (ImageView)findViewById(R.id.img1);
imgViewArray[1] = (ImageView)findViewById(R.id.img2);
imgViewArray[2] = (ImageView)findViewById(R.id.img3);
imgViewArray[3] = (ImageView)findViewById(R.id.img4);
imgViewArray[4] = (ImageView)findViewById(R.id.img5);
imgViewArray[5] = (ImageView)findViewById(R.id.img6);
imgViewArray[6] = (ImageView)findViewById(R.id.img7);
imgViewArray[7] = (ImageView)findViewById(R.id.img8);
imgViewArray[8] = (ImageView)findViewById(R.id.img9);
imgViewArray[9] = (ImageView)findViewById(R.id.img10);
int j=0;
while (j < 10) {
// Get a random image to animate
index = random.nextInt(10);
switch(index) {
case 0: imgViewArray[0].setImageResource(images[6]);
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
imgViewArray[0].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
imgViewArray[0].setImageResource(images[0]);
}
});
}
},
300 // The code executes after 300ms
);
break;
I think you should put the game() call inside onResume().
There are many ways to solve the problem:
Using EventBus
Send the start game Event from Main Activity and register for the Event in the Game activity.
This is my favorite way to handle the problem. It's because the simplicity and prevent us from tightly coupled code. The major problem with using EventBus is we will lost in the sea of Event if there are too much Event in the the app.
How to do:
First, create the Event. This is just a simple class:
public class StartGameEvent {
}
Second, register for the event in the game activity:
public class GameActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
EventBus.getDefault().register(this);
}
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
Third, subscribe for the event:
public class GameActivity extends Activity {
...
#Subscribe
public void onMessageEvent(StartGameEvent event) {
game();
}
}
Last, send the event from Main activity:
EventBus.getDefault().post(new StartGameEvent());
Using LocalBroadcastManager
You need to create the message and broadcast it in from your Main activity:
Intent intent = new Intent("playEvent");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Then, in the game activity, you need to register as receiver:
#Override
public void onCreate(Bundle savedInstanceState) {
// register for the event
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver,
new IntentFilter("playEvent"));
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
game();
}
};
#Override
protected void onDestroy() {
// Unregister here
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(mReceiver);
super.onDestroy();
}
I slightly modifying the code from How to use LocalBroadcastManager? for your case.
Using a static method in Game activity
This is the simplest way but highly discouraged. Because we can't ensure the state of the activity. Do not use this in production code. This is for learning sake only.
You can make the game() method as a static method like this:
public class GameActivity extends Activity {
...
public static void game() {
// game logic.
}
}
Then call the method when you want with:
GameActivity.game();

How to turn off music bgm(Background Music) from other java

I am making an app where bgm start from main page. But I couldn't find a way to turn it off when starts learning.
Can I remotely switch off bgm from different java file
This is my 1st java,mainmenu.class
public class mainmenu extends AppCompatActivity {
MediaPlayer bkgrdmsc;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainmenu);
Button btn = (Button) findViewById(R.id.mula);
assert btn != null;
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent ke_belajar_latihan = new Intent(getApplicationContext(), taqi.mengaji.belajar_latihan.class);
startActivity(ke_belajar_latihan);
}
});
bkgrdmsc = MediaPlayer.create(this, R.raw.song);
bkgrdmsc.setLooping(true);
bkgrdmsc.start();
}
}
This is the other file I want to remotely off the bgm when starting the learning session(as student start to learn)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.belajar_hija_baris);
Button btn=(Button) findViewById(R.id.hijaiyyah);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent ke_hijaiyah=new Intent(getApplicationContext(),taqi.mengaji.hijaiyyah.class);
startActivity(ke_hijaiyah);
}
});
}
I want R.id.hijaiyyah to navigate to learn xml also stop bgm
Please help I'm a newbie XD
Make an singleton class and add you music playing code into it for stopping and starting and use that singleton class in all your 2 activities for eg:
public class MusicManager {
private static MusicManager refrence = null;
public static MusicManager getInstance(){
if(refrence == null){
refrence = new MusicManager ();
}
return refrence;
}
}
Add a public method to this singleton class to start and stop music
public void initalizeMediaPlayer(Context context, int musicId){
// add initalization of media player in it and loop it
MediaPlayer bkgrdmsc;
bkgrdmsc = MediaPlayer.create(this, R.raw.song);
bkgrdmsc.setLooping(true);
}
public void startPlaying(){
bkgrdmsc.start();
}
public void stopPlaying(){
bkgrdmsc.stop();
}
//Add stuff like pausing and resuming if you desire
To use this class add this to any activity you want to play music:
MusicManager.getInstance().initalizeMediaPlayer(this, R.raw.menu); // to initalize of media player
MusicManager.getInstance().startPlaying();// to start playing music
MusicManager.getInstance().stopPlaying(); // to stop playing music
You can also use service to perform this task as service runs in background. You can start and stop service any time in your code.

How can I download mp3 files and play them in my app?

Could someone show me or teach me how I can download 5 or more mp3 in a file and playing them in my app. I've searched about it but all of people how has asked this, nothing explained it well. I don't want to download only one mp3, but multiple mp3s in a file.here is main.java
public class StreamingMp3Player extends Activity implements OnClickListener, OnTouchListener, OnCompletionListener, OnBufferingUpdateListener{
private ImageButton buttonPlayPause;
private SeekBar seekBarProgress;
public EditText editTextSongURL;
private MediaPlayer mediaPlayer;
private int mediaFileLengthInMilliseconds; // this value contains the song duration in milliseconds. Look at getDuration() method in MediaPlayer class
private final Handler handler = new Handler();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initView();
}
/** This method initialise all the views in project*/
private void initView() {
buttonPlayPause = (ImageButton)findViewById(R.id.ButtonTestPlayPause);
buttonPlayPause.setOnClickListener(this);
seekBarProgress = (SeekBar)findViewById(R.id.SeekBarTestPlay);
seekBarProgress.setMax(99); // It means 100% .0-99
seekBarProgress.setOnTouchListener(this);
editTextSongURL = (EditText)findViewById(R.id.EditTextSongURL);
editTextSongURL.setText(R.string.testsong_20_sec);
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnCompletionListener(this);
}
/** Method which updates the SeekBar primary progress by current song playing position*/
private void primarySeekBarProgressUpdater() {
seekBarProgress.setProgress((int)(((float)mediaPlayer.getCurrentPosition()/mediaFileLengthInMilliseconds)*100)); // This math construction give a percentage of "was playing"/"song length"
if (mediaPlayer.isPlaying()) {
Runnable notification = new Runnable() {
public void run() {
primarySeekBarProgressUpdater();
}
};
handler.postDelayed(notification,1000);
}
}
#Override
public void onClick(View v) {
if(v.getId() == R.id.ButtonTestPlayPause){
/** ImageButton onClick event handler. Method which start/pause mediaplayer playing */
try {
mediaPlayer.setDataSource(editTextSongURL.getText().toString()); // setup song from http://www.hrupin.com/wp-content/uploads/mp3/testsong_20_sec.mp3 URL to mediaplayer data source
mediaPlayer.prepare(); // you must call this method after setup the datasource in setDataSource method. After calling prepare() the instance of MediaPlayer starts load data from URL to internal buffer.
} catch (Exception e) {
e.printStackTrace();
}
mediaFileLengthInMilliseconds = mediaPlayer.getDuration(); // gets the song length in milliseconds from URL
if(!mediaPlayer.isPlaying()){
mediaPlayer.start();
buttonPlayPause.setImageResource(R.drawable.button_pause);
}else {
mediaPlayer.pause();
buttonPlayPause.setImageResource(R.drawable.button_play);
}
primarySeekBarProgressUpdater();
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if(v.getId() == R.id.SeekBarTestPlay){
/** Seekbar onTouch event handler. Method which seeks MediaPlayer to seekBar primary progress position*/
if(mediaPlayer.isPlaying()){
SeekBar sb = (SeekBar)v;
int playPositionInMillisecconds = (mediaFileLengthInMilliseconds / 100) * sb.getProgress();
mediaPlayer.seekTo(playPositionInMillisecconds);
}
}
return false;
}
#Override
public void onCompletion(MediaPlayer mp) {
/** MediaPlayer onCompletion event handler. Method which calls then song playing is complete*/
buttonPlayPause.setImageResource(R.drawable.button_play);
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
/** Method which updates the SeekBar secondary progress by current song loading from URL position*/
seekBarProgress.setSecondaryProgress(percent);
}
You'll need to use 3rd party libraries to support MP3 playback, as it is not included in the standard library. See Wikipedia for a list of alternatives.
For the downloading part, use an URLConnection to get an InputStream on the file and write it to a FileOutputStream. This might help, too: Working unbuffered Streams

Categories