I have the following snippet of code:
ArrayList<GameObject> gameObjectList = new ArrayList<GameObject>();
public void init(){
for(int i=0; i<10; i++) {
loadedOjectList.add(new GameObject());
}
}
Now say I want to leave the activity or maybe load a new level in my game. Would writing loadedObjectList.clear() be sufficient to make the 10 objects be eligible for garbage collection? I had something similar to this and whenever I would progress through the levels my game would start slowing down because I'm guessing the objects still exist somewhere. Any ideas?
Of Course the objects will be Garbage Collected because the references get nullified. So the Objects are good to be collected...
Related
I use the ViewHolder pattern as described by James Montemagno
https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/
Considering the objects called by FindViewById, when should I call dispose? What is safe and correct to do. I should do it at some moment:
https://developer.xamarin.com/guides/android/advanced_topics/garbage_collection/
To shorten object lifetime, Java.Lang.Object.Dispose() should be invoked. TThis will manually "sever" the connection on the object between the
two VMs by freeing the global reference, thus allowing the objects to
be collected faster.
ListView is pretty old(Android 1.0). It was tightly coupled and not built with performance in mind. Lots of hacks were needed to keep it relevant. RecyclerView fills that gap.
https://www.youtube.com/watch?v=LqBlYJTfLP4
As for when you should call Dispose(), RecyclerView should handle this basic functionality via the LayoutManager. On the ViewHolder side, you can follow a basic Dispose pattern:
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
if(ItemView != null)
{
ItemView.Click -= HandleClick;
}
_listener = null; //Listener might just be a simple Action<int> like in this example: https://github.com/xamarin/monodroid-samples/blob/master/android5.0/RecyclerViewer/RecyclerViewer/MainActivity.cs#L111
}
In which you only care about Disposing the base and any Event Handlers you set up. However if your RecyclerView uses a bit of images in the View it's inflating, you will want to ensure you properly manage those resources as the Android GC will not be able to collect these items as they will be referenced by Xamarin.Android's GC(And they will be a small reference like a few bytes worth). Somehow you have to sever the link between the two GCs so it can be eligible for collection. You can read more about the GC Algorithm here: Xamarin Android garbage collection algorithm and the cause here: https://developer.xamarin.com/guides/cross-platform/deployment,_testing,_and_metrics/memory_perf_best_practices/#Use_Weak_References_to_Prevent_Immortal_Objects
To do that, we can sever the relationship via a couple ways:
MyObject = null;
MyObject.Dispose();
Either way should mark these items eligible for GC. In the case of Drawable you may also want to set the respective ImageView or object that the Drawable is being set in to null such as SetBackgroundDrawable/etc.
TLDR; Use RecyclerView, and remember to manage any Bitmap/Drawable resources appropriately.
I create little sprites of sheeps on the top of my screen, then they should go down and after crossing bottom line they disappear. Problem is that when they are going across the screen it is very noticable that sometimes they lag. For milliseconds but its possible to see it. It happens absolutely randomly. They change their position with Gdx.graphics.getDeltaTime();
public void update (float deltaTime) {
updateMotionX(deltaTime);
updateMotionY(deltaTime);
// Move to new position
position.x += velocity.x * deltaTime;
position.y += velocity.y * deltaTime;
}
Here is the code of spawing them:
private Sheep spawnSheep(){
Sheep sheep = new Sheep();
sheep.dimension.set(dimension);
// select random cloud image
sheep.setRegion(regSheeps.random());
// position
Vector2 pos = new Vector2();
pos.x = -0.19f; // position after end of level
pos.y = 5;
sheep.position.set(pos);
//speed
Vector2 speed = new Vector2();
speed.y = 3.5f;
sheep.terminalVelocity.set(speed);
speed.y *= -1;
sheep.velocity.set(speed);
return sheep;
}
Maybe somebody already had that problem, i have no idea why it happens,
The lagging is most likely caused by garbage collection because you're continuously allocating memory within your game loop.
You want to avoid calling new whenever possible in the game loop, and if you do call new you want to reuse those objects whenever possible.
Look at pools in libgdx
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/utils/Pool.html
If you're returning an object from a method, such as a Vector2, then create a static instance and reuse that object for return values. Be aware that this is not thread safe and calling the method again will overwrite the value from the first call.
If I was you I'd search for any instances of the word 'new' in your code, and make sure none of them are called frequently within the game loop. You also want to be aware of calling methods that will create instances of objects. Simple things like converting an integer to a string will waste memory, as well as more obvious things like creating a copy of an array.
You should find this useful for tracking memory allocation.
https://visualvm.java.net/
I am creating a game which generates many sprites at some point such as bullets.
I am using object pooling which is generic pool in andengine.
But the problem I am facing is it lags when the object are created for the first time. As for the first time , when the object is attached to scene. It lags when I am attaching 100 sprites at a time.
So I was thinking if its possible to load all the required objects and load it to the pool while in loading scene.
for now my code is as follows..
bullets = bullet_pool.obtainPoolItem();
if(!bullets.hasParent())
{
Presentscene.attachChild(bullets);
}
Please suggest me some ideas.
Can I load a 100 objects (sprite) in the pool before the game, So that It wont lag in the middle of the game to create objects fresh for the pool.
You can pre-load the amount of bullets you want during the loading sequence of the game. Something like this:
private void preloadBullets(){
Bullet[] bulletArr = new Bullet[1000];
// Create the new bullets
for (int i=0; i<1000; ++i){
bulletArr[i] = bullet_pool.obtainPoolItem();
}
// Recycle all bullets
for (int i=0; i<1000; ++i){
bullet_pool.recyclePoolItem(bulletArr[i]);
}
}
This way, if you call preloadBullets before your game runs, you'll have 1,000 bullets recycled in the pool for fast item obtaining.
Being the efficiency freak that I am (as I'm sure lots of you all are as well), I've wondered this for a while and just thought of posing this question:
Two scenarios, possibly two different answers.
If I'm looping through a list of items and updating a bunch of EditTexts in a LinearLayout as such, what are the pros/cons of these two methods:
1)
for (int i = 0; i < itemList.size(); i++) {
((TextView)findViewById(itemList.get(i).getId())).setText(itemList.getText());
((TextView)findViewById(itemList.get(i).getId())).setColor(itemList.getColor());
}
2)
TextView tv;
for (int i = 0; i < itemList.size(); i++) {
tv = ((TextView)findViewById(itemList.get(i).getId()));
tv.setText(itemList.getText());
tv.setColor(itemList.getColor());
}
I think the underlying question is how efficient is "findViewById"? This may be picky, I think 2) is the better solution. Thanks!
With your second option you save:
- A call to findViewById()
- A call to itemList.get(i)
- A call to [itemList.get(i)] getId()
Also, note that in a for loop usually going backward is a little bit faster (more optimized) than going forward (because i < value translates to i-value < 0, which is more expensive than i > 0).
This is not picky at all. 2nd option is without doubt the better one.
1
for (int i = 0; i < itemList.size(); i++) {
((TextView)findViewById(itemList.get(i).getId())).setText(itemList.getText());
((TextView)findViewById(itemList.get(i).getId())).setColor(itemList.getColor());
}
Looks clean, but isn't. If you are working with one and the same textview, absolutely do not call findViewById more than once.
2
TextView tv;
for (int i = 0; i < itemList.size(); i++) {
tv = ((TextView)findViewById(itemList.get(i).getId()));
tv.setText(itemList.getText());
tv.setColor(itemList.getColor());
}
This is the better option, because it only calls findViewById once. It's a little less readable, though.
You could also consider a 3rd option
for (int i = 0; i < itemList.size(); i++) {
TextView tv = ((TextView)findViewById(itemList.get(i).getId()));
tv.setText(itemList.getText());
tv.setColor(itemList.getColor());
}
This keeps everything in the loop (easier to read, imo) without notably sacrificing efficiency. I prefer the 3rd, but the 2nd is a good pick as well.
A google employee Dianne Hackborn has answered a very similar question here.
She says that you should avoid using findViewByid repetitevely whenever you can.
I think without doubt the second option is better.
Not only you save the cost of calling findViewById one extra time (ok at the cost of one extra local variable)
but the code is also much more readable.
You should use new RecyclerView if possible now. Combined with LinearLayoutManager it'll allow you achieve the same, but you'll be forced to use ViewHolder pattern.
If you go with your ListView, you should also implement ViewHolder. findViewById is definitely not efficient, so you need to prevent too many calls to it.
Second way is better, because the cost of findViewById() is acceptable in static UI layouts. However, since getView() is called frequently, the usage of findViewById() should be kept to minimum.
The second is for sure less expensive by 50%.
But I would prefer #TimCastelijns 3rd method because he is dumping the view reference at the end of the loop.
In the first method, you use findViewById twice.
In the second method, you use it once and save a reference to it, which saves 50% off of the resource usage.
I preferred #TimCastelijns, because he saves it as a local variable, which will be dumped, therefore saving resources.
I want to pass an array from one Activity to another Activity,for example I need to pass an array from image_view Activity to Blackimage Activity.Please give solution to this problem in Android.
Using a Singleton is probably a bad idea here, especially given Android's kill-happy lifecycle and the high likelihood of leaking Context if you do it wrong. Android has a very simple and powerful built-in message-passing capability on Intents - use it! You should pass the array as an Extra on the Intent, either using the built-in putExtra methods that take Arrays of various Java builtins, or by making sure your array is made of Serializable objects and passing it to the Intent's putExtra method that takes any serializable object. Then you can simply get the extra out of the Intent in the second Activity's onCreate(), no messy singletons necessary.
Read up on making a singleton class, then you can call singleton.setArray(myArray) in one Activity, and singleton.getArray() in the next.
If they are both in the same application.
In addition to the singleton class, you might want to look at using the Android SharedPreferences to save/get any data to either save your settings or prevent loss of data if interrupted.
Also adding android:configChanges="keyboardHidden|orientation"> into the AndroidManifest will prevent your app from losing data if you rotate screens/slide open keyboard.
SharedPref Example
String m_myData[];
Boolean m_myBoolData[];
public static void saveSettings()
{
SharedPreferences.Editor editor = m_SharedPreferences.edit();
for(int ix = 0; ix < m_myData[].length; ix++
{
editor.putString("myKey" + ix, m_myData[ix]);
editor.putBoolean("myKey" + ix, m_myBoolData[ix])
}
}
public static void getSettings()
{
for(int ix = 0; ix < m_myData[].length; ix++
{
m_myData[ix] = m_SharedPreferences.getString("myKey" + ix, false);
m_myBoolData[ix] = m_SharedPreferences.getBoolean("myKey" + ix, false )
}
}
Passing it through the activity will be the best performance choice, as if you use preferenes or the Intent to pass on the array you will have to loop over the array to persist it and recover it from the Intent or Preferences.
Using the Application will allow you to pass on the array, but doing so, just like with a singletone will force you to handle it instance being destroyed as if you wont do it it wont be GCed even after the two activities died since the application will still keep a reference to it.