This is a problem that is puzzling me and I wanted to get answers.
We have extended the Application and the class has variables that are to be accessed from different areas of the app. I think this was done to get a singleton implementation. The application has member objects of different classes.
public class DataApplication extends Application{
public InfoHelper mInfoHelper;
public void setHelper (InfoHelper infoHelper) {
mInfoHelper = infoHelper;
}
public InfoHelper getInfoHelper() {
if (mInfoHelper == null){
mInfoHelper = new InfoHelper();
}
return mInfoHelper;
}
// the InfoHelper class
public class InfoHelper{
public int trial = 10;
}
Now in an AsyncTask (which is started from an Activity A) updates the value of trial variable like this,
mDataApplication = (DataApplication) ((FragmentActivity)context).getApplication();
InfoHelper infoHelper = mDataApplication.getInfoHelper();
infoHelper.trial = 200;
when the AsyncTask is done, inside the Activity-A, I check the value of the trial variable using and InfoHelper variable that was created before calling the AsycTask,
// The below is created in onCreate() of Activiy-A, before the AsyncTask is started.
mInfoHelper = mScanApplication.getInfoHelper();
// After the Asyctask is done I would check the value of trial.
Log.d(TAG, "Test Value 1 --- "+ mInfoHelper.trial);
Log.d(TAG, "Test Value 2--- "+ mDataApplication.getInfoHelper().trial);
the result is,
Test Value 1 --- 10
Test Value 2--- 200
I was expecting the first result from the first Log statement but I did not expect the second log statement to get me the updated result. How did that happen? When updating in the AsyncTask, I created an object of InfoHelper and updated that object. How come it reflected everywhere. My friends said that it was because it was the same reference of the object and it does not matter if we create an object of the InfoHelper as it is the same memory location, if that is true then the question would be why the first Log statement showed me the old value?
My fundamentals are weak in this area and I appreciate may help in my quest to become better.
Note: If I create the mInfoHelper object again right before printing it I have the updated value which I was expecting to happen.
mInfoHelper = mScanApplication.getInfoHelper();
Log.d(TAG, "Test Value 1 --- "+ mInfoHelper.trial);
the result is,
Test Value 1 --- 200
Related
I am facing a very strange situation. I add an object to an arrayList in a loop, but it is replaced by the next object. Actually second item is duplicated. ( It replaces the first item as well as inserts another object to the ArrayList.)
This is my code. I have done the debugging and included the comments where needed. Could someone point out why this happens? I am taking the object details from the database and those are working as expected.
public class Serv
{
#Autowired
GrpHeader objGrpHeader;
#Autowired
CompPesoOutgoingMsg objMsg;
#Autowired
OutwardMessage objOutwardMessage;
public List<OutwardMessage> outgoingMessagesAsSingleTrx()
{
List<OutgoingMsg_Obj> trxList = myRepo.getTrx("5");
List<OutwardMessage> myTrxList = new ArrayList<>();
for (OutgoingMsg_Obj outgoingMsg : trxList)
{
BigDecimal trxAmt = outgoingMsg.getIntrBkSttlmAmt().getTrxn_amt();
trxAmt = (trxAmt).divide(new BigDecimal(100));
GrpHeader grpHeader = objGrpHeader;
CompPesoOutgoingMsg outMsg2 = objMsg;
OutwardMessage objOutwardMessage2 = objOutwardMessage;
outgoingMsg.setRmtInf(objRmtInf);
outgoingMsg.setPmtTpInf(objPmtTpInf);
outMsg2.setHeader(grpHeader);
outMsg2.setCdtTrfTxInf(Arrays.asList(outgoingMsg));
objOutwardMessage2.setObjMsg(outMsg2);
**//Here, Correct object details are printed**
log.info("outwardMsg 100 {} ", objOutwardMessage2);
//Add Item to the list
myTrxList.add(objOutwardMessage2);
for (OutwardMessage outwardMsgx : myTrxList)
{
//1. When this loop executed first time, first object details are printed
//2. When printed second time, first added object is no more. And second added object is there twice.
log.info("outwardMsg 101 {} ", outwardMsgx);
}
}
return myTrxList;
}
}
You have a single reference. By setting the objOutwardMessage2to objOutwardMessageyou are just changing the data inside the reference.
Since no new object is created for each iteration, the same objOutwardMessage2 value is getting replaced each time.
Try
OutwardMessage objOutwardMessage2 = new OutwardMessage();
and copy the value of objOutwardMessage to the newly created objOutwardMessage2.
This has become a Dorothy Dix as I found the root of the matter while I was composing this question. Nevertheless, I decided to post it because it had everyone in our office stumped and I could find nothing helpful in the google or stackoverflow searches. This is a good example of once you ask the right question, you may see the light.
While the title might sounds complicated, it is a really simple problem that seemed to have no answer. At the centre of this is an enum:
Status
public enum Status
{
INVALID ( "INVALID" ),
ISSUED ( "Issued" ),
CANCELLED ( "Cancelled");
private final String displayName;
private final static Map<String,Status> displayMap = new HashMap( 4 );
private Status( String display ){
this.displayName = display;
mapDisplayName( this.displayName, this );
}
public String getDisplayName(){
return displayName;
}
public static Status parseString( String statusStr ) {
return displayMap.get( statusStr );
}
private static void mapDisplayName( final String displayName, final Status state ){
displayMap.put( displayName, state );
}
}
The idea of course is to use the displayMap as a reverse-lookup. Nothing to do with the getDisplayName() method at all.
This enum's getDisplayName() call is used in a sub-panel to initialise a static array used with a combobox, like:
public class JPanelStatus extends javax.swing.JPanel {
private final String[] STATUS_LABELS = {
Status.ISSUED .getDisplayName(),
Status.CANCELLED .getDisplayName()
};
public JPanelStatus(){
initComponents();
:
jComboBoxStatus.setModel( new DefaultComboBoxModel<>( STATUS_LABELS ) );
:
}
:
}
Which is referenced in the main JPanel. When I view this JPanelStatus sub-panel in the Netbeans Designer, it works fine. As does the [Preview Design] function.
However when I load the main form, it fails and the exception show an initialisation failure:
java.lang.NoClassDefFoundError: Could not initialize class au.com.project.State
at au.com.project.client.JPanelStatus.<init>(JPanelStatus.java:35)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
... ... ...
The Netbeans IDE log added the following extra information :-p
INFO: Could not initialize class au.com.project.State
Through a process of elimination -- Commenting-out unrelated code -- I discovered the form will load once I comment-out the HashMap put() call in the State enum.
"That is interesting.", I say. It looked like a side-effect from the put(). And in away it is -- A small Spock which quickly gave me the same error from the command line without the JPanel and without Netbeans.
The error is caused by me, trying to use a HashMap from within the Enum constructor. It won't work as written.
So I changed the title to hit at the true problem -- Which is actually, how to use a HashMap to do a reverse-lookup for an enum?
The problem comes from how the HashMap is declared within the Status enum due to HOW enums are initialised.
The first thing in a Java Enum must be the list of values, here: "INVALID", "ISSUED", and "CANCELLED". The next thing everyone needs to know is that there is a secret Java stage that runs first during Object creation (Class or Enum). Init is dumb, is runs linearly through the declarative code first-come, first-served.
The first 3 x statements of an enum call the constructor -- That means the statement:
private final static Map<String,Status> displayMap = new HashMap( 4 );
Has NOT yet been executed, and displayMap is null. Also, a static { } block is executed in that same 1-2-3-... sequence and does not work either.
Unfortunately none of the Netbeans/Designer stack-trace or IDE log reported a NullPointerException -- The unit test does. Once you have a NPE, it focuses the mind. displayMap is uninitialised when the first constructor call is made.
Solution: The displayMap cannot be static final, because you may not initialise static members in a constructor. It must be initialised on the first call, using some variation of the example shown:
Status
public enum Status
{
INVALID ( "INVALID" ),
ISSUED ( "Issued" ),
CANCELLED ( "Cancelled");
private static Map<String,Status> displayMap;
private Status( String display ){
this.displayName = display;
mapDisplayName( this.displayName, this );
}
:
private static void mapDisplayName( final String displayName, final Status state ){
if( null == displayMap ){
displayMap = new HashMap( 7 );
}
displayMap.put( displayName, state );
}
}
And then it all runs quite smoothly.
Caveat:
Do NOT assign null in the displayMap declaration -- That was counter productive:
The if( null == displayMap ){...} block successfully assigns the HashMap during the first call to the Enum constructor.
After all the enum values declarations are processed.
Init will call any initialises for declared variables.
If displayMap = null; is declared it replaces the populated HashMap, with 3 x values, with a new empty HashMap. grrr
Possibly related question:
Reverse lookup for Java Enums with more than one value per key/constant? ... I felt that a HashMap would deliver the reverse-lookup of multiple strings a lot more easily.
I have 2 broadcastReceivers and 1 simple class
-simple class has 1 static variable
-when setting static variable simpleClas.time from broadcastReceiver1, the varibale is set to the correct value
-but when you try to access simpleClass.time from broadcastReceiver2, the static variable remains the same all the time, it remains in the init value. How is that thing possible?
At the end is a static
class simpleClass{
public static long time = 0;
}
class broadCastReceiver1 extends BroadcastReceiver{
#Override
public onReceive(){
//do some stuff and do an update of time variable
simpleClass.time = System.currentTimeMillis()/1000;
}
}
class broadCastReceiver2 extends BroadcastReceiver{
#Override
public onReceive(){
//do some stuff and only Read the variable time that was previously modified by broadCastReceiver1 and print the reading
System.out.println("new Value of time = " + simpleClass.time);
}
}
assuming that order of events is:
broadCastReceiver1
broadCastReceiver2
The value of time is read all the time to initial value 0;
for the broadCastReceiver2 the variable is all the time at value 0, but in the simpleClass class, time variable is updated!!!
you can do other operations in simpleClass with the new value of variable time.
Somehow broadCastReceiver2 sees only the init value of simpleClass.time.
How come? can anyone explain?
By default, broadCastReceivers run on a new process, therefore they can't share the same data.
You will need to change your manifest definitions to make them run on the same process by adding android:process="string" to the broadcast reciever definition
I was wondering if it is possible to reset the value of a variable from another class. For example I have this variable in a HillClimber (hc) class:
public int ballWeight = 200;
What I want to do is run a simulation of a game with the ball weighting at this value. When it is finished I want to set the value to 201 from another class and begin the simulation again, and after that increase to 202 and start another and so on. My problem is that every time I restart the simulation the ballWeight variable is reset to 200. I have tried using a setter method in the HillClimber class:
public int setBallWeight(int ballWeight) {
return this.ballWeight = ballWeight;
}
and called it from another class at the end of a simulation:
hc.setBallWeight(hc.ballWeight+1);
but this does not seem to work as the variables stored value is not changed. Does anyone know how I can do this so the stored value of ballWeight will be increased by 1 each time a simulation ends? Or is this even possible? Thanks.
Usually in a POJO you have what are called a getter and a setter method for every variable of the object. In your case:
public class HillClimber{
private int ballWeight;
public HillClimber(){
this.ballWeight = 200;
}
public void setBallWeight(int ballWeight){
this.ballWeight = ballWeight;
}
public int getBallWeight(){
return this.ballWeight;
}
}
In this way you can access the variable ballWeight via get and set method. You don't access it directly like in hc.ballWeight, which is possible but is a bad practice, and prevent this access type declaring your variable as private (meaning that only the class in which it is declared can directly access it).
To fullfill your request of adding one at every run of the game you can therefore call
hc.setBallWeight(++hc.getBallWeight()); //Equivalent to hc.setBallWeight(hc.getBallWeight() + 1);
I usually don't use this approach if the class isn't automatically generated (as in an Hibernate context), but instead declare another method in the HillClimber class
public void incrementBallWeight(int ballWeightToAdd){
this.ballWeight += ballweiGhtToAdd; //Equivalent to this.ballWeight = this.ballWeight + ballweiGhtToAdd;
}
or if I always need to add only one to my variable
public void incrementBallWeight(){
this.ballWeight++;
}
and then simply call incrementBallWeight after every game run.
NB: to have this working you will have to use always the same instance of HillClimber. In your main
public class Game{
private HillClimber hc = new HillClimber(); //Create the instance and sets ballWeight to 200
public static void main(String[] args){
playGame();
hc.incrementBallWeight(); //ballWeight == 201
playAnotherGame()
hc.incrementBallWeight(); //ballWeight == 202 -> Always the same instance of HillClimber (hc)
.
.
.
}
}
EDIT
I think your problem is greater than that. You are asking to save the state of a variable ( meaning that this value should be available also if you turn off and on your pc) without using a permanent storage. This is simply unachievable.
You should rethink your program (and I mean java program, not a "game run") to not stop after every game run. You can do this in different ways: via Swing GUI, via user input from stdin and so on. If you want some help on this topic, we need to know more of your code (maybe putting the whole of it is best).
OR you can use a file to store your value, which is not as difficult as you think. (Also).
somehow my mind is not working and mild fever didn't help.
I have the following code, batteryLevel here shows the correct value - 50.
public class AlarmEventService extends Service {
static String batteryLevel;
...
int level = intent.getIntExtra("level", 0);
batteryLevel = String.valueOf(level);
Log.i(APP_TAG, batteryLevel);
}
Why in my outside call when I get value of AlarmEventService.batteryLevel the value is null?
public class AlarmEventReceiverWake extends BroadcastReceiver {
...
Log.i(APP_TAG, "Battery Level " + AlarmEventService.batteryLevel);
}
From what you have presented of the code, there is no reason why it shouldnt work as expected. It may be possibile that:
Another variable named batteryLevel may be declared locally, thereby not assigning the value to the global version.
the value of batteryLevel may be reset after your initial call.
Make sure that the statement:
batteryLevel = String.valueOf(level);
is actually being called before
Log.i(APP_TAG, "Battery Level " + AlarmEventService.batteryLevel);