Issues with garbage collection and Picasso - java

I am trying to set an ImageView in a Google Maps Marker's InfoWindow and have copied the code from this answer pretty exactly, except that my InfoWindowAdapter isn't an anonymous inner class (it's just an inner class of the activity). This was working before, but for some reason it has stopped working - the onSuccess method in the Callback doesn't get called, so the InfoWindow only displays the image the second time it is opened.
Looking at the logs for Picasso I'm getting messages similar to Main canceled [R20]+374ms target got garbage collected. I figured this might be because the Callback is getting gc'd, and tried making it final, and also saving the object in a class field (neither of these worked, although maybe I was doing it wrong?)
What could be happening here, and how can I fix it? Is that target in the error message referring to the Callback, or could it be referring to the marker that gets passed as an argument to the Callback's constructor?
Another odd thing is that sometimes the images are loaded correctly when the InfoWindow is first opened - I'm trying to find out why, but basically I have a lot of markers and whether their images load correctly or not on the first go seems to be inconsistent. There are some (the majority) that never seem to load correctly when the InfoWindow is first opened.
[edit] This was after a bunch of code was merged into that activity, so could it be a memory thing? (there's more processing done now than there was when I wasn't having this problem)
[edit 2] I'm having exactly the same issue with Glide!! Probably garbage collection?

I'm not familiar with that answer, but Target could be gc'ed when you do not hold strong reference to that.
It's because Picasso holds Target instance with weak reference.
You should hold Target instance somewhere outside of Picasso.
Check this issue: https://github.com/square/picasso/issues/352

Solved it, the garbage collection message was actually referencing the ImageView, not the Callback object. Ensuring that the ImageView object isn't garbage collected will correct this (e.g. by saving the ImageView in a field in the class, or even the activity that my class was nested in)

I was doing the same mistake, here was the solution that worked :
My previous code :
picasso.load(url).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
After this I just created a new variable for Target object :
final Target target=new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
imageView.setBackground(new BitmapDrawable(mContext.getResources(), bitmap));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
then I used the target object later in my code :
picasso.load(url).into( target);

Related

Why cache data is not deleting on app destroy

When I try using the code bellow in the onDestroy() method in MainActivity it seams it does not work. What I am doing wrong?
Code:
#Override
protected void onDestroy() {
super.onDestroy();
deleteCacheData();
}
public void deleteCacheData() {
File cacheDir = this.getCacheDir();
File[] files = cacheDir.listFiles();
if (files != null) {
for (File file : files) {
file.delete();
}
}
}
There is two cases with your code:
You can't reliably depends on the case that onDestroy() method will be called. Because there is no such guarantee that it will always be called by the system. Here the excerpt from onDestroy() documentation:
protected void onDestroy ()
Perform any final cleanup before an activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it), or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here. This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
You should call your deleteCacheData() before calling the super.onDestroy(). So, this is incorrect:
#Override
protected void onDestroy() {
super.onDestroy();
deleteCacheData();
}
this is the correct one:
#Override
protected void onDestroy() {
deleteCacheData();
super.onDestroy();
}
If you using Windows OS
Because In your Windows task manaegr one Process is Running when the android studio start or build run or stop named
Java Jmt first stop it then your can directly delete the both build folder not need to clear cache

Listening to class reload in Java

For performance reasons, I have a class that stores a Map whose key is a Class<?> and its value is function of that class's fields. The map is populated during code execution according to the type of the calling object. The above is a generalization/simplification
public class Cache {
private static final Map<Class<?>, String> fieldsList = ...;
//Synchronization omitted for brevity
public String getHqlFor(Class<?> entity){
if (!fieldsList.containsKey(entity))
fieldsList.put(entity,createHql(entity));
return fieldsList.get(entity);
}
}
During development, thanks to the help of Jrebel, I often make modifications to classes by changing entire properties or just their names. I can continue development just fine. However, if I already put a value into the cache it will be stale forever.
What I am asking here is if it is possible to intercept the event that a class in the classpath has changed. Very broad... But my specific problem is very simple: since I have such a need only during development, I just want to wipe that cache in case any class in my classpath changes.
How can I accomplish this? I don't need to do anything special than intercepting the event and simply wiping the cache
JRebel has a plugin API that you can use to trigger code on class reloads. The tutorial complete with example application and plugin available here: https://manuals.zeroturnaround.com/jrebel/advanced/custom.html
The JRebel plugin is a self-contained jar built against the JRebel SDK, which is attached to the running application via the JVM argument -Drebel.plugins=/path/to/my-plugin.jar. The JRebel agent attached to the application will load and start plugins from this argument.
If the application is not started with the JRebel agent, the plugin is simply not loaded.
In your example you want to register a ClassEventListener that will clear the Cache.fieldsList map. As it is a private field, you need to access it via reflection or add a get/clear method via a ClassBytecodeProcessor
public class MyPlugin implements Plugin {
void preinit() {
ReloaderFactory.getInstance().addClassReloadListener(new ClassEventListenerAdapter(0) {
#Override
public void onClassEvent(int eventType, Class<?> klass) throws Exception {
Cache.clear();
}
});
}
// ... other methods ...
}
And to clear the map
public class CacheCBP extends JavassistClassBytecodeProcessor {
public void process(ClassPool cp, ClassLoader cl, CtClass ctClass) {
ctClass.addMethod(CtMethod.make("public static void clear() { fieldsList.clear(); }", ctClass));
}
}
However a better option is to only clear/recalculate the single class entry on class reload if possible. The example didn't display whether the info computed from one class depended on superclass infos, but if this is true, the JRebel SDK has methods to register a reload listener on the class hierarchy as well.
There is an existing class ClassValue which already does the job for you:
public class Cache {
private final ClassValue<String> backend = new ClassValue<String>() {
#Override
protected String computeValue(Class<?> entity) {
return createHql(entity);
}
};
public String getHqlFor(Class<?> entity){
return backend.get(entity);
}
}
When you call get, it will call computeValue if this is the first call for this specific Class argument or return the already existing value otherwise. It does already care thread safety and for allowing classes to get garbage collected. You don’t need to know when class unloading actually happens.

Google Play Game Services - Listener null pointer exception

I am still fairly new to Android and I am trying to implement Achievements inside my app. I basically want to replicate the achievements implemented in the "Type-a-Number Challenge" sample app given on the Google play developer site here.
I have a first activity that contains the methods and classes to handle the achievements, and a second activity where I have the variables that would be forwarded to the first activity for "processing". I copied the code that I believed was necessary for doing this, but I am always getting a null pointer exception when calling the listener inside the second class.
Here is my listener in the second activity:
public interface Listener {
public void onEnteredScore(int score);
}
Listener mListener = null;
public void setListener(Listener l) {
mListener = l;
}
The null pointer exception is flagged here when I call the listener as such (where mRequestedScore is different to 0):
mListener.onEnteredScore(mRequestedScore);
The first activity's class implements the second activity listener like this:
public class FirstActivity extends BaseGameActivity
implements SecondActivity.Listener
And includes the onEnteredScore method as such
#Override
public void onEnteredScore(int requestedScore) {
checkForAchievements(requestedScore);
pushAccomplishments();
}
I am not entirely sure if the error appears because the listener is expecting a click or some action by the user, or the "linkage" is not being established properly between both activities.
I looked around for similar issues but haven't found anything yet.
Apologies if the mistake is obvious.
Thanks in advance for any help provided.
Your "linkage" isn't established, hence the null.
If you want to pass data between Activities (not fragments), you'll need to use the Intent framework - see How do I pass data between Activities in Android application?
The Interface method that you are following in the Type a Number Challenge is useful for passing data between Fragments and the parent Activity. That is what it is being used for in that example. You don't appear to be using Fragments.
For achievements, you are probably better served using a class attached to your FirstActivity. That class can then implement your Listener interface (if the interface is even useful at that point). Using a separate activity is far more heavyweight than is required.

How to destroy Application listener object in libgdx

I am using libgdx, my code is like this,
public class MyActivity extends AndroidApplication {
public void onCreate(Bundle savedInstanceState){
//here i have initialized my application listener object
initialize(new MyApplicationListener(),false);
//other code
}
}
//MyApplicationListener.java
public class MyApplicationListener implements ApplicationListener {
public void create(){}
public void render(){}
public void dispose() {
//diposing all resources
}
}
Now my question is when iam finishing my MyActivity.java, the dispose()-method in MyApplicationListener.java was not getting called. Therefore my game was affecting from OOM exception.I have also tried to call the dispose method manually, but few objects were remaining as it is in the heap.
To start from scratch, open the gdx-setup-ui.jar from the downloaded libGDx zip folder. Export the created three project folders to Eclipse. Use it as reference to find out how to run it. See instructions for details on how to use this jar file.

Android - Java - Access private variable in Main-Activity from another instanced class

I've been thinking for hours about this problem now without finding a solution. Still I think I'm just overlooking some very simple things.
My program is (mainly) supposed to record and playback audio, so I got one Main-Activity which contains all the functions with interactivity to the user and I got one class I called 'AudioHandler' to manage all the audio stuff in the background.
The Main-Activity uses an instance of AudioHandler.
Within the AudioHandler-class I got an OnCompletionListener, to notice when playback of the recorded audio-file has finished.
The problem is: When playback has finished - and the OnCompletionListener gets called, I want to change an ImageView (Turn the pause-button into a play-button) in the Main-Activity.
How can I access the ImageView in the Main-Activity from the AudioHandler-Instance?
...without making the ImageView-Variable public.
Method that calls play from the AudioHandler in the Main-Activity:
public State playRecording() {
//change play-button to stop-button
iPlay.setImageResource(R.drawable.stop_button_active);
//start or resume playback of the recorded Audio
ah.play();
//Return that the program is in playing-mode
return State.PLAYING;
}
play-function in AudioHandler
public void play() {
try {
mPlayer.start();
} catch (IllegalArgumentException e) {
Log.d("MEDIA_PLAYER", e.getMessage());
e.printStackTrace();
} catch (IllegalStateException e) {
Log.d("MEDIA_PLAYER", e.getMessage());
e.printStackTrace();
}
//add listener to notice when the end of the audio record has been reached
mPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
//should somehow change the ImageView 'iPlay' in the Main-Activity when reaching this point.
}
});
}
Any help is appreciated :)
Marco
If you need to gain access to a variable, that variable should be either package-accessible or public. Or, even better, you should have an encapsulating method. Something like:
// On the main class:
public ImageView getIPlay(){
return iPlay;
}
private static MainActivity instance;
public MainActivity getInstance(){
return instance;
}
/** Either on the constructor or the 'OnCreate' method, you should add: */
instance = this;
Now you can access the ImageView from any Activity or class with:
MainActivity.getInstance().getIPlay();
It's that simple, really. You can go through a lot of other solutions, from using reflection through AOP or any kind of things. But it's just making the issue more complex. Try creating the setter method.
Your question is about object encapsulation.
When you define an instance variable as private, you are saying that only that object and members of that class can access the variable. This is a good thing because it protects you from accidentally changing data you did not want to. This is also why we have getters and setters.
So in your class you have something I imagine looks like this
public class Main {
... some code here
private ImageView myView;
... more code here
what you need to do is add the following methods to your Main class
public ImageView getView() {
return myView;
}
and
public void setView(ImageView a) {
myView = a;
}
so now when you want to access the ImageView from another class, you just call something like Main.getView() and you'll have it.
Now if this doesn't answer your question, it's because you didn't design your app too thoughtfully (so it seems) but luckily I won't be the kind of responder who tells you to uproot everything you have done and start over.
It sounds like you're working with an Android app and your issue is to communicate between activities.
This is why Android has something called Intents. You can send an Intent from one activity to another to carry data. So in this case you would send an Intent from one activity to the main class that would tell the main class to change the picture in the imageview. I won't lie, I suck at using intents but there are many wonderful tutorials online that will show you how to do this.
Another option would be to create a RemoteView of your layout that has the play/pause button and access it from the other activity, RemoteView has a built in function to change the bitmap of a remote imageview (again, see the Android Developer Documentation for RemoteView for more on this)
I'm sorry I couldn't give you some actual code, I'm not confident enough in my abilities on these topics but I'm 100% confident that one of the three methods I just listed will answer your question.
You could create a public wrapper method within your main Activity that toggles the ImageView between Pause and Play.
Or, you could pass the the ImageView to the AudioHandler (via the constructor?) and just manipulate it there.

Categories