I am developing an android application in which I can/allowed to use only one instance of MediaPlayer(Singleton instance).
static MediaPlayer mp;
public static MediaPlayer getMediaPlayer() {
if (mp == null) {
mp = new MediaPlayer();
}
return mp;
}
Now This activity can be called for two purposes
from within application (Say ABC)
from any other application (say XYZ) for preview
This instance of mediaplayer is supposed to play either video or audio.
So I have created a class which handles request(parameterized constructor to check for audio instance needed or video instance needed) and based on request, it creates required instance.
But the problem arises when Within application user is playing an audio file and user launched other application (XYZ) and requested to play video.
Now I am storing MediaPlayer's previous state (like which file it was playing and current position etc) and releasing MediaPlayer to be used for XYZ application for Video Playing. And once user stops playing video, ABC resumes playing audio file based on the stored instance.
So is this the right approach? Or I need to do modify the architecture of this task?
Please suggest w.r.t. design patterns
Using singletons in Android for state persistance is something to be careful about.
Mabye you should investigate the activity lifecycle to understand in which cases you can loose the singleton instance (and therefore all the data stored inside it).
Here is some information
For instance when your app is running in the background, the cellphone can ask for memory and kill the instance of your singleton.
Here is an example Singleton that I would try:
public class MediaPlayer{
private static MediaPlayer instance = new MediaPlayer();
public static MediaPlayer getInstance() {
return MediaPlayer.instance;
}
}
Now you have a scenario in which you can create objects based on the getInstance() method which can only reference the same object which will ensure your singleton pattern. I tested it and attempted to make objects from this singleton pattern:
MediaPlayer t1 = MediaPlayer.getInstance();
MediaPlayer t2 = MediaPlayer.getInstance();
System.out.println(t1.equals(t2));
result:
true
Related
In my app I used the singleton pattern for objects which serve other classes and not more than one instance of them is needed. LocalstorageManager for example:
public class LocalStorage {
private Context context;
private static LocalStorage instance = null;
protected LocalStorage() {
// Exists only to defeat instantiation.
}
public synchronized static LocalStorage getInstance() {
if (instance == null) {
instance = new LocalStorage();
}
return instance;
}
public void setContext(Context _context) {
instance.context = _context;
}
...
In this app I am using a BroadcastReceiver that responds to GSM notifications:
...
#Override
protected void onPushReceive(Context context, Intent intent) {
LocalStorage localStorage = LocalStorage.getInstance();
...
Should I check whether my singletons state is set before using them? Is there a chance than on cases of low memory or an incoming GSM when the app is not running I will have to reinstansiate my singletons with their state? If so, should I do it in the custom app class? Would it always be called?
Should I check whether my singletons state is set before using them?
Singleton if properly implemented would return only one instance
which is common throughout the app life-cycle. Your singleton's state
is ensured until unless the Singleton object gets destroyed say as described in point "2" below.
Is there a chance than on cases of low memory or an incoming GSM when the app is not running I will have to reinstansiate my singletons with their state?
Java Garbage Collector (GC) will collect all the objects that are not used/not referenced. Which means if no active object of your app has a "reference"/"is using" this object then the GC will clear it. In such case you may have to instantiate your object. Java GC gets triggered irrespective of "..low memory or an incoming GSM.." it could also be System discretion.
If so, should I do it in the custom app class? Would it always be called?
No, not in custom app class do it in the Singleton class implementation. The method "getInstance()" will take care of when to instantiate a new object Vs when to serve an existing object. If there is any custom state/parameter to instantiate you may want to pass them in getInstance() method.
I have 15 or so activities. Each one of them has a method, and I want to play audio in that method. Now, I have the obvious option to copy and paste the following line of code into each and every one of my activities Now, if I wanted to change something, I would have to go back into each and every one of my activities again. Here is the code:
MediaPlayer pop = MediaPlayer.create(CurrentActivity.this, R.raw.pop);
pop.start();
So, after searching the web for a few hours, I found that most people would just copy and paste it into each activity. So, I put the line of code (above) into a separate java class (which was a service by the way) tried to call that method in the service every time I needed to play the audio. So, I did the following:
public class TwentySeconds extends Service{
public void myPop(View view){
MediaPlayer pop = MediaPlayer.create(TwentySeconds.this, R.raw.pop);
pop.start();
}
}
Now, I got the error non static method cannot be referenced from static context. So, naturally, I tried to make method myPop static. Then, I got the error on TwentySeconds.this about being referenced from static context. So, it seems I am stuck. Changing the methods to static can't work, as I am trying to use an instance of the class as well using this. So, how should I go about calling method myPop where the MediaPlayer can successfully play?
Thanks for the advice,
Rich
Typically, if a utility method needs a Context, it is passed in.
public class Utilities {
public static void myPop(Context context){
MediaPlayer pop = MediaPlayer.create(context, R.raw.pop);
pop.start();
}
}
Utilities.myPop(CurrentActivity.this);
I am trying to build my first android app. I have multiple Activities and I am using a Handler and an AssetFileDescriptor in order to play a sound file.
My problem is, how can I pass these objects around? I have one Activity that starts a timer via the handler, and another which stops the timer via the handler. Should I pass these objects around between Activities, or is there another way?
I am not used to Java, but I was wondering if I could make a config static class or something that creates all of these objects, and then each one of my Activities would just access these objects from this static config class. However, this has its own problems, since in order to call the method getAssets(), I cannot use a static class ("Cannot make a static reference to a non-static method.")
Any ideas?
This simplest solution would be to store objects in the Application class, here is a SO answer on the topic Using the Android Application class to persist data
Another more advanced option would be to use Dagger. It is a Dependency Injection framework that can do a lot of cool stuff but is somewhat difficult to get running (atleast took me some time to get working).
Dagger enables defining a Singleton class like this:
#Singleton
public class MySingletonObject {
#Inject
MySingletonObject() {
...
}
}
And whenever you need it in your app:
public class SomeActivityOrFragment {
#Inject MySingletonObject mySingletonObject;
...
mySingletonObject.start();
}
public class SomeOtherActivityOrFragment {
#Inject MySingletonObject mySingletonObject;
...
mySingletonObject.stop();
}
I have Android application and own Application derived class holding some internal data.
Among other there are some string fields. The problem is that if I put the application in foreground, work on other application, switch back to my app again, the app may be restarted because it got killed by system. Unfortunatelly the Application object seems not to be created again because the onCreate method of application object doesn't get called and all fields are set to null. My Activity gets recreated but all Application's object fields are null. When is the Application.onCreate method called? How to handle it?
there is no onCreate that you can register to.in later API's there's a way to register to the Activity lifecycle functions. and then you can do what ever you want.
basically, what you should do is use SharedPrefrences for storing information.
what I would do is:
class MyApp extends Application {
private static String someResource = null;
public static String getSomeResource(Context context) {
if(someResource == null) {
SharedPrefrences prefs = (SharedPrefrences)
context.getSystemService(Context.SHARED_PREFRENCES);
someResource = prefs.getString(SOME_RESOURCE, null);
}
return someResource;
}
Application onCreate() will called only for one time during its life-cycle, i.e.. only when application is started.
As suggested by thepoosh below answer is valid ,if your application is killed,still the data is saved in shared preference.
I'm creating a music player for Android and it's mostly working. The problem is that when I turn the device horizontally I lose all the variables from the Activity (which makes sense because it is destroyed and re-created).
I've tried using bundles to store the state of the player with onSaveInstanceState & onRestoreInstanceState but I still can't access the media player. Is there a way to pass objects like the MediaPlayer in bundles? Should I be using a database instead?
Thanks
You should use a Service to Provides "background" audio playback capabilities, allowing the
user to switch between activities or Rotate device without stopping playback.
Check out android_packages_apps_Music which is opensource by CM on github , It use MediaPlaybackService extends Service to do this , checkout MediaPlaybackService.java
For objects you couldn't pass via a bundle, I would suggest you to use the simple SharedPreference to store objects.
Here you have a simple implementation:
public class Data {
private SharedPreferences preferences;
private int test;
public Data (Context context)
{
preferences = context.getSharedPreferences("Data", 0);
test = preferences.getInt("test", 0);
}
public int getTest()
{
return test;
}
public void setTest(int input)
{
this.test = input;
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("Test", input);
editor.commit();
}
}
You have just to initialize the variable in the onCreate():
Data mydata = new Data(this);
And you can use set/get with mydata to store/retrieve your persistent data.
Edit: It is maybe not suitable for MediaPlayer objects, but for other classical types (int, string, boolean...).
Both of the methods below would allow you to keep your mediaplayer object through the rotation, but neither use bundles.
You could persist your media player by using onRetainNonConfigurationInstance() to save the variable and getLastNonConfigurationInstance() to retrieve it after the rotation, but this method isn't necessarily the best as it is not always called
-See this SO post for more info https://stackoverflow.com/a/3916068/655822
Or you could persist your media player by extending your application class and storing it in there
below info copied from the linked SO answer for the purpose of making this answer quicker to read
You can pass data around in a Global Singleton if it is going to be used a lot.
public class YourApplication extends Application
{
public SomeDataClass data = new SomeDataClass();
}
Then call it in any activity by:
YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.
-See this SO post for more info on that https://stackoverflow.com/a/4208947/655822
Another way would be to :
In your AndroidManifest.xml, find your entry for your activity and add the following attribute and value:
android:configChanges="orientation|screenSize"
This will stop your activity from being destroyed and recreated on orientation.