I'm using a singleton class SingletonA for my resources and I have a service ServiceS who uses the resources.
public class SingletonA {
private static SingletonA ourInstance = new SingletonA();
public static SingletonA getInstance() { return ourInstance; }
private SingletonA () {}
String resources;
synchronized public void importSomething() {
resources = "I have some value now";
}
}
public class ServiceS extends Handler {
private static ServiceS ourInstance = new ServiceS();
public static ServiceS getInstance() { return ourInstance; }
private ServiceS () {}
SingletonA sa = SingletonA.getInstance();
public void printResources() {
println(sa.resources);
}
}
public class MyActivity extends Activity {
SingletonA sa = SingletonA.getInstance();
#override
protected void onCreateBundle savedInstanceState) {
super.onCreate(savedInstanceState);
sa.importSomthing();
ServiceS.printResources();
}
}
-> In ServicesS class, sa value is null -> sa.printResources() causes NPE
However, since I add one more sa = SingletonA.getInstance(); into ServiceS.printResources() like this:
public void printResources() {
sa = SingletonA.getInstance();
println(sa);
}
-> It worked: sa != null and resources = "I have some value now".
Can someone explain for me why sa in ServiceS still null ? Thanks,
As the comment of Buddy:
it's due to static initialization order. The static ServiceS.ourService is initialized before SingletonA.ourInstance.
See here for more information on static initialization order. But the easy solution would be to just call SingletonA.getInstance() when necessary (vs caching in a member variable). Or to lazily initialize ServiceS.ourInstance inside getInstance
Related
I'm trying to write unit testing for the following snippet.
class ABC {
int getMyValue(final Activity activity) {
if(MyClass.getInstance(activity).getValue() == 1) return 10;
else return 20;
}
void doSomething() {
}
}
I've tried something like this to test the doSomething function.
mABC = new ABC();
public void test_doSomething() {
doReturn(20).when(mABC).getMyValue();
//validate
}
How can I test getMyValue similarly? I would like to assert when the value is 1 it's returning me 10 and in all other cases, it's returning me 20.
I'm doing this in my android application. Is there any existing framework that can help me do this?
EDIT:
MyClass looks something like this
public class MyClass {
private static Context mContext;
public static getInstance(Context context) {
mContext = context;
return new MyClass();
}
private MyClass() {}
public void getDreamValue() {
Settings.Secure.getInt(mContext.getContentResolver(), "dream_val", -1);
}
}
You might consider modifying your MyClass as follows.
public class MyClass {
private static Context mContext;
// Create a private variable that holds the instance.
private Myclass instance;
public static getInstance(Context context) {
mContext = context;
if (instance == null)
instance = new MyClass(); // Assign the instance here
return instance;
}
private MyClass() {}
public void getDreamValue() {
Settings.Secure.getInt(mContext.getContentResolver(), "dream_val", -1);
}
}
Now, as you are using Robolectric, you can set the instance value to a mock as follows in your test class.
#RunWith(RobolectricTestRunner.class)
public class ABCTest {
#Mock
MyClass mockInstance;
#Mock
Context mockContext;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
// Set the mock instance for MyClass
ReflectionHelpers.setStaticField(MyClass.class, "instance", mockInstance);
}
#Test
public void testWhen1() {
doReturn(1).when(mockInstance).getDreamValue();
Assert.assertEquals(10, new ABC().getMyValue());
}
#Test
public void testWhenNot1() {
doReturn(2).when(mockInstance).getDreamValue();
Assert.assertEquals(20, new ABC().getMyValue());
}
#After
public void tearDown() {
// Set the instance to null again to enable further tests to run
ReflectionHelpers.setStaticField(MyClass.class, "instance", null);
}
}
I hope that helps.
Note: It looks like you are trying to provide a singleton instance of MyClass. Hence, you really should not create a new instance of MyClass in the getInstance function. I avoided creating a new instance each time, using the null check in my code.
I'm learning about MVC. My project has tons of variables. So I made a new class for them called MainVariables.
public class MainVariables {
private String mPictureDirectory;
private String mNameOfThePictureFile;
private String mFullPathPicture;
private double mLongitude;
private double mLatitude;
private String mAddress;
private String mCity;
private String mState;
private String mCountry;
private String mPostalCode;
private String mKnownName;
private String mDescription;
private String mSolicitationType;
...
...
The rest is composed by automatic getters and setters for each variable.
I'm having a problem accessing and casting those variables across my application.
I tried accessing it by casting the following in other files:
private MainVariables mMainVariables;
The above code throws the error Attempt to invoke virtual method on a null object reference
Then I tried the following:
private MainVariables mMainVariables = new MainVariables();
Now, this does work. Only in the file it's using though. For Example, I set variables from within the "SolicitationFragment" and when I try to access it on "PostFragment", I get an empty result.
That's because I'm having to initialize MainVariables on each file.
How can I get around this and be able to access my variables globally?
Make the variables static, or final if you're not going to change them. This way you don't have to create a new instance and can call MainVariables.mPictureDirectory immediately
public class MainVariables {
public static String mPictureDirectory;
}
Another option is a singleton pattern, this way you create only one instance of an object and still can use getters and setters
public class MainVariables {
private static MainVariables mInstance = null;
private String mString;
private MainVariables(){
mString = "Hello";
}
public static MainVariables getInstance(){
if(mInstance == null)
{
synchronized (MainVariables.class) {
if (mInstance== null) {
mInstance= new MainVariables();
}
}
return mInstance;
}
public String getString(){
return this.mString;
}
public void setString(String value){
mString = value;
}
}
In your MainActivity you can declare a field
MainVariables mainVariables = MainVariables.getInstance()
and call
mainVariables.[METHOD] from basically anywhere in your MainActivity
Create a class extending your Application class and create a method to get instance of MainVariables:
AppController.java
public class AppController extends Application {
private MainVariables mMainVariables;
private static AppController mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized AppController getInstance() {
return mInstance;
}
public MainVariables getMainVariables() {
if (mMainVariables == null) {
mMainVariables = new MainVariables();
}
return mMainVariables;
}
}
MainVariables.java
public class MainVariables {
private String string;
public String getString(){
return this.string;
}
public void setString(String string){
this.string = string;
}
}
USE:
// SET VALUE
AppController.getInstance().getMainVariables().setString("Hello Android");
// GET VALUE
String str = AppController.getInstance().getMainVariables().getString();
FYI, You have to add AppController class under application name in your AndroidManifest.xml file.
<application
android:name=".AppController">
</application>
Hope this will help~
I am trying to create a global variable where it can be accessed from any any where including Activity, Fragment and other custom classes.
public class Global extends Application {
private static Global sInstance;
private String mSharedInfoFileName; //can be any custom object
public static Global getInstance() { return sInstance; }
#Override
public void onCreate() {
super.onCreate();
sInstance = this;
initialize();
}
private void initialize() { mSharedInfoFileName = "globalInfo"; }
public String getFileName() { return mSharedInfoFileName; }
private Global() { }
}
and try to use it like this
public class MyFragment extends android.support.v4.app.Fragment {
String s = Global.getInstance().getFileName();
}
even after declaring it in class scope still gave same error
private static Global mGlobal = Global.getInstance();
which give me Attempt to invoice... .Global.getFileName()' on a null object reference. What am I missing?
Thank you
Change this method to static :
public static String getFileName() {
return mSharedInfoFileName;
}
and call it like below:
Global.getFileName();
The mSharedInfoFileName variable has to be static too :
private static String mSharedInfoFileName;
Friends In My Application , i want to use text box value in
all other activity without passing any argument. how it's possible? Anyone
know these give me a example, thanks in advance. by Nallendiran.S
There are a few different ways you can achieve what you are asking for.
1.) Extend the application class and instantiate your controller and model objects there.
public class FavoriteColorsApplication extends Application {
private static FavoriteColorsApplication application;
private FavoriteColorsService service;
public FavoriteColorsApplication getInstance() {
return application;
}
#Override
public void onCreate() {
super.onCreate();
application = this;
application.initialize();
}
private void initialize() {
service = new FavoriteColorsService();
}
public FavoriteColorsService getService() {
return service;
}
}
Then you can call the your singleton from your custom Application object at any time:
public class FavoriteColorsActivity extends Activity {
private FavoriteColorsService service = null;
private ArrayAdapter<String> adapter;
private List<String> favoriteColors = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_favorite_colors);
service = ((FavoriteColorsApplication) getApplication()).getService();
favoriteColors = service.findAllColors();
ListView lv = (ListView) findViewById(R.id.favoriteColorsListView);
adapter = new ArrayAdapter<String>(this, R.layout.favorite_colors_list_item,
favoriteColors);
lv.setAdapter(adapter);
}
2.) You can have your controller just create a singleton instance of itself:
public class Controller {
private static final String TAG = "Controller";
private static sController sController;
private Dao mDao;
private Controller() {
mDao = new Dao();
}
public static Controller create() {
if (sController == null) {
sController = new Controller();
}
return sController;
}
}
Then you can just call the create method from any Activity or Fragment and it will create a new controller if one doesn't already exist, otherwise it will return the preexisting controller.
3.) Finally, there is a slick framework created at Square which provides you dependency injection within Android. It is called Dagger. I won't go into how to use it here, but it is very slick if you need that sort of thing.
I hope I gave enough detail in regards to how you can do what you are hoping for.
Create it static type and than you can get it where you want.
Private TextVeiw txtvw;
Public static String myText="";
myText=txtvw.getText();
Access this variable with class name in which it defined.
MyActivity.myString
I'm trying to track down a new null pointer exception which is appearing in my ACRA logs and which I can't reproduce. Here's the relevant code:
public class MyApplication extends Application {
public void onCreate() {
DataManager.instance().initializeData(this);
}
}
public class DataManager {
private static DataManger instance = new DataManger();
private List<DataModel> dataModels;
private List<I_Callback> callbacks = new ArrayList<I_Callback>();
private boolean isInitialized = false;
private DataManager(){}
public static DataManager instance() {
return instance;
}
public void initializeData(Context context) {
new DataManagerInitializer().execute(context);
}
public void setDataModels(List<DataModel> models) {
dataModels = models;
}
public void synchronized registerInitializeCallbacks(I_Callback callback) {
if (isInitialized) {
callback.executeCallback();
} else {
callbacks.add(callback);
}
}
public void synchronized setInitialized() {
isInitialized = true;
for (I_Callback callback:callbacks) {
callback.executeCallback();
}
callbacks.clear();
}
}
public class DataManagerInitializer extends AsyncTask<Context, Void, Void>{
protected Void doInBackground(Context... contexts){
List<DataModel> dataModels = new ArrayList<DataModel>();
/*various code to create DataModel objects and add to dataModels list*/
DataManager.instance().setDataModels(dataModels);
return null;
}
protected void onPostExecute(Void result) {
DataManager.instance().setInitialized();
}
}
public class ActivityA extends Activity implements I_Callback{
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.graphical_layout);
DataManager.instance().registerInitializeCallbacks(this);
}
public void executeCallback() {
/* wire up button to call Activity B */
}
}
public class ActivityB extends Activity {
public void onCreate(Bundle savedInstanceState) {
List<DataModel> dataModels = DataManager.instance().getDataModels();
/* The following line of code throws a null pointer exception
in the stack trace*/
for (int i=0; i < dataModels.size(); i++){
/* do something with the data model */
}
}
}
To break down the above more simply, the application is launched which kicks off the initializion of the data manager singleton. ActivityA, the main activity, launches and waits for the data manager to complete initialization before allowing any actions, wiring up any events, etc. From ActivityA, its not possible to get to ActivityB without the call back method executing and ActivityB is only reachable from ActivityA. The only way for the list of data models to be null in the DataManager is for it to not have been initialized, but I'm struggling to see how this is possible. Any suggestions on how my null pointer may have occurred?
private static DataManger instance = new DataManger();
...
public static DataManager instance() {
return instance;
}
Is where the problem is. So your instance variable is getting garbage collected. As it is instantiated when it is declared, it is not being appropriately re-instantiated. So, try this instead:
private static DataManger instance = null;
...
public static DataManager instance() {
if (instance == null){
instance = new DataManager();
}
return instance;
}
This will ensure the call to instance() (usually called getInstance() but this is only convention), will return a valid single instance of the datamanager. Try to avoid instantiating global variables with their declaration, to avoid this specific problem.
Let's assume that:
you are interacting with the Activity B
press the home button:
start playing with other apps (consuming memory)
at some point the so needs memory and it's gonna start garbage collecting objects, included your "instance".
If that happens when you launch your app the framework will resume the activity B and the npe will happen.
You need to re-create the instance (in the activity B) if it is null.