Plugin Development: IResourceChangeListener called more than once on just one change - eclipse

I am using IResourceChangeListener to listen to changes in resource.
my code is:
public void createPartControl(Composite parent) {
// Graph will hold all other objects
graph = new Graph(parent, SWT.NONE);
// create the graph with the right nodes and connections.
init();
//listen to changes in the resource.
workspace = ResourcesPlugin.getWorkspace();
resourceChangeListener = new IResourceChangeListener() {
public void resourceChanged(IResourceChangeEvent event) {
//IResourceDelta delta = event.getDelta();
Display.getDefault().asyncExec(new Runnable() {
public void run() {
init();
System.out.println("Something changed!");
}
});
}
};
workspace.addResourceChangeListener(resourceChangeListener);
}
public void dispose() {
workspace.removeResourceChangeListener(resourceChangeListener);
}
But, when I am doing just one change in the resource, and save it, the listener called more than once! (usually twice, but sometimes even 6 times!!!)
I tried to use delta to see if it's called in the project,folder,file..
and I didn't saw differences between the calls (maybe I didn't used it properly).
I found this link, but I didn't found there solution to solve my problem
IResourceChangeListener being called twice with one change
How can I fix my code?
Thanks.

There is nothing you can do in the listener code to change how many resource change events you get. It depends entirely on how the code making the changes is doing the change.
You may find that IResourceDelta.getKind and IResourceDelta.getFlags return different values in the events. Also something getMovedFromPath and getMovedToPath for rename or move operations.
If it is your code doing the change you can use a WorkspaceJob or WorkspaceModifyOperation to do atomic changes to the workspace which will also reduce the number of resource change events.
You might also want to check that your old listeners are being removed correctly.

Related

What could cause PlayerPrefs to not save a string?

I have the below code. What could possibly make this not work? Other PlayerPrefs seem to work fine. The log always shows that it restores "" and yet it always saves my actual text.
EDIT:
I've just discovered that my "OnDisable" code is being called before "Start". I didn't really think that was possible, but that's the problem. So I guess my question is changing a bit...
EDIT 2:
OnDisable was being called before Start because another "Awake" function was disabling this object which apparently immediately runs OnDisable.
public InputField ModuleList;
void Start()
{
ModuleList.text = PlayerPrefs.GetString("ModuleSet", "");
Debug.Log("Restoring " + PlayerPrefs.GetString("ModuleSet", ""));
}
public void OnDisable()
{
Debug.Log("Saving " + ModuleList.text);
PlayerPrefs.SetString("ModuleSet", ModuleList.text);
}
call
PlayerPrefs.Save();
for saving data
Make sure you do not disable you GO before Start() method being called

Unity3D: Custom UnityEvent AddListener not firing

I have my own custom UnityEvent and am trying to add a listener.
I have used AddListener on numerous other UI objects, such as buttons, dropdowns, toggles, etc. so I understand the process. However, when I Invoke my UnityEvent, it simply doesn't fire.
I'm receiving no error messages, and after doing reading and research, everything looks correct. So, not sure what to do further.
This is an object that emits when it's rotated.
This is the basics of my code:
using UnityEngine.Events;
public class Rotator: MonoBehaviour
{
public UnityEvent OnRotate;
int angle = 0;
int newAngle = 0;
void Start()
{
OnRotate = new UnityEvent();
}
void Update()
{
newAngle = (int)transform.rotation.eulersAngles.z;
if (newAngle != angle)
{
print ("Actual Instance ID: " + GetInstanceID());
print ("Invoking!");
OnRotate.Invoke();
angle = newAngle;
}
}
}
and
public class Owner: MonoBehaviour
{
public Rotator rotator;
void Start()
{
print ("Rotator Instance ID: " + rotator.GetInstanceID());
rotator.OnRotate.AddListener(
() => UpdateRotation()
);
}
void UpdateRotation()
{
print ("Invoked!");
}
}
When the Rotator has it's angle changed, I get this in the console:
Actual Instance ID: 11234
Rotator Instance ID: 11234
Invoking!
The instance ID is to make sure I'm working with the same objects and not going in circles for nothing. They match, so I'm listening to the object that's firing.
However, the listener isn't firing. I've tried different combinations with delegates, etc. but it's all the same. No errors. It just doesn't invoke.
Obviously, I'm doing something wrong, but what is it?
Thanks for any help.
Somehow your answered your new edited version of the question with exactly the code you previously provided in the First Version of your Question!
As I tried to tell you ... if you anywhere in your code do OnRotate = new UnityEvent() of course you thereby erase any persistent callbacks and any runtime callbacks added before that moment!
In short
Simply leave it as
public UnityEvent OnRotate;
and you don't even have to think about it anymore.
For understanding why it also works if you put it in Awake please simply have a look at the Order of Execution for Event Functions
→ First Awake and OnEnabled is called for every GameObject/Component. Then all Start methods are called as soon as the GameObject/Component is active.
Within each of these blocks (Awake + OnEnable) and (Start) the order of execution between different component types is not guaranteed unless you explicitly configure it via the Script Execution Order Settings where you could define that Owner is simply run before Rotator .. then having both in Start would also work again.
Why does it also work if you do it on the public field?
→ Because this field is serialized. That means it is initialized automatically in the Inspector and then stored together with the Scene or prefab asset including any persistent callbacks.
And then Later Unity re-uses the serialized Version of the field so actually you can completely remove the new UnityEvent(); since it doesn't have any effect on a serialized field! It will always be initialized automatically anyway!
Ok, I found out what the issue was.
My question now is "why?".
I changed my code from:
public UnityEvent OnRotate;
void Start() {
OnRotate = new UnityEvent();
}
to
public UnityEvent OnRotate = new UnityEvent();
void Start() {
}
And now it works.
Although, now that I think about it, Awake() is the method where they all fire before initialization, whereas Start() is when the object is created. So the Start() of the Rotator is probably getting called after the Owner is adding a listener.

StartCoroutine get error NullReferenceException

I have two cs files, Main.cs and Menu.cs. On OnGUI event which is in Main.cs file I call method from Menu.cs.
private void OnGUI()
{
Menu menu=new Menu();
menu.Create_Menu();
}
And in Menu.cs.
public void Create_Menu ()
{
StartCoroutine(LoadCar());
}
private IEnumerator LoadCar()
{
//Load Object
Download download;
download=new Download();
GameObject go = null;
yield return StartCoroutine(LoadAsset("http://aleko-pc/3dobjects?key=1017&objecttype=1","car13",(x)=>{go = x;}));
}
I get error NullReferenceException
UnityEngine.MonoBehaviour.StartCoroutine (IEnumerator routine)
If I copy private IEnumerator LoadCar() method in Main.cs class, and call from OnGUI it works.
Maybe I do not understant working area of Coroutines, Can any body help me?
First of all the OnGUI method is called every frame and I don't think you want to download the assets every frame.
Second, you need to make sure Menu is derived from MonoBehviour and added to the view hierarchy.
A better approach would be to add Menu as a component to a GameObject (maybe the same that has the Main script attached) and call Create_Menu on the Start method of Menu.

GWT Google Map Api V3 - broken when changing it

It is working fine for me for the first time it is rendered.
But, If I change anything over the map or recreate it, its broken.
Here is the screen shot for how it looks.
Here is a screen shot after I changed the results per page value.
This is my code.
#UiField DivElement mapPanel;
private GoogleMap googleMap;
public void loadAllMarkers(final List<LatLng> markers)
{
if(!markers.isEmpty())
{
final MapOptions options = MapOptions.create();
options.setMapTypeId(MapTypeId.ROADMAP);
googleMap = GoogleMap.create(mapPanel, options);
final LatLngBounds latLngBounds = LatLngBounds.create();
for(LatLng latLng : markers)
{
final MarkerOptions markerOptions = MarkerOptions.create();
markerOptions.setPosition(latLng);
markerOptions.setMap(googleMap);
final Marker marker = Marker.create(markerOptions);
latLngBounds.extend(marker.getPosition());
}
googleMap.setCenter(latLngBounds.getCenter());
googleMap.fitBounds(latLngBounds);
}
}
I am calling the loadAllMarkers() method whenever new results needs to be loaded.
Can someone point out what I am doing wrong here.
This seems to come from the following (which I pulled from a Google+ Community - GWT Maps V3 API):
Brandon DonnelsonMar 5, 2013
I've had this happen and forgotten why it is, but
mapwidget.triggerResize() will reset the tiles. This seems to happen
when the onAttach occurs and animation exists meaning that the div
started smaller and increases in side, but the map has already
attached. At the end of the animation, the map doesn't auto resize.
I'v been meaning to investigate auto resize but I haven't had time to
attack it yet.
In your case, you would call googleMap.triggerResize() after you finish your changes. this solved my problem when I had the exact same issue. I know it's a little late, but I hope it helps!
Another answer there was to extend the Map widget with the following:
#Override
protected void onAttach() {
super.onAttach();
Timer timer = new Timer() {
#Override
public void run() {
resize();
}
};
timer.schedule(5);
}
/*
* This method is called to fix the Map loading issue when opening
* multiple instances of maps in different tabs
* Triggers a resize event to be consumed by google api in order to resize view
* after attach.
*
*/
public void resize() {
LatLng center = this.getCenter();
MapHandlerRegistration.trigger(this, MapEventType.RESIZE);
this.setCenter(center);
}

Memory usage of a GWT application

I'm currently working on a GWT application as a proof of technology for future projects. I like the way of building my AJAX code in Java instead of JavaScript. But I seem to be running into a memory problem when I repeat calls to an RPC service. The browser memory usage keeps growing and growing.
When searching Google I keep reading about how great GWT is and that its impossible to get memory leaks so can anyone explain why my browser (Firefox and Chromium) memory is rocketing?
Thanks in advance for helping me,
Bram
The code:
...
class ExampleTable extends Composite
private RPCService rpcService;
private Timer tableUpdater;
public ExampleTable(){
... Init timer and RPC Service
... Add components
initWidget();
}
private void getTableDataFromRPCService() {
this.rpcService.getData(new AsyncCallback<ArrayList<Data>>() {
#Override
public void onSuccess(ArrayList<Data> result) {
ExampleTable.this.updateTable(result);
}
#Override
public void onFailure(Throwable caught) {
//Do nothing
}
});
}
private void updateTable(ArrayList<Data> tableData){
... Update the table
}
private void startUpdateTask() {
this.serviceUpdater = new Timer() {
#Override
public void run() {
ExampleTable.this.getTableDataFromRPCService();
}
};
serviceUpdater.scheduleRepeating(2000);
}
}
EDIT:
I've spent some time to write a test application which can be downloaded here. I ran the application for about half an hour with the table update enabled after that Firefox took about 350MB of memory. I also ran the test with the update table disabled for an hour memory usage in Firefox went to little over 100MB.
(To run this sample you need the Google visualization API for GWT which can be downloaded from Google but I'm not allowed to post the link because of a new user policy )
I just got home from work and start another test without the table data update to see if memory usage keeps increasing or if it stops at a certain point.
This is the client implementation class (GWTMemoryIssue.java):
public class GWTMemoryIssue implements EntryPoint {
//Run with or without table
private static final boolean WITH_TABLE = false;
private final TestServiceAsync rpcService = GWT.create(TestService.class);
private Panel panel;
private Timer timer;
private Table table;
public void onModuleLoad() {
RootPanel rootPanel = RootPanel.get();
this.panel = new VerticalPanel();
this.panel.setSize("100%", "100%");
rootPanel.add(panel);
if (WITH_TABLE) {
loadTable();
}else{
startUpdateTask();
}
}
private void startUpdateTask() {
this.timer = new Timer() {
#Override
public void run() {
GWTMemoryIssue.this.getTableData();
}
};
this.timer.scheduleRepeating(2000);
}
public void loadTable() {
Runnable onLoadCallback = new Runnable() {
public void run() {
GWTMemoryIssue.this.table = new Table(createTableData(), createTableOptions());
GWTMemoryIssue.this.table.setSize("100%", "100%");
GWTMemoryIssue.this.panel.add(GWTMemoryIssue.this.table);
GWTMemoryIssue.this.startUpdateTask();
}
};
VisualizationUtils.loadVisualizationApi(onLoadCallback, Table.PACKAGE);
}
private Options createTableOptions() {
Options options = Options.create();
return options;
}
private DataTable createTableData() {
DataTable data = DataTable.create();
data.addColumn(ColumnType.STRING, "Name");
data.addColumn(ColumnType.NUMBER, "Intval 1");
data.addColumn(ColumnType.NUMBER, "Intval 2");
data.addColumn(ColumnType.NUMBER, "Intval 3");
return data;
}
private void getTableData() {
rpcService.getListOfItems(new AsyncCallback<ArrayList<ListItem>>(){
public void onFailure(Throwable caught) {
// Do nothing
}
public void onSuccess(ArrayList<ListItem> result) {
if (WITH_TABLE){
GWTMemoryIssue.this.updateTableData(result);
}else{
//Ignore the data from the server
}
}
});
}
private void updateTableData(ArrayList<ListItem> result) {
DataTable data = createTableData();
data.addRows(result.size());
int row = 0;
for (ListItem li : result) {
data.setValue(row, 0, li.getName());
data.setValue(row, 1, li.getIntVal());
data.setValue(row, 2, li.getIntSecondVal());
data.setValue(row, 3, li.getThirdIntVal());
row++;
}
this.table.draw(data, createTableOptions());
}
}
With all the additional information you provided here are some thoughts. I guess the memory increase is caused by the lists remaining in memory. It's either possible the memory is not freed at all or the JavaScript garbage collector doesn't get time to clean up, due too the short time frame between updates. Here are some test you could do:
To test if the garbage collector doesn't get time adapt you code such that the update only runs a finite number of times, and then check if the memory usage decreases over a few minutes. If the memory usage decreases, than it might be less of an issue in you real world example. But simple test it by setting the delay to the 30 seconds.
You could help the garbage collector by clearing the list after they are used: I don't know what works best, so here are some suggestions: Remove object from the list, or loop over the list and set values to null. This should not be necessary in normal case, because the garbage collector would do it.
You can also try the following Firefox Memory profiler add-on to see if you can locate the memory increases: http://ajaxian.com/archives/enhanced-firefox-memory-profiler-add-on
I've been using GWT quite some time with many tables and RPCs and until now most memory leaks I found were my own fault.
The RPC layer does not seem to leak as far as I know and your example is just too simple to pose a problem.
You might need to take a look at what the updateTable method is actually doing, you might have a leak in your own code.
One thing that can cause huge memory leaks with GWT are Imagebundles in IE. It is a known fact that these leak extremely in GWT because they are using DXTransform to support alpha transparency. The memory goes up in large chunks everytime widgets are put on the screen. But there are tricks to avoid this.
No there is no explicit operation needed to clean garbage in Javascript. It is supposed to run automatically (although the GC in the browser is not on the same level as in a modern JVM).
GWT does it best to avoid common pitfalls that would cause memory leaks in JS (circular references between JS and DOM nodes are badly handled in some browsers).
So the question is: is the memory usage always going up ? Or does it top out at a certain point (or it just crashes with some out of memory ?). It can be normal that your application seems to be growing and growing... but GC should kick in at some point.
In my application memory usage tops out at about 64MB. But I am not working on Ubuntu, IE on windows is our main target, although I sometimes test on FireFox as wel (and there I don't see a leak either).
One other thing you might need to do is to avoid polling every 2 seconds like you do. If a request takes longer than 2 secs you start queing up the requests (a browser has a limitation on the number of concurrent connections). so it's best to wait for the response before firing a new timer.