How to active a Foreground Service using a Mediaplayer Singleton - java

I am very newer in Android and I have a Mediaplayer Singleton because I am using fragment that show a list, I want that when the Mediaplayer Singleton is playing will active a service, I was trying with runOnUiThread but this only active many times the service.
this is the Singleton in MyMediaSingleton.java
public class MyMediaSingleton {
MediaPlayer player;
private static volatile MyMediaSingleton instance=null;
private MyMediaSingleton(){
}
public static MyMediaSingleton getInstance(){
if(instance==null){
synchronized (MyMediaSingleton.class){
if(instance==null){
instance=new MyMediaSingleton();
}
}
}
return instance;
}
}
Thank you for your patience.

Media Player Singleton Class
public class MyMediaSingleton {
MediaPlayer mp;
private static volatile MyMediaSingleton instance = null;
private MyMediaSingleton () { }
public static MyMediaSingleton getInstance() {
if (instance == null) {
synchronized (MyMediaSingleton .class) {
if (instance == null) {
instance = new MyMediaSingleton ();
}
}
}
return instance;
}
}
Activity class
public class MainActivity extends Activity {
private MyMediaSingleton player = getInstance();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void playSound(View view){
if(player.mp==null)
player.mp = MediaPlayer.create(getApplicationContext(), R.raw.sound);
player.mp.start();
//For playing multiple sound using single MediaPlayer do it as:
if(player.mp ==null)
player.mp = new MediaPlayer();
else
player.mp.reset();
String fileName="android.resource://"+getPackageName()+
"/"+ R.raw.sound;
player.mp.setDataSource(getApplicationContext(),Uri.parse(fileName));
player.mp.prepare();
player.mp.start();
}
}

Related

How do I combine this two application class for Android Studio?

I have two application class which I want to combine in one, but provides two function, but I want it only one class so that I can call it on the application class in my manifest and get the App to produce both functions since i can not have two classes called on the application class in my manifest file in android studo.
I would like to put the AppController class in the App.Java class
Where I am confused is how to combine it since both extends different classes which java does not permit extending two classes in one.
Below is the App.java class
public class App extends MultiDexApplication implements Constants {
public static final String TAG = App.class.getSimpleName();
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static App mInstance;
private ArrayList<Feeling> feelingsList;
private ArrayList<BaseGift> giftsList;
private SharedPreferences sharedPref;
private String username, fullname, accessToken, gcmToken = "", fb_id = "", photoUrl, coverUrl, area = "", country = "", city = "";
private Double lat = 0.000000, lng = 0.000000;
private long id;
private int state, allowRewardedAds = 1, admob = 1, ghost, pro, verify, balance, allowShowMyInfo, allowShowMyFriends, allowShowMyGallery, allowShowMyGifts, allowGalleryComments, allowComments, allowMessages, allowLikesGCM, allowCommentsGCM, allowFollowersGCM, allowGiftsGCM, allowMessagesGCM, allowCommentReplyGCM, errorCode, currentChatId = 0, notificationsCount = 0, messagesCount = 0, guestsCount = 0, newFriendsCount = 0;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
FirebaseApp.initializeApp(this);
sharedPref = this.getSharedPreferences(getString(R.string.settings_file), Context.MODE_PRIVATE);
this.readData();
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
try {
ProviderInstaller.installIfNeeded(this);
} catch (Exception e) {
e.getMessage();
}
}
}
// NB; I have some more codes in here which i am unable to put in full here.
}
}
Then this this the second class AppController.java
public class AppController extends Application {
private static Context mContext;
private static String mAppUrl;
public static MediaPlayer player;
public static Activity currentActivity;
#Override
public void onCreate() {
super.onCreate();
setContext(getApplicationContext());
mAppUrl = Constant.PLAYSTORE_URL + mContext.getPackageName();
setTelephoneListener();
player = new MediaPlayer();
mediaPlayerInitializer();
//AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
public static void mediaPlayerInitializer(){
try {
player = MediaPlayer.create(getAppContext(), R.raw.snd_bg);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setLooping(true);
player.setVolume(1f, 1f);
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
public static String getAppUrl() {
return mAppUrl;
}
private static void setContext(Context context) {
mContext = context;
}
public static Context getAppContext() {
return mContext;
}
public static void playSound()
{
try {
if (SettingsPreferences.getMusicEnableDisable(mContext)&&!player.isPlaying()) {
player.start();
}else{
}
} catch (IllegalStateException e) {
e.printStackTrace();
mediaPlayerInitializer();
player.start();
}
}
public static void StopSound() {
if (player.isPlaying()) {
player.pause();
}
}
private void setTelephoneListener() {
PhoneStateListener phoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if (state == TelephonyManager.CALL_STATE_RINGING) {
StopSound();
} else if (state == TelephonyManager.CALL_STATE_IDLE) {
} else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
StopSound();
}
super.onCallStateChanged(state, incomingNumber);
}
};
TelephonyManager telephoneManager = (TelephonyManager) getAppContext().getSystemService(Context.TELEPHONY_SERVICE);
if (telephoneManager != null) {
telephoneManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
static
{
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
}
Just Extend Your "AppController" class to "App" class. No need to do extra other work.
Like Below.
public class AppController extends App {
......
}
MulitdexApplication extends Application.
You could change your AppController to:
public class AppController extends MulitdexApplication
and then your App to
public class App extends AppController implements Constants

How to use a MediaPlayer Singleton

I am new to Android developing and am starting with a simple soundboard application. I started developing a soundboard using multiple fragments until I realized that I was using multiple instances of MediaPlayer. This is not good because I want only one sound to play at a time.
I realized that I'd have to use a MediaPlayer Singleton to solve my problem. The only problem is that I can't find many sources or examples of the MediaPlayer Singleton online.
Here's what I originally put into every "onCreateView" in each fragment:
public static class FragmentPage1 extends Fragment {
int selectedSoundId;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_page1, container, false);
final MediaPlayer player = new MediaPlayer();
final Resources res = getResources();
final int[] buttonIds = { R.id.btn1, R.id.btn2, R.id.btn3, R.id.btn4, R.id.btn5, R.id.btn6, R.id.btn7, R.id.btn8, R.id.btn9 };
final int[] soundIds = { R.raw.sound01, R.raw.sound02, R.raw.sound03, R.raw.sound04, R.raw.sound05, R.raw.sound06, R.raw.sound07, R.raw.sound08, R.raw.sound09 };
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
for (int i = 0; i < buttonIds.length; i++) {
if (v.getId() == buttonIds[i]) {
selectedSoundId = soundIds[i];
AssetFileDescriptor afd = res.openRawResourceFd(soundIds[i]);
player.reset();
try {
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
player.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
player.start();
break;
}
}
}
};
for (int i = 0; i < buttonIds.length; i++) {
ImageButton soundButton = (ImageButton) rootView.findViewById(buttonIds[i]);
registerForContextMenu(soundButton);
soundButton.setOnClickListener(listener);
}
return rootView;
}
}
To my knowledge I'd probably put the onClickListener inside of each fragment and the MediaPlayer Singleton in a new Java class. I don't know what to do from there though.
How do I implement a MediaPlayer Singleton and how do I call it back in the fragment's "onCreateView" method?
Examples are highly appreciated and thanks!
See, Singleton is a design pattern, and it is implemented by setting the default constructor as private, then you should provide a get method from wich you can recover your object instance. Check out the example bellow:
public class Foo {
private MediaPlaye md;
private Foo () {
md = new MediaPlayer();
}
public MediaPlayer getMediaPlayer () {
if (md == null) {
new Foo();
}
return md;
}
}
In your sittuation, the best thing to do is to create a Service class that will encapsulate all the MediaPlayer methods. This is done like that because, usually, the developer wants that the player keeps playing even if the user leaves the Activity to which it is binded. In each fragment that you want to use the MediaPlayer API, you can bind the Service and use the defined interface. Take a look in the class below:
public class MusicPlayerService extends android.app.Service implements MediaPlayer.OnPreparedListener,
MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener,
ObserverSubject {
private static final int NOTIFY_ID = 1;
private List<MusicPlayerObserver> mObservers;
private MediaPlayer mMediaPlayer;
private final IBinder playerBind = new MusicBinder();;
private List<Track> mPlaylist;
private Integer mPosition;
private Boolean isRepeating;
private Boolean isShuffling;
private Boolean isPrepared;
private Boolean isPaused;
// Callback Methods______________________________________________
#Override
public void onCreate() {
...
}
#Override
public void onPrepared(MediaPlayer mp) {
...
}
#Override
public IBinder onBind(Intent intent) {
return playerBind;
}
#Override
public boolean onUnbind(Intent intent) {
mMediaPlayer.stop();
mMediaPlayer.release();
return false;
}
#Override
public void onDestroy() {
stopForeground(true);
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp.reset();
return false;
}
// UTIL METHODS__________________________________________________
private Long getCurrentTrackId() {
return mPlaylist.get(mPosition).getTrackId();
}
private Long getCurrentAlbumId() {
return mPlaylist.get(mPosition).getAlbumId();
}
// MEDIA PLAYER INTERFACE________________________________________
public void play() {
...
}
public void pause() {
...
}
public void resume() {
...
}
public void next() {
...
}
public void previous() {
...
}
public void seekTo(int pos) {
...
}
// SERVICE INTERFACE PROVIDER_____________________________________
/**
* Interface through the component bound to this service can interact with it
*/
public class MusicBinder extends Binder {
public MusicPlayerService getService() {
return MusicPlayerService.this;
}
}
}
I highly recommend that you follow this strategy of creating a MusicPlayer service. Also, I suggest you to take a look in another Design Patter called Observer. Usually, in music apps, you want to update several UI elements based on the MP state. Observer is perfect for that situation.
Hope I've helped a little.

Android static TextToSpeech

My problem is that I have an Android App which should tell the user something. I would like to have something like
Speaker.say("Hello World!");
// Wait till sentence is said
Speaker.say("Its " + time);
// Wait again
NextCommand.xyz();
I tried
import android.speech.tts.TextToSpeech;
public class TTS implements TextToSpeech.OnInitListener {
private static TextToSpeech mTts;
private String text;
private static final TTS helper = new TTS();
public static TTS getInstance(){
return helper;
}
public void say(String text){
if(mTts == null){
this.text = text;
mTts = new TextToSpeech(context /* ignore this please */, helper);
mTts.setPitch(3);
}
else{
mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
}
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
}
}
public void stopTTS(){
if(mTts != null){
mTts.shutdown();
mTts.stop();
mTts = null;
}
}
}
And then in onCreate:
TTS tts = TTS.getInstance();
tts.say("Hello World");
tts.say("Hello again!")
but:
only first sentence is said and the optionsMenu is created after that
How to do this?
I solved it:
import android.speech.tts.TextToSpeech;
import java.util.Locale;
public class Test implements TextToSpeech.OnInitListener {
TextToSpeech tts;
String text;
public Test(String text) {
tts = new TextToSpeech(MyApplication.getContext(), this);
this.text = text;
}
#Override
public void onInit(int i) {
if (i == TextToSpeech.SUCCESS) {
tts.setLanguage(Locale.GERMAN);
tts.setPitch(3);
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
while(tts.isSpeaking());
}
}
}
and then you call it:
new Test("Hello");
new Test("Hello again!");
Toast.makeText(this, "Finished", Toast.LENGTH_LONG).show();

Using static variables inside static inner class

I have a class which has a static inner class. The OuterClass wants to use the variables from the static inner class. The problem is I need to instantiate the inner class if I'm using instance variables. So, I decided to use a static variables. Does it contrary to OOP concepts? If so, is there any other principle I should follow or any design pattern I should use to do the same thing?
The reason I used static class is I want to create a custom builder for android activity. The problem is I cannot use constructor to initialise OuterClass which extends Activity. So, I need to load those static variables inside the onCreate() method.
This is my sample code
public class DialogFactory extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setBackgroundDrawable(
new ColorDrawable(android.graphics.Color.TRANSPARENT));
setContentView(R.layout.activity_custom_dialog);
this.setDialogTitle(Builder.title);
this.setDialogMessage(Builder.message);
this.loadButtons();
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.dialog_positive_button:
Builder.callable.onClickButton(Builder.type, DialogEventListener.ButtonType.POSITIVE_BUTTON);
this.finish();
break;
case R.id.dialog_neutral_button:
Builder.callable.onClickButton(Builder.type, DialogEventListener.ButtonType.NEUTRAL_BUTTON);
this.finish();
break;
case R.id.dialog_negative_button:
Builder.callable.onClickButton(Builder.type, DialogEventListener.ButtonType.NEGATIVE_BUTTON);
this.finish();
break;
}
}
private void setDialogTitle(String title) {
TextView view = (TextView) findViewById(R.id.dialog_title);
view.setText(title);
}
private void setDialogMessage(String message) {
TextView view = (TextView) findViewById(R.id.dialog_message);
view.setText(message);
}
private void loadButtons() {
Button positiveButton = (Button) findViewById(R.id.dialog_positive_button);
Button negativeButton = (Button) findViewById(R.id.dialog_negative_button);
Button neutralButton = (Button) findViewById(R.id.dialog_neutral_button);
positiveButton.setVisibility(View.GONE);
negativeButton.setVisibility(View.GONE);
neutralButton.setVisibility(View.GONE);
for (Map.Entry<DialogEventListener.ButtonType, String> entry: Builder.buttons.entrySet()) {
if (entry.getKey() == DialogEventListener.ButtonType.POSITIVE_BUTTON) {
positiveButton.setVisibility(View.VISIBLE);
positiveButton.setText(entry.getValue());
}
else if (entry.getKey() == DialogEventListener.ButtonType.NEGATIVE_BUTTON) {
negativeButton.setVisibility(View.VISIBLE);
negativeButton.setText(entry.getValue());
}
else if (entry.getKey() == DialogEventListener.ButtonType.NEUTRAL_BUTTON) {
neutralButton.setVisibility(View.VISIBLE);
negativeButton.setText(entry.getValue());
}
}
}
#Override
public void onBackPressed() {
//
}
public static final class Builder {
private static DialogEventListener callable;
private static DialogEventListener.DialogType type;
private static String title;
private static String message;
private Context context;
private static Map<DialogEventListener.ButtonType, String> buttons;
public Builder(Context context, DialogEventListener callable,
DialogEventListener.DialogType dialogType, String title, String message) {
Builder.callable = callable;
Builder.type = dialogType;
Builder.title = title;
Builder.message = message;
this.context = context;
Builder.buttons = new HashMap<DialogEventListener.ButtonType, String>();
}
public Intent build() {
return new Intent(this.context, DialogFactory.class);
}
public void addButton(DialogEventListener.ButtonType buttonType, String label) {
Builder.buttons.put(buttonType, label);
}
}
}
After looking at your code, I see multiple problems. To start with, the constructor in the Builder class is use less. And accessing all the attributes of the builder class with class name (declaring them as static) will give you uninitialized references and will result into null pointer exception.
I don't completely understand the purpose of your Builder class here, but if possible try to create a separate class that deals with the creation and initialization. After that create an instance of Builder class inside activity class, use constructor to inject dependencies, and try to use functions inside builder class to perform further operations.

Modifying data from an Async task in an entirely different class

I would like to know just out of curiosity if there are any convenient ways of pulling data out of an async task created inside a class, and then modifying the data in another class (Without extending classes)
I have a way to do it, but it involves making methods static along with the Async task itself
for example, here I'm just making a string "text" in the Async task
public class Main extends Activity{
//Context ctx;
static class MyAsyncTask extends AsyncTask<Void,String,String>{
static String result;
private static Context context;
public MyAsyncTask(Context m)
{
this.context = m;
}
#Override
protected String doInBackground(Void... noArgs) {
result = "text";
return result;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
public static String getStr()
{
return result;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText et = (EditText)findViewById(R.id.editText1);
Button btn = (Button)findViewById(R.id.button1);
MyAsyncTask task = new MyAsyncTask(this);
task.execute();
final Test t = new Test();
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
et.append(t.modifiedString());
}
});
}
}
and in a new class I make a simple String method to modify that data from the async task
public class Test{
public String modifiedString()
{
// Main main = null;
// MyAsyncTask task = new MyAsyncTask(main.ctx);
// task.execute();
String s = (String)Main.MyAsyncTask.getStr();
return "modified " + s + "\n";
}
}
I'm wondering, is there a way I can do this without having to make the async task static? Perhaps with sharing contexts or something?
by the way I'm not doing this to solve any particular problem, I'm only doing it out of curiosity
Just create a singleton
public class Main extends Activity{
public static Main instance;
public static String thestring;
public class MyAsyncTask extends AsyncTask<Void,String,String>{
static final String result = "text";
Context context;
public MyAsyncTask(Context m)
{
this.context = m;
}
#Override
protected String doInBackground(Void... noArgs) {
return result;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
public String getStr()
{
return result;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText et = (EditText)findViewById(R.id.editText1);
Button btn = (Button)findViewById(R.id.button1);
MyAsyncTask task = new MyAsyncTask(this);
task.execute();
thestring = task.getStr();
instance = this;
final Test t = new Test();
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
et.append(t.modifiedString());
}
});
}
public String pulledFromAsyncTask()
{
return thestring;
}
public static Main getInstance(){
return instance;
}
}
and then in the another class
public class Test{
public String modifiedString()
{
Main main = Main.getInstance();
//so with main.something.. you can call the methods you want
//a good solution is to make a singleton class only for MyAsyncTask setting the
//functions get/set so you can take the values from other classes
return "modified " + main.pulledFromAsyncTask() + "\n";
}
}
Reference to a Context in a static way is generally bad idea, it can cause memory leaks
Why don't you simply pass MyAsyncTask object to Test and then do whatever modifications you want, i.e. non-static fashion?
When it comes to testable code static/ singleton is a tough choice.
Depending upon your requirement on the state of data you can however start with an Observer pattern or producer-consumer pattern.
Check out Event bus library for probably an out of the box solution for this use case

Categories