What for do we need to synchronize creating syncadapter in onCreate() in service? As far as I know, there is only one instance of service in system at time. So, there is no change of parallel calls onCreate().
Code from android developers sample:
public class SyncService extends Service {
// Storage for an instance of the sync adapter
private static SyncAdapter sSyncAdapter = null;
// Object to use as a thread-safe lock
private static final Object sSyncAdapterLock = new Object();
public void onCreate() {
/*
* Create the sync adapter as a singleton.
* Set the sync adapter as syncable
* Disallow parallel syncs
*/
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
}
}
}
...
}
Related
I'm using Dagger 2 to provide a singleton Realm instance for the whole app (all data access objects use a single realm). However, as far as I know, Realm can have multi-instance using Realm.getInstance() and we have to close each instance when we're done with it as presented by the Realm docs:
/**
* Closes the Realm instance and all its resources.
* <p>
* It's important to always remember to close Realm instances when you're done with it in order not to leak memory,
* file descriptors or grow the size of Realm file out of measure.
*
* #throws IllegalStateException if attempting to close from another thread.
*/
#Override
public void close() {
if (this.threadId != Thread.currentThread().getId()) {
throw new IllegalStateException(INCORRECT_THREAD_CLOSE_MESSAGE);
}
if (realmCache != null) {
realmCache.release(this);
} else {
doClose();
}
}
My question is: should I use a singleton Realm instance as I did, or create a realm instance for each Activity / Fragment and close it using realm.close() at onDestroy()?
Managed RealmObjects (which are lazy-loaded on their access) are accessible only if there is at least 1 open instance of Realm on that given thread, however NOT closing Realm instance on non-looper background thread is very severe problem.
If you provide thread-local singleton Realm from Dagger module then that Realm instance will only be accessible on the thread it was created on. And will cause a crash accessed from anywhere else.
One possibility would be to provide a singleton class of your own that can open Realm instances, like this:
#Singleton
public class RealmManager {
private final ThreadLocal<Realm> localRealms = new ThreadLocal<>();
#Inject
public RealmManager() {
}
/**
* Opens a reference-counted local Realm instance.
*
* #return the open Realm instance
*/
public Realm openLocalInstance() {
checkDefaultConfiguration();
Realm realm = Realm.getDefaultInstance(); // <-- maybe this should be configurable
if(localRealms.get() == null) {
localRealms.set(realm);
}
return realm;
}
/**
* Returns the local Realm instance without adding to the reference count.
*
* #return the local Realm instance
* #throws IllegalStateException when no Realm is open
*/
public Realm getLocalInstance() {
Realm realm = localRealms.get();
if(realm == null) {
throw new IllegalStateException(
"No open Realms were found on this thread.");
}
return realm;
}
/**
* Closes local Realm instance, decrementing the reference count.
*
* #throws IllegalStateException if there is no open Realm.
*/
public void closeLocalInstance() {
checkDefaultConfiguration();
Realm realm = localRealms.get();
if(realm == null) {
throw new IllegalStateException(
"Cannot close a Realm that is not open.");
}
realm.close();
// noinspection ConstantConditions
if(Realm.getLocalInstanceCount(Realm.getDefaultConfiguration()) <= 0) {
localRealms.set(null);
}
}
private void checkDefaultConfiguration() {
if(Realm.getDefaultConfiguration() == null) {
throw new IllegalStateException("No default configuration is set.");
}
}
}
But even then, you'd need to manage the local instances for the given threads where you need them.
public class MainActivity
extends AppCompatActivity {
RealmManager realmManager;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
realmManager = Injector.get().realmManager();
realmManager.openLocalInstance();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
...
}
#Override
protected void onDestroy() {
super.onDestroy();
realmManager.closeLocalInstance();
}
A singleton instance most likely gets you into problems. You should create one for each Activity/Fragment instead.
There is android application which stored data into the sqlite. I keep a list of routes in databases table.I display the data on the active route on the screen/To release the processor, I use static List inside service.To release the processor, I use static List inside service. I change the list when receiving data from the server.
public class NetworkService extends Service{
private static NetworkService instance = null;
private static List<RouteTask> routeTaskList;
private static LoadRoutesTask loadRoutesTask;
private static RouteChangedListener rtListener ;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
if (instance == null) {
instance = this;
NetworkManager.updateNetworkInfo(this);
NetworkManager.setNetworkListener(this);
}
}
public static Context getCurrentContext() {
return instance;
}
public static boolean hasInstance() {
return instance != null;
}
public static void setRouteTaskList(List<RouteTask> rtList)
{
routeTaskList = rtList ;
}
public static List<RouteTask> getRouteTask(){
return routeTaskList;
}
}
In application i can set value
NetworkService.setRouteTaskList(list);
or get value :
List<RouteTask> = NetworkService.getRouteTaskList();
My application usually use routeTaskList instead of sql query for data table.
The task now is change the service, for the android development standards. I removed static field and Now, I run a service through intents (startService(intent)). How Can I remove static settter and getter for routeTaskList object ?
You can provide the Service with the list of tasks as extras in the Intent you use in the startService() call. This replaces your static setter.
To get the list of tasks is more complicated. Options:
You could use AIDL and bind to the Service and then call a method to get the list of tasks
You could call startService() with an Intent that asks the Service to broadcast the list of tasks. In the Service.onStartCommand() you could then send a broadcast Intent which contains the list of tasks as extras.
You could have the Service send a sticky broadcast Intent which contains the list of tasks every time the list changes. Your app would then use registerReceiver() call to read the most recently sent sticky broadcast.
I have followed this link and successfully made singleton class in Android.
http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/
Problem is that i want a single object. like i have Activity A and Activity B. In Activity A I access the object from Singleton class. I use the object and made some changes to it.
When I move to Activity B and access the object from Singleton Class it gave me the initialized object and does not keep the changes which i have made in Activity A.
Is there any other way to save the changing?
Please help me Experts.
This is MainActivity
public class MainActivity extends Activity {
protected MyApplication app;
private OnClickListener btn2=new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent=new Intent(MainActivity.this,NextActivity.class);
startActivity(intent);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Get the application instance
app = (MyApplication)getApplication();
// Call a custom application method
app.customAppMethod();
// Call a custom method in MySingleton
Singleton.getInstance().customSingletonMethod();
Singleton.getInstance();
// Read the value of a variable in MySingleton
String singletonVar = Singleton.customVar;
Log.d("Test",singletonVar);
singletonVar="World";
Log.d("Test",singletonVar);
Button btn=(Button)findViewById(R.id.button1);
btn.setOnClickListener(btn2);
}
}
This is NextActivity
public class NextActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
String singletonVar = Singleton.customVar;
Log.d("Test",singletonVar);
}
}
Singleton Class
public class Singleton
{
private static Singleton instance;
public static String customVar="Hello";
public static void initInstance()
{
if (instance == null)
{
// Create the instance
instance = new Singleton();
}
}
public static Singleton getInstance()
{
// Return the instance
return instance;
}
private Singleton()
{
// Constructor hidden because this is a singleton
}
public void customSingletonMethod()
{
// Custom method
}
}
and MyApplication
public class MyApplication extends Application
{
#Override
public void onCreate()
{
super.onCreate();
// Initialize the singletons so their instances
// are bound to the application process.
initSingletons();
}
protected void initSingletons()
{
// Initialize the instance of MySingleton
Singleton.initInstance();
}
public void customAppMethod()
{
// Custom application method
}
}
When i run this code, i get Hello which i have initialized in Singleton then World which i gave it in MainActivity and again shows Hello in NextActivity in logcat.
I want it to show world again in NextActivity.
Please help me to correct this.
Tip: To create singleton class In Android Studio, right click in your project and open menu:
New -> Java Class -> Choose Singleton from dropdown menu
EDIT :
The implementation of a Singleton in Android is not "safe" (see here) and you should use a library dedicated to this kind of pattern like Dagger or other DI library to manage the lifecycle and the injection.
Could you post an example from your code ?
Take a look at this gist : https://gist.github.com/Akayh/5566992
it works but it was done very quickly :
MyActivity : set the singleton for the first time + initialize mString attribute ("Hello") in private constructor and show the value ("Hello")
Set new value to mString : "Singleton"
Launch activityB and show the mString value. "Singleton" appears...
It is simple, as a java, Android also supporting singleton. -
Singleton is a part of Gang of Four design pattern and it is categorized under creational design patterns.
-> Static member : This contains the instance of the singleton class.
-> Private constructor : This will prevent anybody else to instantiate the Singleton class.
-> Static public method : This provides the global point of access to the Singleton object and returns the instance to the client calling class.
create private instance
create private constructor
use getInstance() of Singleton class
public class Logger{
private static Logger objLogger;
private Logger(){
//ToDo here
}
public static Logger getInstance()
{
if (objLogger == null)
{
objLogger = new Logger();
}
return objLogger;
}
}
while use singleton -
Logger.getInstance();
answer suggested by rakesh is great but still with some discription
Singleton in Android is the same as Singleton in Java:
The Singleton design pattern addresses all of these concerns. With the Singleton design pattern you can:
1) Ensure that only one instance of a class is created
2) Provide a global point of access to the object
3) Allow multiple instances in the future without affecting a
singleton class's clients
A basic Singleton class example:
public class MySingleton
{
private static MySingleton _instance;
private MySingleton()
{
}
public static MySingleton getInstance()
{
if (_instance == null)
{
_instance = new MySingleton();
}
return _instance;
}
}
As #Lazy stated in this answer, you can create a singleton from a template in Android Studio. It is worth noting that there is no need to check if the instance is null because the static ourInstance variable is initialized first. As a result, the singleton class implementation created by Android Studio is as simple as following code:
public class MySingleton {
private static MySingleton ourInstance = new MySingleton();
public static MySingleton getInstance() {
return ourInstance;
}
private MySingleton() {
}
}
You are copying singleton's customVar into a singletonVar variable and changing that variable does not affect the original value in singleton.
// This does not update singleton variable
// It just assigns value of your local variable
Log.d("Test",singletonVar);
singletonVar="World";
Log.d("Test",singletonVar);
// This actually assigns value of variable in singleton
Singleton.customVar = singletonVar;
I put my version of Singleton below:
public class SingletonDemo {
private static SingletonDemo instance = null;
private static Context context;
/**
* To initialize the class. It must be called before call the method getInstance()
* #param ctx The Context used
*/
public static void initialize(Context ctx) {
context = ctx;
}
/**
* Check if the class has been initialized
* #return true if the class has been initialized
* false Otherwise
*/
public static boolean hasBeenInitialized() {
return context != null;
}
/**
* The private constructor. Here you can use the context to initialize your variables.
*/
private SingletonDemo() {
// Use context to initialize the variables.
}
/**
* The main method used to get the instance
*/
public static synchronized SingletonDemo getInstance() {
if (context == null) {
throw new IllegalArgumentException("Impossible to get the instance. This class must be initialized before");
}
if (instance == null) {
instance = new SingletonDemo();
}
return instance;
}
#Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Clone is not allowed.");
}
}
Note that the method initialize could be called in the main class(Splash) and the method getInstance could be called from other classes. This will fix the problem when the caller class requires the singleton but it does not have the context.
Finally the method hasBeenInitialized is uses to check if the class has been initialized. This will avoid that different instances have different contexts.
The most clean and modern way to use singletons in Android is just to use the Dependency Injection framework called Dagger 2. Here you have an explanation of possible scopes you can use. Singleton is one of these scopes. Dependency Injection is not that easy but you shall invest a bit of your time to understand it. It also makes testing easier.
I call a Service several times, the Service performs its job and then stop himself.
What I need is to store an abject between consecutive calls of the same Service,
So that:
every time the Service is called it retrieves the object uses
and it saves it again before stopping for using it in the next call.
The object in question is a RemoteViews object.
use can use Singleton Pattern:
public class SingletonClass{
private YourObject objectToStoreBetweenSession;
private SigletonClass instance;
private SingletonClass(){
objectToStoreBetweenSession = new YourObject();
}
private static SingletonClass getInstance(){
if(instance==null)
instance = new SingletonClass();
return instance;
}
public void setObject(YourObject obj){
objectToStoreBetweenSession = obj;
}
public YourObject getObject(){
return objectToStoreBetweenSession;
}
}
Into your Service:
YourObject objectToStoreBetweenSession = SingletonClass.getInstance().getObject();
if(objectToStoreBetweenSession.value==0){
//First time that Service is called.
}else{
//Do whatever you want
SingoletonClass.getInstance().setObject(new YourObject("value"));
}
I am using android media player class for playing notification sound in my android Application.
MediaPlayer player = MediaPlayer.create(getApplicationContext(), R.raw.notify);
player.setLooping(false);
player.start();
I need to play different notification sounds in different Activities, so every time i need to play the sound i need to create media player instance and then i need to say start.
But instead of doing this, How can i maintain single instance of the media player throughout the application and use it in all the activities to play the sounds.
Can someone please suggest me the better way of implementing it.
From my point of view i will create one singleton class and i will add all the MediaPlayer related function in this class.
Thanks.
You should consider the Singleton pattern. Make a class MyPlayer that has a static method getMediaPlayer() that returns the same instance of MediaPlayer each time called.
I always do similar thing with a modified version of Singleton Pattern. Since context is needed everywhere in Android, I pass the context to the instance:
public class Asset{
public static Asset(Context context);
}
You can also have different singleton across different context scope, in this implementation, for example:
private static Hashtable<Context, Asset> instances;
public static Asset(Context context){
if (!instances.containKey(context)){
instances.put(context, new Asset(context));
return instances.get(context);
}
The advantage of this compare to classic singleton, is you can define the scope of your singletons. Sometimes you just need the instance stay in same Activity, but second Activity may have different instance. If you need it across different Activity, you just need to pass context.getApplicationContext().
Elaborating a bit more on singleton considerations:
Note: here, the problem of Audioservice failure when creating a series of players consecutively (say 20 mediaPlayers) is addressed too.
Creating the player: The singleton class should create another thread to handle the mediaplayer operations (not the main UI thread)
Create Player Runnable: This thread (created by the singleton instance should be given background priority, a delay of "Thread.sleep(500);" before creation logic to allow the AudioService- used by the MediaPlayer.create()- to finish its work since the later method returns instantly.
Create Player Runnable code:
/**
* Created by George hannuneh on 10/12/2015.
* Holds the background work for creating a media player
*/
public class CreatePlayerRunnable implements Runnable {
static final int CREATE_STATE_FAILED = -1;
static final int CREATE_STATE_STARTED= 0;
static final int CREATE_STATE_COMPLETED= 1;
private static final String TAG ="CreatePlayerRunnable";
private static int sRunnablesCount = 1;
final TaskRunnableCreatePlayerMethods mPlayerTask;
/**
*
* An interface that defines methods that PlayerCreationTask implements. An instance of
* CreatePlayerTask passes itself to an CreatePlayerRunnable instance through the
* CreatePlayerRunnable constructor, after which the two instances can access each other's
* variables.
*/
interface TaskRunnableCreatePlayerMethods {
/**
* Sets the Thread that this instance is running on
* #param currentThread the current Thread
*/
void setCreatePlayerThread(Thread currentThread);
Context getActivity();
Uri getMediaUri();
void handleCreationState(int createStateFailed);
void setPlayer(MediaPlayer returnMediaPlayer);
String getPlayerId();
MediaPlayer getPlayer();
}
/**
* This constructor creates an instance of CreatePlayerRunnable and stores in it a reference
* to the CreatePlayerTask instance that instantiated it.
*
* #param createPlayerTask The CreatePlayerTask
*/
CreatePlayerRunnable(TaskRunnableCreatePlayerMethods createPlayerTask) {
mPlayerTask = createPlayerTask;
}
#Override
public void run() {
/*
* Stores the current Thread in the CreatePlayerTask instance,
* so that the instance
* can interrupt the Thread.
*/
mPlayerTask.setCreatePlayerThread(Thread.currentThread());
// Moves the current Thread into the background
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
MediaPlayer returnMediaPlayer = null;
try {
Thread.sleep(500);
// Before continuing, checks to see that the Thread hasn't
// been interrupted
if (Thread.interrupted()) {
throw new InterruptedException();
}
returnMediaPlayer = MediaPlayer.create(mPlayerTask.getActivity(), mPlayerTask.getMediaUri());
if (returnMediaPlayer == null) {
Log.e("CreatePlayerRunnable", mPlayerTask.getMediaUri()+ " - failed to create player");
return;
}
PlayerEventsHandler playerEvents = new PlayerEventsHandler(mPlayerTask.getPlayerId());
returnMediaPlayer.setLooping(true);
returnMediaPlayer.setOnCompletionListener(playerEvents);
returnMediaPlayer.setOnErrorListener(playerEvents);
returnMediaPlayer.setVolume(0f, 0f);
returnMediaPlayer.start();
} catch (InterruptedException e1) {
// Does nothing
} catch(Exception e)
{
returnMediaPlayer = null;
e.printStackTrace();
}
finally {
if(MainActivity.DEBUG_MODE_ENABLED){
Log.d(TAG, "end of runnable: "+ sRunnablesCount++);
}
if (null == returnMediaPlayer){
mPlayerTask.handleCreationState(CREATE_STATE_FAILED);
} else {
mPlayerTask.setPlayer(returnMediaPlayer);
// Reports a status of "completed"
mPlayerTask.handleCreationState(CREATE_STATE_COMPLETED);
}
// Sets the current Thread to null, releasing its storage
mPlayerTask.setCreatePlayerThread(null);
// Clears the Thread's interrupt flag
Thread.interrupted();
}
}
}