ArrayList initialized/accessed using Singleton class - java

I am using an ArrayList in my application.
I would like to know the exact procedure to initialize my ArrayList from a Singleton class.
The data will be used in some other Activities.
Can anybody help to know about Singleton class?

Here is how to create your singleton class :
public class YourSingleton {
private static YourSingleton mInstance;
private ArrayList<String> list = null;
public static YourSingleton getInstance() {
if(mInstance == null)
mInstance = new YourSingleton();
return mInstance;
}
private YourSingleton() {
list = new ArrayList<String>();
}
// retrieve array from anywhere
public ArrayList<String> getArray() {
return this.list;
}
//Add element to array
public void addToArray(String value) {
list.add(value);
}
}
Anywhere you need to call your arrayList just do :
YourSingleton.getInstance().getArray();
To add elements to array use :
YourSingleton.getInstance().addToArray("first value");
or
YourSingleton.getInstance().getArray().add("any value");

Please look at the following wikipedia-artikle:
https://en.wikipedia.org/wiki/Singleton_pattern
But keep in mind that singletons are 'global state' and make your sourcecode harder to test. There are lot of people saying: "singletons are evil'

I think you need something like this.
public class SingletonClass {
private static ArrayList<String> strArray;
private static SingletonClass singleton;
private SingletonClass(){}
public static synchronized SingletonClass getConnectionInstance(ArrayList<String> strArray){
if (singleton == null) {
singleton = new SingletonClass();
}
this.strArray = strArray;
return singleton;
}
}

Related

return a long list of constant in Java

I have a class in which 100+ consts are defined
public class Codes {
static final public ErrorCode ISSUE_1 = new ErrorCode(XXX);
static final public ErrorCode ISSUE_2 = new ErrorCode(XXX);
// 100+ error codes
}
Now I need to define a Codes.getAll() to return all the ErrorCode defined in the class.
Is there any elegant way to implement it?
using reflection could be a solution;
List<ErrorCode> list = new ArrayList<>();
for (Field field : Codes.class.getFields()) {
if (field.getType() == ErrorCode.class) {
list.add((ErrorCode) field.get(null));
}
}

Sonar - Store a copy - Mutable members should not be stored or returned directly

I have a list which is a private member in my class.
I have used getter and setter to get and set the values.
SOnar throws an error - Mutable members should not be stored or returned directly.
For example: ABC and DEF are two classes.
class ABC{
private List<DEF> defList;
public List<DEF> getDefList() { return defList; }
public void setDefList(List<DEF> defList) { this.defList = defList; }
After lot of googling and searching, I have understood that the getter can be changed as follows:
public List<DEF> getDefList() { return new ArrayList<>(defList); }
When i try to use setter similarly,
public void setDefList(List<DEF> defList) { this.defList.addAll(defList); }
then the variable starts showing
'private field 'defList' is never assigned.
May I know the correct way to do when it is a list, (a list of another class)
Note: Both the answers from Prasad Karunagoda and Leo Aso works. I cant mark both as accepted answer. So having a note here
The warning is because you did not give the field an initial value. This is how you should implement the code to ensure immutability using java.util.Collections.
class ABC {
private List<DEF> defList = Collections.emptyList();
public List<DEF> getDefList() {
return defList;
}
public void setDefList(List<DEF> defList) {
// defensively copy, then make immutable
defList = new ArrayList<>(defList);
this.defList = Collections.unmodifiableList(defList);
}
I believe it is better not to add additional restrictions (immutability) to the List returned from the getter. If you do that, clients using your List will not be able sort it for example.
So, my recommended approach is this:
public class ABC {
private List<DEF> defList = new ArrayList<>();
public List<DEF> getDefList() {
return new ArrayList<>(defList);
}
public void setDefList(List<DEF> defList) {
if (defList == null)
throw new IllegalArgumentException("Parameter defList is null");
this.defList.clear();
this.defList.addAll(defList);
}
}
From design perspective, an even better API for ABC class would be:
public List<DEF> getDefList()
public void clearDefList()
public void addAllDefs(List<DEF> defs) // Or method name appendDefs

Singleton class Arraylist is empty

I have created a singleton ArrayList class in android which is following.
public class SingletonArrayList {
private static SingletonArrayList mInstance;
private ArrayList<String> userNameList = null;
public static SingletonArrayList getInstance() {
if(mInstance == null)
mInstance = new SingletonArrayList();
return mInstance;
}
private SingletonArrayList() {
userNameList = new ArrayList<String>();
}
// retrieve array from anywhere
public ArrayList<String> getArray() {
return this.userNameList;
}
//Add element to array
public void addToArray(String value) {
userNameList.add(value);
}
}
I'm calling this singleton ArrayList in my activity2. It's working fine there(it contains data!).
activty2:
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, SingletonArrayList.getInstance().getArray());
But in activtiy1 it's returing an empty list.
activity1:
Log.i("single",SingletonArrayList.getInstance().getArray().toString());
if(SingletonArrayList.getInstance().getArray().contains(username1)) {
Toast.makeText(getApplicationContext(), "Username already Exists. Please select a different username", Toast.LENGTH_LONG).show();
return;
}
Basically, the problem is that ArrayList is coming empty in one activity and contains data in another activity. Any solutions?

Singleton returning two instances

I'm trying to use a singleton (PhotoStorage) to provide an arrayList of Photo objects, but it seems that the PhotoStorage instance is not behaving as a singleton (two instances).
I am using dagger to inject this singleton into a class named PhotoInteractor. The objectGraph seems A-OK up to this point.
The same PhotoInteractor instance is used in three fragments in a viewpager. These fragments are all instantiated at runtime:
RecentFragment:
HistoryFragment:
Notice how the instance #4067 of the PhotoInteractor is the same for both fragments.
Also:
mAppContext#4093: same
photoStorage#4094: same
When I click a photo object (grid image) from RecentFragment, the PhotoStorage.addPhoto(url) method is called. This correctly adds the photo object to the photoStorage instance array (4094). That much is OK.
Problem:
When I close the applicaton, it is intended that the PhotoStorage.savePhotosToFile method serialzes this arrayList object into JSON on the filesystem.
The following method is called from the same PhotoInteractor instance:
#Override
public void savePhotos(){
photoStorage.get(mAppContext).savePhotosToFile();
}
When I debug the application, the PhotoStorage.get method already has a singleton instance, but what appears to be a 2nd instance!
//Singleton enforcement
public static PhotoStorage get(Context c){
if(sPhotoStorage == null){
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
return sPhotoStorage;
}
This means that the ArrayList of photos will always be empty since it is a new instance of PhotoStorage. Iā€™m not sure where it is instantiating itself from.
Edit - Added PhotoStorage.class:
public class PhotoStorage{
private ArrayList<Photo> mPhotos;
private PhotoJSONer mSerializer;
private static PhotoStorage sPhotoStorage;
private static Context mAppContext;
private static final String PHOTOS_DATABASE = "photos.json";
public static final String TAG = PhotoStorage.class.getSimpleName();
public PhotoStorage(Context appContext){
mSerializer = new PhotoJSONer(appContext, PHOTOS_DATABASE);
try{
mPhotos = mSerializer.loadPhotos();
}catch(Exception e){
mPhotos = new ArrayList<Photo>();
}
}
//Singleton enforcement
public static PhotoStorage get(Context c){
if(sPhotoStorage == null){
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
return sPhotoStorage;
}
public ArrayList<Photo> getPhotos(){
return mPhotos;
}
public Photo getPhoto(String url){
for(Photo p: mPhotos){
if(p.getUrl() == url)
return p;
}
return null;
}
public void deletePhoto(String url){
Log.i(TAG, "deleted photo");
mPhotos.remove(url);
}
public void addPhoto(Photo photo){
Log.i(TAG, "added photo");
mPhotos.add(photo);
}
public boolean savePhotosToFile(){
try{
mSerializer.savePhotos(mPhotos);
return true;
}catch (Exception e){
return false;
}
}
}
You are not executing Singletton pattern in the correct way,
The Singleton design pattern addresses all of these concerns. With the Singleton design pattern you can:
Ensure that only one instance of a class is created
Provide a global point of access to the object
In your case, we don't see PhotoStorage class but this call comes from an instance, what is not allowed by Singletton pattern:
photoStorage.get(mAppContext).savePhotosToFile();
//ā†‘ instance call WRONG!!
This line works, but as your get method is static is not a good practice as Karakuri pointed and also breaks the Singletton pattern definition.
public static PhotoStorage get(Context c){
SOLUTION
To make photoStorage.get() invalid and create a correct Singletton pattern you must:
declare the getInstance() method static in the class (here PhotoStorage)
hide default constructor to avoid instances of the class
create private constructors if necessary
call getInstance() it in a static way:
class PhotoStorage {
// hidding default constructor
private PhotoStorage () {};
// creating your own constructor but private!!!
private PhotoStorage(Context appContext){
mSerializer = new PhotoJSONer(appContext, PHOTOS_DATABASE);
try{
mPhotos = mSerializer.loadPhotos();
}catch(Exception e){
mPhotos = new ArrayList<Photo>();
}
}
//Singleton enforcement
public synchronized static PhotoStorage get(Context c){
if(sPhotoStorage == null){
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
return sPhotoStorage;
}
}
Then you can make static call from everywhere the class scope allows:
#Override
public void savePhotos(){
PhotoStorage.get(mAppContext).savePhotosToFile();
//ā†‘ static call CORRECT!!
}
UPDATE: if your app have several threads and singleton getInstance requests may overlapp, there is a double check syncronized singletton pattern you can apply:
//Singleton enforcement
public synchronized static PhotoStorage get(Context c){
if(sPhotoStorage == null){
synchronized(PhotoStorage.class) {
if(sPhotoStorage == null) {
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
}
}
}

How can I call a constructor after statements?

I have this calss KeywordFilter. I want the constrcutor that accepts a keyword to create a List, add the keyword to the list and then call the constructor with the list parameter. How can I do that? because as I know, calling the constructor should be the first call.
public class KeywordFilter implements Filter {
private List<String> filteringKeywords;
public KeywordFilter(List<String> filteringKeywords) {
this.filteringKeywords = filteringKeywords;
}
public KeywordFilter(String keyword) {
List<String> filteringKeywords = new ArrayList<String>();
filteringKeywords.add(keyword);
this(filteringKeywords);//This makes a compilation error
}
}
Create your list directly :
public KeywordFilter(String keyword) {
this(new ArrayList<String>(Arrays.asList(keyword)));
}
In general, you can put the code that constructs the list in a separate function (preferably, but not necessarily, static):
private static List<String> makeFilterKeywords(String keyword) {
List<String> filteringKeywords = new ArrayList<String>();
filteringKeywords.add(keyword);
return filteringKeywords;
}
public KeywordFilter(String keyword) {
this(makeFilterKeywords(keyword));
}
This should help
public KeywordFilter(String keyword) {
this(Collections.singletonList(keyword));
}
public KeywordFilter(List<String> filteringKeywords) {
this.filteringKeywords = filteringKeywords;
}
public KeywordFilter(String keyword) {
this(((List<String>)Arrays.asList(keyword));
}
The simplest and shorten solution
public KeywordFilter(String keyword) {
this(Arrays.asList(keyword));
}
But this returns a fixed-size list backed by the specified array, without add() or remove() support.
This is applicable also to varargs
public KeywordFilter(String... keywords) {
this(Arrays.asList(keywords));
}
You can create the ArrayList with the KeyWord and then have another method append the new list to existing list (which you have created with only the keyword in the constructor).
Something like this:
public class KeywordFilter implements Filter {
private List<String> filteringKeywords;
public KeywordFilter(String keyword) { //Consctructor
filteringKeywords = new ArrayList<String>();
filteringKeywords.add(keyword);
}
public void appendList(List<String> filteringKeywords) { //new method
filteringKeywords.addAll(filteringKeywords);
}
}

Categories

Resources