Is something wrong with this construct in Android?
class A extends Activity {
private Object myObject = new Object();
#Override
protected void onCreate(Bundle savedInstanceState) {
//myObject = new Object();
}
}
Because at some point(s) later I get (sometimes, not reproducible yet) exceptions because myObject is null. I don't know if it's because I have to initialize in onCreate.
Edit: Additional details:
The actual class of myObject is List<Object> (Where Object is a domain specific type)
At some point later in the activity I'm storing myObject as a static field of a "Parameter passer" class and starting other Activity (because I'm avoiding to implement Parcelable. If this is good or bad practice should not be discussed here, unless that's causing my error). In the other Activity I pick up myObject. There it's (sometimes) null.
Edit 2: I don't understand why this object becomes null if I'm storing a reference to it as static field of my parameter passer class (a standalone, dedicated class). That's how garbage collection works, right, it just removes when the objects are not referenced anymore. So since I have a static reference this object should not be removed. According to this thoughts, if they are correct, the problem should be somewhere else.
When you start a new activity your old one goes on the block for possible garbage collection (including any classes instantiated in it, including your parameter passer class), so your object is not necessarily going to be available (which is why you see an intermittent failure.).
I see two option:
1) Pass it along in the bundle with your intent that starts the new activity. As you were trying to avoid this, probably not your best choice.
2) Extend the Application class and store the object in there.
EDIT
I think the accepted answer to this SO Question might fix your issue (and explain what is actually happening).
No. That code is just fine. You can create objects in the constructor.
You may want to check a previous question about it Instance variable initialization in java and the section 3.2.4. Field Defaults and Initializers which basically states that the first case:
private Object myObject = new Object();
is identical to an initialization in the class constructor. (NOTICE onCreate is NOT the constructor).
So, myObject should never be null, except in the case the "new Object()" instruction failed, generating an exception.
Isn't this possible your code is changing the contents of myObject later on the code?
Related
I'm in the process of completely redesigning my Android app. Before, EVERYTHING was in the same class.
So I tried to redraw everything so that the code is clearer apart Admob than the doc advice to put in the Main thread, I separate the different part of my code in class. So I used two technique: I created a songleton that contains variables that I want to have access to constantly,and I call my classes via weak reference.
Here is what it looks like:
For example, the UIManager class that needs to update the game's IU have a weak reference looks like this:
private static SoftReference<UIManager> ManageUI;
static{ManageUI= new SoftReference<>(null);}
static UIManager get()
{
if(ManageUI.get()==null)
{
ManageUI= new SoftReference<>(new UIManager());
}
return ManageUI.get();
}
GameManager Manager=GameManager.getInstance();
to be able to use the findviewbyid for example I place in method argument the main class that is the mainthread
the singleton that contains all my variables that I want to have permanent access to looks like this:
private GameManager()
{}
/** Holder */
private static class Manager
{
/** Instance unique non préinitialisée */
private final static GameManager instance = new GameManager();
}
/** Point d'accès pour l'instance unique du singleton */
public static GameManager getInstance()
{
return Manager.instance;
}
To separate all in different class, I pass argument to my method so I can call au stuff belong to Activity like that:
(My main class is called GamePlay)
void OpenGlobalScene(GamePlay activity)
{
Manager.OnTitle=false;
if (!checkLayout(activity,R.id.globalscene)) {
LayoutInflater(activity,9, true);
LinearLayout GamePlan = (LinearLayout) activity.findViewById(R.id.globalscene);
GamePlan.setAlpha(Manager.AlphaBord);
}
}
For now, I have not noticed any problems except a few slownesses on old android phone 4.4.2.
Also compared to my old code were EVERYTHING was in the same class, it's much easier to change pieces of code (going to the inapp billing V3 was simpler since everything was in one class that I call like the others with weak referencre)
My questions are:
-What are the problems that such a structure might pose?
I had also chosen that structure to not load or leave in memory things that are not useful
-How are chance that Android will erase from memory an action in progress called with weak reference?
-As you can see I pass the activity has argument to the method, sometimes I pass it from a method to another. Is that fact can cause some trouble?
Thank you for your help.
Check Dagger2 is better than the clasic singleton https://developer.android.com/training/dependency-injection/dagger-android?hl=es-419
thanks for your answer and your tips. I'am gonna check this out.
Anyone else know something about consequences on memory when using weak references ?
I need to pass objects to my fragments in order to initialize them.
Currently I am doing this with ((MyActivity)getActivity()).getX(). (direct access to the activity)
However, I would like to pass the required objects as parameter.
I definitely do not want to add parcelable objects to the bundle, since they require an excessive amount of useless boilerplate code. My goal is to reduce complexity, not increasing it.
And I do not want to add serializable objects to the bundle, since they are slow and cause an unnecessary overhead.
What is the best way to pass objects to fragments?
Any ideas to solve the problem in a more convenient way?
I definitely do not want to add parcelable objects to the bundle, since they require an excessive amount of useless boilerplate code. My goal is to reduce complexity, not increasing it.
You write this code in your model classes which is separated from your activities and fragments. There is no complexity in implementing Parcelable. And it is a common way to pass objects to a Fragment.
Any other solutions? Well, you still can do this ((MyActivity)getActivity()).getX() as long as your fragment is attached to your activity. In this case it is even faster than Parcelable because there is no serialization at all.
Other ways would be to write objects to database, pass their ids to a Fragment and then use a query to retrieve objects.
You can also use SharedPreferences, but that's rarely used. For this you will need to convert your object to String.
You can do the Android way: Parcelable.
You can serialize then.
You can do the poor way : static
You can do the retained way: Create a Fragment with setRetainInstance(true) and save your objects references.
I understand you don't want to use parcelable / serializable objects to a Bundle. I also agree with you since I got lazy, and my phone app is getting complicated.
Here's what you can do, and it works reliably.
Make a public method in your Fragment class, sample below.
Have the Activity, preferably no other place, call that public method. Remember Activity is always present, Fragments and Adapters may not due to its lifecycle.
The timing of the call is crucial if you're not using Bundles. I have used it without any problems.
The advantage of this technique is that it is fast, especially compared to Bundles. Many developers do not consider this however.
Note: If you are using simple fundamental Java types, do use Bundles! As suggested by Google.
Sample code:
public class MyFragment extends Fragment {
...
public void setList(final ArrayList<String> arrayList) {
...
}
In the Activity:
MyFragment fragment1 = MyFragment.newInstance(<parameters>);
fragment1.setList( arrayList );
Do you need to change the properties once they have been set on the fragment? If not, you can use setArguments(Bundle). If it is a fairly light object you can even skip implementing Parcelable and just set each property individually. The advantage is that the arguments are preserved upon orientation change. The disadvantage is that you need to call this method before attaching your fragment, hence it is not very useful once the fragment is in use.
It's way too late for my answer, but if someone else is wondering. The recommended way is to use Parcelable or Serializable, but you can always do something like this:
public class ObjectManager {
private static final String TAG = "ObjectManager";
private static ObjectManager instance;
private Object currentObject;
public static ObjectManager getInstance() {
if (instance == null)
instance = new ObjectManager();
return instance;
}
public Object getCurrentObject() {
return currentObject;
}
public void setCurrentObject(Object object) {
this.currentObject = object;
}
}
And then use it: where you needed as long as your app is running
//Use on the object you would like to save
ObjectManager.getInstance().setCurrentObject(object);
//Get the instance from pretty much everywhere
Object = ObjectManager.getInstance().getCurrentObject();
You can use it always, but it will be most likely to be useful, if you pass objects bigger than the Bundle max size.
I use a third-party API (JAudioTagger) and I would like to start an activity with an object of this API (AudioFile).
The problem is this object does not implement Parcelable or Serializable.
What is the best way to do this ?
EDIT
Google's answer : http://developer.android.com/guide/faq/framework.html
You have a few options, none of which are easy or perfect (depending on the object and use-case).
Create a custom object that extends the AudioFile object and implements either Serializable or Parcelable - which can be tedious, but not impossible. With custom objects like this, the documentation may be lacking for this option.
Someone mentioned static as an option. This can generally work well, except you are talking about Android. Android can destroy and re-create the JVM for your app at any time when it is not visible to the user. So, if this AudioFile class is playing in the background in your app, strange behavior could occur if Android decides to kill the process.
You can use an object in the Application class, but is potentially has the same issues as #2.
Use SharedPreferences and some kind of index system to retrieve the file.
You can create a class of your own, which would accept an object of type AudioFile, and populate fields with its values.
public class MyAudioFile implements Parcelable{
private File file;
//other fields...
public MyAudioFile(AudioFile audioFile){
this.file = audioFile.getFile();
//populate other fields
}
//parcelable stuff
}
Let's assume I have a class MainActivity.
This contains a number of objects stored in fields, such as instances of Player, Enemy, Level, etc. Each of these objects needs to be able to refer to every other object.
What is the best way to go about this?
Make these fields static, and refer to them accordingly, i.e.
MainActivity.player.setHealth(0);
Create getter methods for each field, and simply pass each object a reference to MainActivity, so that they can call these getter methods, i.e.
mainActivity.getPlayer().setHealth(0);
Pass each object a reference to every other object, and store these references in fields within each object, so that they can be referred to directly, i.e.
player.setHealth(0);
Not a real answer but just to give you some tips.
Your Player should be like so:
public class Player
{
private static Player _player = null;
int _health;
...
public static Player getInstance()
{
if (_player == null)
_player = new Player(...);
return _player;
}
public void increaseHealth(int amount)
{
_health += amount;
}
}
Then in any part of your application when you need a Player you can do:
Player p = Player.getInstance();
and you will get the same player all the time. You can do a similar thing with your level class as only 1 level will be active at any one time.
However the Enemy class will need a different approach. I would make a List inside the Level class and get at them like so:
Level l = Level.getInstance();
List<Enemy> enemiesOnLevel = l.getEnemies();
// do something with them
Have a look in the Android docs here: http://developer.android.com/guide/faq/framework.html#3. There is also the possibility to serialize your object into primitive datatypes and pass those within your Intent to the new Activity.
A couple more options to share objects between activities are to use parcable, which I think is probably the highest performance method, and shared preferences.
In my app I used to learn (the little I know about android programming), I used gson to serialize the object to json, then stored it in shared preferences in activity A , then recreated it from shared preferences in activity B, and then stored it again.
i'm developing an app that, when i press a button, downloads a XML file, put the xml data in a custom object and passes it to a second activity.
The problem is that something is wrong: when a call the startActivity() function the app crashes with a Runtime error.
My code is:
public void onClickBtn1(View view)
{
final ProgressDialog dlg = ProgressDialog.show( this, "Data wait", "Waiting data from the site ..");
// Thread to wait data
Thread th = new Thread() {
public void run() {
// Download and parse xml data
final DatiSport dati = new DatiSport();
boolean ret = dati.download();
dlg.dismiss();
// check result
if (ret==true)
{
// -- Ok
handlerUI.post( new Runnable() {
public void run() {
Intent intSec = new Intent(AICSActivity.this, SportActivity.class);
intSec.putExtra("datiSport", dati);
startActivity(intSec);
}
});
}
else
{
The app crashes on the startActivity() call. When i break on the startActivity() line i'm not able to look the variable called 'dati' and i guess this is not well defined.
If i substitute dati with 12345, there is not problem.
Which is the problem with dati ?
--- Changed here cause I'm not enabled to reply myself ---
Ok guys. Thanks for replies!
My guess is that i need to re-design the app data.
My first attempt was: download the XML text and accommodate the data into a (rather) complex object. This object contain a list of championships, each of them contains a list of categories, each of them contains a list of teams.
The problem is that, since the Serializable is not working, the implementation of Parcelable is too complex and it should generate almost the same data as the xml file.
I'm wondering if it should be easier passing directly the xml text to other activities (they have to show in turn the list of championships, then the categories of a selected championship, then the list of teams for a selected category...)
Any other idea?
Extract from this Answer :
Serializable is a standard Java interface. You simply mark a class Serializable by implenting the interface, and Java will automatically serialize it in certain situations.
Parcelable is an Android specific interface where you implement the serialization yourself. It was created to be far more efficient that Serializable, and to get around some problems with the default Java serialization scheme.
Extract from this answer :
Seeing Parcelable might have triggered the question, why is Android
not using the built-in Java serialization mechanism? It turns out that
the Android team came to the conclusion that the serialization in Java
is far too slow to satisfy Android’s interprocess-communication
requirements. So the team built the Parcelable solution. The
Parcelable approach requires that you explicitly serialize the members
of your class, but in the end, you get a much faster serialization of
your objects.
After seeing some answer on StackOverFlow, i come to conclusion that Parcelable is optimized than Serialization in android.
How to make class to Parcelable ?? (Check out this, this & this tutorials)
Use a Serializable or Parcelable when passing objects
You need a class to implement the Serializable class
//to pass :
intent.putExtra("MyClass", obj);
// to retrieve object in second Activity
getIntent().getSerializableExtra("MyClass");
Your class would look something like this;
import java.io.Serializable;
#SuppressWarnings("serial") //with this annotation we are going to hide compiler warning
public class MyClass implements Serializable {
public Deneme(Object obj){
this.obj= obj;
}
private Object obj;
}
The Intent class has a method as
putExtra(String name, int value)
thats why it works when you put 12345 at the place of "value", but there is no overloaded version of putExtra that takes "DatiSport" object.
You must ensure that "DatiSport" is Serializable or Parcelable.
See below for more info-
http://developer.android.com/reference/android/content/Intent.html#putExtra%28java.lang.String,%20java.io.Serializable%29
How to send an object from one Android Activity to another using Intents?
How to pass an object from one activity to another on Android
Make your class implement Serializable interface and then pass object instances in intent extra.
To pass data from one Activity to another :
intent.putExtra("ClassName", obj);
To retrieve data in the Second Activity from the First Activity :
getIntent().getSerializableExtra("ClassName");
I found the problem !!!
An internal class were not implementing Serializable!
In the dump window i saw the internal object 'ioe' that said that there was a NotSerializable error and the name of the class!!
Now i checked each internal class and the data is passed to the next activity.
Thanks a lot