why the volley class uses singleton pattern design? - java

to use the volley library i found the following code:
public class AppController extends Application {
public static final String TAG = AppController.class
.getSimpleName();
private RequestQueue mRequestQueue;
private static AppController mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized AppController getInstance() {
return mInstance;
}
public RequestQueue getRequestQueue() {
//baraye avalin bar ejra mishe
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req, String tag) {
// set the default tag if tag is empty
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
getRequestQueue().add(req);
}
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
i want to understand why this class uses Singleton pattern design?if we create two objects of the class what problems occur?

This is not the singleton pattern. The singleton pattern enforces that there can only ever be (at most) a single instance of a particular class. That's not true here. You could have many RequestQueues across many AppControllers.
What this is, in fact, is lazy initialisation. It is probably employed because instantiating a RequestQueue is somewhat of a large operation, and you don't want to instantiate it unnecessarily if you don't have to.

Related

How to solve Android MultiDex Apllication Instance Null Pointer Exception?

I want to do a core api service integration in my Android project.
My core service class is as follows:
public class TestApplication extends MultiDexApplication {
private static final String LOG_TAG_NETWORK = "GNetwork";
public static JacksonConverterFactory factory;
private static TestApplication instance;
private OkHttpClient.Builder okHttpBuilder;
private TestService testtService;
private Location lastKnownLocation;
public static TestApplication getInstance() {
return instance;
}
#Override
public void onCreate() {
super.onCreate();
instance = this;
Pref.init(this);
okHttpBuilder = new OkHttpClient.Builder();
okHttpBuilder.connectTimeout(UrlConstants.CONNECT_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)
.readTimeout(UrlConstants.READ_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)
.writeTimeout(UrlConstants.WRITE_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
if (BuildConfig.LOG_ENABLED) {
HttpLoggingInterceptor httpLoggingInterceptor =
new HttpLoggingInterceptor(message -> Log.d(LOG_TAG_NETWORK, message));
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpBuilder.addInterceptor(httpLoggingInterceptor);
}
factory = getJacksonConverterFactory();
}
#NonNull
private JacksonConverterFactory getJacksonConverterFactory() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return JacksonConverterFactory.create(objectMapper);
}
public void setupRetrofit() {
String BASE_URL = "http://xxxxx";
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL).client(okHttpBuilder.build())
.addConverterFactory(factory).build();
testService = retrofit.create(TestService.class);
}
public TestService getTestService() {
return testService;
}
}
Then I create an instance from this core class. But here my constant getIntance value returns null.
TestApplication.getInstance().setupRetrofit();
I can't understand that. GetInstance method always return null;
In my app build.gradle file is multiDexEnabled true.
How to solve this situation?
never use instance of application like this. for get application instance you need activity and in your activity you can use
static TestApplication getInstance(Activity activity) {
if (instance == null)
instance = ((TestApplication) activity.getApplication());
return instance;
}
this will solve your issues but the way you implement retrofit and using it is not best practices. You can find better way that doesn't need activity.
change getInstance()
from this
public static TestApplication getInstance() {
return instance;
}
to this
public static TestApplication getInstance() {
instance=new TestApplication();
return instance;
}
and also remove this line from oncreate
instance = this;
After Enabling Multidex
Replace With:-
public class Application extends MultiDexApplication {
public static final String TAG = Application.class.getSimpleName();
#Override
public void onCreate() {
super.onCreate();
ApplicationHelper.initDatabaseHelper(this);
PostInteractor.getInstance(this).subscribeToNewPosts();
}
}

Android Volley Error

I get Android volley error suddenly when i run my program.here i paste my AppController class for handling the volley objects.
AppController.java
public class AppController extends Application {
public static final String TAG = AppController.class.getSimpleName();
private RequestQueue mRequestQueue;
private static AppController mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized AppController getInstance() {
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req, String tag) {
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
getRequestQueue().add(req);
}
public <T> void addToRequestQueue(Request<T> req) {
req.setTag(TAG);
getRequestQueue().add(req);
}
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
and i call this class in some another class of my program like
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
it will executed without any errors in so many days but now it shows error
like
Error:
java.lang.NoSuchMethodError: No virtual method setTag(Ljava/lang/Object;)Lcom/android/volley/Request; in class Lcom/android/volley/Request or its super classes (declaration of 'com.android.volley.Request'; appears in /data/app/com.example.rninja4.rookie-1/split_lib_dependencies_apk.apk:classes6.dex)
at com.example.packagename.App.AppController.addToRequestQueue(AppController.java:39)
You have not declared application class in manifest like below.
<application
android:name="AppController"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >

Android Same instance output different result

I outputted the same object at the same time but I got different results...
What could be the cause of DIFFERENT result?
The function in UserHelper.class:
public void login(String phone, String password) {
UserModel.logInInBackground(phone, password, new LogInCallback<UserModel>() {
#Override
public void done(UserModel userModel, AVException e) {
if (null != userModel) {
if (userModel.getPosition() == UserModel.USER_BUYER) {
refresh();
DebugLog.e("fuck" + mUserStatus + UserInstance.getInstance().getUserStatus());
for (UserListener listener : listeners)
listener.OnUserLogin();
} else if (userModel.getPosition() == UserModel.USER_SELLER)
logout();
} else for (UserListener listener : listeners)
listener.HandleError(e.getCode());
}
}, UserModel.class);
public USER_STATUS getUserStatus() {
return mUserStatus;
}
And the UserInstance.class.
public class UserInstance {
public static UserHelper mInstance;
public static UserHelper getInstance() {
if (null == mInstance) mInstance = new UserHelper();
DebugLog.e(mInstance.toString());
return mInstance;
}
}
First of all, if you meant the UserHelper class to be a singleton,
why do you access the USER_STATUS instance using UserInstance.getInstance().getUserStatus() instead of just getUserStatus() ?
Second of all, you probably get different instances of UserHelper if the singleton is accessed from different threads, because your implementation is not thread-safe.
A correct implementation would be using a double locking pattern:
public class UserInstance {
public static UserHelper mInstance;
private static final ReentrantLock lock = new ReentrantLock();
public static UserHelper getInstance() {
if (null == mInstance){
lock.lock();
try{
if (null == mInstance){
mInstance = new UserHelper();
}
}
finally{
lock.unlock();
}
}
DebugLog.e(mInstance.toString());
return mInstance;
}
}
Ultimately, I get the same instance..
Thanks to Shlomi Uziei. I forgot to use double locking pattern. And I should not make mInstance static...

Android Volley error using Singleton pattern

I am trying to follow this guide on how to work with Volley using a Singleton. The goal is to use this Singleton to have my RequestQueue in an Application context so it won't be affected by shifting from landscape to portrait and such.
But I get the following error:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.File android.content.Context.getCacheDir()' on a null object reference
at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:45)
at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:105)
at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:115)
at se.ccconsulting.arenaui3.VolleySingleton.(VolleySingleton.java:20)
at se.ccconsulting.arenaui3.VolleySingleton.getInstance(VolleySingleton.java:34)
at se.ccconsulting.arenaui3.AdventureFragment.onCreateView(AdventureFragment.java:62)
...
And it points towards this line:
mRequestQueue = Volley.newRequestQueue(HelperApplication.getAppContext());
I am not sure what is wrong here as from what I can see in the code the getInstance() method in VolleySingleton.java is not supposed to
VolleySingleton.java
public class VolleySingleton {
private static VolleySingleton mInstance = null;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private VolleySingleton(){
mRequestQueue = Volley.newRequestQueue(HelperApplication.getAppContext());
mImageLoader = new ImageLoader(this.mRequestQueue, new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);
public void putBitmap(String url, Bitmap bitmap) {
mCache.put(url, bitmap);
}
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
});
}
public static VolleySingleton getInstance(){
if(mInstance == null){
mInstance = new VolleySingleton();
}
return mInstance;
}
public RequestQueue getRequestQueue(){
return this.mRequestQueue;
}
public ImageLoader getImageLoader(){
return this.mImageLoader;
}
}
HelperApplication.java
public class HelperApplication extends Application{
private static HelperApplication mInstance;
private static Context mAppContext;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
this.setAppContext(getApplicationContext());
}
public static HelperApplication getInstance(){
return mInstance;
}
public static Context getAppContext() {
return mAppContext;
}
public void setAppContext(Context mAppContext) {
this.mAppContext = mAppContext;
}
}
This is the line of code I used from Volley before implementing the Singlton which worked perfectly but do not meet my needs:
RequestQueue queue = Volley.newRequestQueue(getActivity());
I am debugging on Genymotion.
Fruthermore, row of code from Volley.java mentioned in the exception:
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
I need help getting passed this error.
If you read the README of the Github repo that code links to, it specifically mentions, you need to add this to your manifest XML.
<application android:name="com.company.MyApplication">
</application>
In your case, change com.company.MyApplication to xxx.yyy.HelperApplication, though.

Singleton with params

I've write a Singleton, but this singleton need a Context as a param to initialize itself. As the Context is used only once in its constructor, I would not like to add it in getInstance(Context). After thinking more, I came out the following answer:
public class Singleton {
private static Context sContext;
public static void init(Context context) {
sContext = context;
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static Singleton INSTANCE = new Singleton();
}
private Singleton() {
if (sContext == null) {
throw new IllegalArgumentException("#init should be called in Application#onCreate");
}
// Initialize the Singleton.
// .....
// After the constructed, remove the sContext.
sContext = null;
}
}
It's well, with a class method init called in Android/Applicaiton#onCreate method.
It's not instance the SingletonHolder.INSTANCE, as it's not loaded.
Could some give someone advice on my solution。Thanks!
With the help of # WarrenFaith I changed my code.
public class Singleton {
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static Singleton INSTANCE = new Singleton();
}
private Singleton() {
final Context context = BaseApplication.getApplication();
// Initialize the Singleton.
// .....
}
}
public class BaseApplication extends Application {
private static Application sApplication;
public static Application getApplication() {
return sApplication;
}
#Override
public void onCreate() {
super.onCreate();
sApplication = this;
}
}
Why not using a way easier solution:
public class Singleton {
private final static Singleton mInstance = new Singleton();
private final static Context sContext;
private Singleton() {
sContext = MyApplication.getInstance();
// do more
}
public static Singleton getInstance() {
return mInstance;
}
}
That is a pretty bullet proof singleton pattern.
Of course you need to implement your application class to be a singleton but by definition it already is.
public class MyApplication extends Application {
private static MyApplication mInstance;
#Override
protected void onCreate() {
super.onCreate();
mInstance = this;
// create your Singleton!
Singleton.getInstance();
}
public static MyApplication getInstance() {
return mInstance;
}
}

Categories

Resources