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.
Related
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();
}
}
I'm trying to create a singleton class that will be responsible for playing game sounds. I created a singleton class GameSounds with a method playSound(). In the res folder I have a a subfolder 'raw' with a file letter_found.mp3.
This is the source code of the GameSounds class I wrote:
import android.app.Application;
import android.content.Context;
import android.media.MediaPlayer;
public class GameSounds extends Application {
private static GameSounds gameSounds = new GameSounds();
private static MediaPlayer soundPlayer;
private static Context mContext;
private static int mySoundId = R.raw.letter_found;
private GameSounds() {
mContext = this;
}
public static GameSounds getInstance() {
return gameSounds;
}
public static void playSound() {
soundPlayer = MediaPlayer.create(mContext, mySoundId);
soundPlayer.start();
}
}
This doesn't seem to work as I'm getting the following error message:
"java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference"
I don't understand why this is happening. I tried to search Stackoverflow but couldn't find a solution.
Any help/explanation is greatly appreciated.
You can have a Singleton holding an Application Context (NOT Activity context) but practically you have to set this context before you use your singleton which can be enforced by throwing exceptions. See below example code.
public class GameSounds {
private static Context sContext;
public static void setContext(Context context) {
if (context == null) {
throw new IllegalArgumentException("context cannot be null!");
}
// In order to avoid memory leak, you should use application context rather than the `activiy`
context = context.getApplicationContext();
if (context == null) {
throw new IllegalArgumentException("context cannot be null!");
}
sContext = context;
}
private static Context getContext() {
if (sContext != null) {
return (Context)sContext;
}
throw new IllegalStateException("sContext was not set yet! Please call method setContext(Context context) first.");
}
// the rest of other methods. e.g. playSounds()
private static GameSounds gameSounds = new GameSounds();
private GameSounds() {
}
public static GameSounds getInstance() {
return gameSounds;
}
public void playSound() {
Context context = getContext();
soundPlayer = MediaPlayer.create(context, mySoundId);
soundPlayer.start();
}
}
You shouldn't inherit Application class unless you try to use Singleton pattern. Because Application is base class which contains all other components such as activities and services.
Instead, GameSound class should contain Context object and proper constructor.
Example)
public class GameSounds {
private GameSounds gameSounds;
private MediaPlayer soundPlayer;
private WeakReference<Context> mContext;
private int mySoundId = R.raw.letter_found;
private GameSounds(Context context) {
mContext = new WeakReference<>(context);
}
public GameSounds getInstance(Context context) {
if (gameSounds == null) {
gameSounds = new GameSounds(context);
}
return gameSounds;
}
public void playSound() {
soundPlayer = MediaPlayer.create(mContext.get(), mySoundId);
soundPlayer.start();
}
}
In this code, there is WeakReference<Context> instead of Context. WeakReference is used to prevent memory leaks because memory leaks can occur if you have an instance outside the activity.
To play sound, execute GameSounds.getInstance(this).playSound(); is fine.
If Context can't provide when try to play sound, implement initialize methods and called in Application class can be ok.
public class GameSounds {
private static GameSounds gameSounds;
private MediaPlayer soundPlayer;
private WeakReference<Context> mContext;
private int mySoundId = R.raw.letter_found;
private GameSounds(Application context) {
mContext = new WeakReference<>(context);
}
public static void initialize(Application context) {
if (gameSounds == null) {
gameSounds = new GameSounds(context);
}
}
public static GameSounds getInstance() {
if (gameSounds == null) {
throw new NullPointerException("You need to initialize this code by GameSound.initialize(this) in application class");
}
return gameSounds;
}
public void playSound() {
soundPlayer = MediaPlayer.create(mContext.get(), mySoundId);
soundPlayer.start();
}
}
In this case, you should make Application class and initialize GameSound class by GameSound.initialize(this) in Application class.
To play sound, GameSound.getInstance().playSound() is fine.
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.
How can I have access to a file in my res/raw folder from a Singleton (not an activity) on Android?
I've tried:
InputStream is = MainActivity.getResources().openRawResource("data.json");
which doesn't work since "non-static method getResouces() cannot be referenced from static content".
I've also tried:
URL fileURL = getClass().getClassLoader().getResource(R.raw.data);
String filePath = fileURL.getPath();
which throws a Null-pointer exception.
My Singleton:
public class CoursesDataManager {
private static CoursesDataManager instance;
private final List<Course> courses;
public static CoursesDataManager getInstance() {
if (instance == null)
instance = new CoursesDataManager();
return instance;
}
private CoursesDataManager() {
courses = parseCourses(**filePath/inputStream**);
}
The reason I want to get the file is that I want my Singleton to parse the data in that file once, store this data, and have this data never change and be accessible throughout the lifetime of my application.
Thanks a lot.
public class CoursesDataManager {
private static CoursesDataManager instance;
private final List<String> courses;
public static CoursesDataManager getInstance(Context context) {
if (instance == null)
instance = new CoursesDataManager(context);
return instance;
}
private CoursesDataManager(Context context) {
courses =context.getResources().openRawResource(R.raw.filename);
}
}
call it from Activity
CoursesDataManager.getInstance(getApplicationContext());
You need context to access resources. You could use Application context for this purpose. Subclass your Application, save the context in a static variable. Use the context inside singleton.
Create a Application class:
public class MyApplication extends Application {
public static MyApplication context = null;
public void onCreate() {
super.onCreate();
context = this;
}
}
In your manifest, specify the name of the Application class:
<application
android:name=".MyApplication"
...
>
</application>
Now, use this context in singleton:
InputStream is = MyApplication.context.getResources().openRawResource("data.json");
Note: You can use this method, even when you are creating the singleton instance from outside the Activity, where you dont have Activity context.
Add the context to your class and change it to something like that:
public class CoursesDataManager {
private static CoursesDataManager instance;
private Context context;
private final List<Course> courses;
public static CoursesDataManager getInstance(Context context) {
if (instance == null)
instance = new CoursesDataManager(context.getApplicationContext());
return instance;
}
private CoursesDataManager(Context context) {
this.context = context;
courses = parseCourses(**filePath/inputStream**);
}
public class CoursesDataManager {
private static CoursesDataManager instance;
private static Context mContext;
private final List<Course> courses;
public static CoursesDataManager getInstance(Context context) {
if (instance == null)
{
instance = new CoursesDataManager();
}
mContext = context;
return instance;
}
private CoursesDataManager() {
courses = parseCourses(**filePath/inputStream**);
}
You can use resource from here like
mContext.getResources().openRawResource(resourceId);
I have a singleton class which I first instantiate in 1 activity, then use it in 2 other activities. When the 2nd activity loads, the instance becomes null, where is was not null before.
Here is the code for the singleton class:
public class RestaurantMenuHolder{
private static RestaurantMenuHolder mInstance = null;
public static ArrayList<RestaurantMenuObject> restaurantMenu;
public static RestaurantMenuHolder getInstance(ArrayList<RestaurantMenuObject> restaurantMenu){
if(mInstance == null){
mInstance = new RestaurantMenuHolder(restaurantMenu);
}
return mInstance;
}
public static RestaurantMenuHolder getInstance(){
return mInstance;
}
private RestaurantMenuHolder(ArrayList<RestaurantMenuObject> restaurantMenu){
this.restaurantMenu = restaurantMenu;
}
public static int getCount(){
return restaurantMenu.size();
}
}
I have tried adding synchronized to the getInstance methods, the constructor and getCount, but I still get null when the second activity loads. Does anyone know why or how the singleton would suddenly become null?
I can provide code for the activities if required.
EDIT: More Code
When I initialize the singleton: I run holder = RestaurantMenuHolder.getInstance(restaurantMenu); where restaurantMenu is an arrayList. I initialize this to store data. This is verified to work, the singleton is not null at this point.
In the first activity that I use the singleton, I run RestaurantMenuHolder menuHolder = RestaurantMenuHolder.getInstance(); in onCreateView for the fragment. I use this instance to retrieve the data previously stored. The singleton is also verified to work here.
When the second activity is started, the singleton becomes null, but not immediately. I run menuHolder = RestaurantMenuHolder.getInstance(); again in the second activity and retrieve some more data, all of which is valid.
The problem appears to occur in the ImageAdapter. I use a slidingMenu with an ImageAdapter for both activities. The singleton works for the first activity and is not null, but becomes null when I try to use it again in the second activity.
Here is code from the ImageAdapter:
public class ImageAdapter extends BaseAdapter{
private static LayoutInflater inflater = null;
private ViewHolder holder;
private String id;
private RestaurantMenuHolder menuHolder;
private RestaurantLocationHolder locationHolder;
private Context context;
private String[] sliding_list = {"Home", "Skip to Menu", "Location & Hours", "About Us"};
Typeface tf;
public ImageAdapter(Context context, String id){
this.context = context;
inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.id = id;
tf = Typeface.createFromAsset(context.getAssets(),
"Roboto-Light.ttf");
menuHolder = RestaurantMenuHolder.getInstance();
locationHolder = RestaurantLocationHolder.getInstance(context);
MenuUtilities.setImageHash();
}
#Override
public int getCount() {
if(id == "menu"){
Log.d((menuHolder == null) + "", "MENUHOLDER NULL");
return menuHolder.getCount();
} else if (id == "location") {
return locationHolder.getCount();
} else {
return sliding_list.length;
}
}
... more code
When the second activity is started, return menuHolder.getCount(); results in a NullPointerException. Log.d((menuHolder == null) + "", "MENUHOLDER NULL"); returns true at this point, when it had previously returned false.
just Do single change and will work
public class RestaurantMenuHolder{
private static RestaurantMenuHolder mInstance = null;
public static ArrayList<RestaurantMenuObject> restaurantMenu;
public static RestaurantMenuHolder getInstance(ArrayList<RestaurantMenuObject> restaurantMenu){
if(mInstance == null){
mInstance = new RestaurantMenuHolder(restaurantMenu);
}
return mInstance;
}
public static RestaurantMenuHolder getInstance(){
if(mInstance == null){
mInstance = new RestaurantMenuHolder(restaurantMenu);
}
return mInstance;
}
private RestaurantMenuHolder(ArrayList<RestaurantMenuObject> restaurantMenu){
this.restaurantMenu = restaurantMenu;
}
public static int getCount(){
return restaurantMenu.size();
}
}