Resolving ConcurrentModificationException from modifying overlays - java

I've been trying to fix an error causing an intermittent ConcurrentModificationException. What's happening is that I have tons of geopoints being displayed with an ItemizedOverlay. When the map is moved, however, I'm trying to clear out all current overlay items (the geopoints) and replace them with new points appropriate to the new view window.
I therefore have a callback function that clears out the old overlays and replaces them with new ones. I think my bug stems from multiple threads trying to do this simultaneously. The relevant sections are below. I have a very limited understanding of how the overlays and such work on a low level, so I was wondering if anyone could confirm (or refute) that this could be causing issues.
//first clear out the old overlays
List<Overlay> mapOverlays = mapView.getOverlays();
mapOverlays.clear();
//create the new overlays, each initialized with appropriate Drawables
MenuOverlay lowOverlay = new MenuOverlay(this, lowRisk);//(all valid Drawables)
MenuOverlay medOverlay = new MenuOverlay(this, medRisk);
MenuOverlay highOverlay = new MenuOverlay(this, highRisk);
//populate the overlays
//add the new overlays into the list of overlays
mapOverlays.add(lowOverlay);
mapOverlays.add(medOverlay);
mapOverlays.add(highOverlay);
//make the map refresh; this operation has to be pushed to another thread
Runnable runnable = new Runnable() {
public void run() {
mapView.invalidate();
}
};
runOnUiThread(runnable);
I tried making this method synchronized, but the error still occurred. Could this arise from the new runnable being pushed to the UI thread before the previous runnable terminates maybe? I've seen mention that populate is a better way than invalidate, although I'm not entirely sure how they're different. Any ideas how to resolve this?

Modifying the set of overlays should always be done on the UI thread. The List that getOverlays() returns is owned by the MapView, and it can decide to view or manipulate the list at any time.
Since you're working with a lot of geopoints, it's likely that your background thread is clearing (or adding) overlays while the MapView is iterating over them on the UI thread. That would trigger a ConcurrentModificationException because the iterator is invalidated when its underlying set of overlays changes. Sometimes the changes are not immediately visible to the UI thread, so the crash is intermittent.
Setting up the overlays is usually the slow part of this type of workflow. To avoid the concurrent modification, you could set up your overlays in the background thread and then make all of your calls to clear() and add() inside of the Runnable. (Another option is to use an AsyncTask.)
For example:
// Slow setup steps
final MenuOverlay lowOverlay = new MenuOverlay(this, lowRisk);
final MenuOverlay medOverlay = new MenuOverlay(this, medRisk);
final MenuOverlay highOverlay = new MenuOverlay(this, highRisk);
Runnable runnable = new Runnable() {
public void run() {
// Anything that touches UI widgets (map, overlay set, views, etc.)
List<Overlay> mapOverlays = mapView.getOverlays();
mapOverlays.clear();
mapOverlays.add(lowOverlay);
mapOverlays.add(medOverlay);
mapOverlays.add(highOverlay);
mapView.invalidate();
}
};
runOnUiThread(runnable);

Related

JavaFX Update GUI Before Entering Another Thread

EDIT:
I noticed that my question was linked to another. While our goals are similar, the other question's set up is different: they are creating all the GUI aspects of the program within the main class of their program, they are also setting the trigger event of the button press within the start method. Therefore the solution of using the "setOnAction(event->" coupled with Task works. It is a single class program, I was able to make the solution work if I created a new, single class program, this application does not work for me for my situation.
In my set up I am not running this event out of the main class, but out of the Controller class that is linked to my FXML and I have the event that triggers the method already defined. I did not post my entire Controller class as that seemed unnecessary. If there is a way to make the linked question's solution work for my different set up, or a link for guidance that would be stellar. I have looked into the "task" set up, taking from the linked question, but so far have not been able to get it to work successfully as pictured below:
#FXML
private void goForIt(ActionEvent event)
{
kickTheBaby();
}
private void kickTheBaby()
{
java.util.Date now = calendar.getTime();
java.sql.Timestamp currentTimestamp = new java.sql.Timestamp(now.getTime());
statusFld.setOnAction(event -> {statusFld.setText("Running");
Task task = new Task<Void>() {
#Override
public Void call()
{
(new Thread(new EmailCommunication("", currentTimestamp, "START"))).start();
(new Thread(new DataGathering2())).start();
return null;
}
};
task.setOnSucceeded(taskFinishEvent -> statusFld.setText(statusFld.getText()
+ "All done time to sleep..."));
new Thread(task).start();
});
}
I have a program in Java8 using FXML that downloads and parses data. I wish to make the program update the GUI TextField (called "statusFld" here) to say "Running" when I click the start button. Below is the method in the controller that should be responsible for this series of events.
#FXML
private void goForIt(ActionEvent event)
{
statusFld.setText("Running!");
java.util.Date now = calendar.getTime();
java.sql.Timestamp currentTimestamp = new java.sql.Timestamp(now.getTime());
(new Thread(new EmailCommunication("", currentTimestamp, "START"))).start();
(new Thread(new DataGathering2())).start();
}
However, when I attempt to run the program the GUI does not visually update and goes straight into the other two threads. So I attempted to utilize the "Platform.runLater()" methodology in one of the other threads by passing the status field to it as so:
Platform.runLater(() ->
{
statusFld.setText("Running!");
});
But after 20 minutes it had not given a visual update to the GUI. My guess is that this is probably due to the sheer amount of data processing that I am having it do, so who knows what "later" will actually be in this case.
My question is how can I be sure that the GUI visually updates before moving on to the other, very processing intense, threads?
Thank you!

Free up not used View when creating new ones

I got two kind of ArrayAdapter in my Application which load both (more or less) dynamically data.
The first one is bound to a thread which fires each second to refresh the data.
The second one refresh the data with a onClick action.
Now when i run my application i can see in with dumpsys meminfo that the View counter
is constantly increasing (while on the fragment with the thread).
Obviously this causes a huge memory leak after a few seconds/minutes. The same
does happen for the onClick one.
My assumption is that those "old" data are still stored inside those view and won't
get freed. Is there a way to remove each old view?
My adapter is located here; https://github.com/Blechd0se/android_packages_apps_AeroControl/blob/master/AeroControl/src/com/aero/control/adapter/AeroAdapter.java
The main method which use the adapter is here (createList()); https://github.com/Blechd0se/android_packages_apps_AeroControl/blob/master/AeroControl/src/com/aero/control/fragments/AeroFragment.java
Or is there another way to just free up those unneeded Views?
EDIT:
I found a solution if anybody is interested;
As described i need to use the notifyDataSetChanged()-Method whenever i change the data.
This is only possible if working with List. In my example its List<adapterInit> which alows
me to use the mentioned method as well as clear(). Also setAdapter on each second
is a very bad idea. Now i change only the data and the result is as expected. The View-Count
went down from ~15.000 to 100-200.
A patch can be found on my github.
It appears (from the code below) that you are refreshing the data by creating a new adapter rather than telling the adapter that the data has changed. Try passing the data to the adapter and then calling notifyDataSetChanged();
This will keep you from spamming a dozen new views every second.
Second, you may want to see if the garbage collector is cleaning these up at some point. Since you were creating multiple views a second, you were probably creating views faster than the gc could reasonably keep up. It might have paused your program if it reached a critical point (not sure). See if you will actually crash due to out-of-memory to see if it is actually a memory leak.
private RefreshThread mRefreshThread = new RefreshThread();
private Handler mRefreshHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.what >= 1) {
if (isVisible() && mVisible) {
createList();
mVisible = true;
} else {
// Do nothing
}
}
}
};
public void createList() {
// Default Overview Menu
adapterInit overview_data[] = new adapterInit[]
{
// First Value (0) is for loadable images.
new adapterInit(getString(R.string.kernel_version), AeroActivity.shell.getKernel()),
new adapterInit(getString(R.string.current_governor), AeroActivity.shell.getInfo(GOV_FILE)),
new adapterInit(getString(R.string.current_io_governor), AeroActivity.shell.getInfo(GOV_IO_FILE)),
new adapterInit(getString(R.string.current_cpu_speed), getFreqPerCore()),
new adapterInit(getString(R.string.current_gpu_speed), AeroActivity.shell.toMHz((AeroActivity.shell.getInfo(gpu_file).substring(0, AeroActivity.shell.getInfo(gpu_file).length() - 3)))),
new adapterInit(getString(R.string.available_memory), AeroActivity.shell.getMemory(FILENAME_PROC_MEMINFO))
};
listView1 = (ListView) root.findViewById(R.id.listView1);
adapter = new AeroAdapter(getActivity(),
R.layout.overviewlist_item, overview_data);
listView1.setAdapter(adapter);
}

Android UI flickers on posting to handler

In one of my adapters for a custom ListView, I have a piece of code to insert a Bitmap into an ImageView that looks something like this :
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable()
{
#Override
public void run()
{
imageView.setImageBitmap(bitmap);
}
});
Except that I'm passing on the Handler along with a callback (that is later wrapped in the Runnable), to a different thread which computes the Bitmap to be displayed and then posts the results on to the provided handler.
And every time the ListView is updated, the contents flicker a couple of times.
I'm aware that AsyncTasks are primarily for this purpose. But I'd still like to know what is causing the screen to flicker.

Animated infowindow in Google Maps v2

I recently asked about applying an animation to a marker popup window (infowindow) and was explained why that wasn't possible:
Note: The info window that is drawn is not a live view. The view is rendered as an image (using View.draw(Canvas)) at the time it is returned. This means that any subsequent changes to the view will not be reflected by the info window on the map. To update the info window later (e.g., after an image has loaded), call showInfoWindow(). Furthermore, the info window will not respect any of the interactivity typical for a normal view such as touch or gesture events. However you can listen to a generic click event on the whole info window as described in the section below.
Researching some more, I found a project using V1 that manually creates the View on the marker's position. To do this, the other guy did something like this:
public void showPopup(View view, GeoPoint point, boolean centerPopup) {
removeAllViews();
MapView.LayoutParams lp = new MapView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
point,
Utils.dipsToPixels(0.0f, mContext),
Utils.dipsToPixels(-12.0f, mContext),
MapView.LayoutParams.BOTTOM_CENTER);
if (centerPopup) {
getController().animateTo(point);
mIgnoreNextChangeEvent = true;
}
View balloon = mInflater.inflate(R.layout.balloon, null);
balloon.setLayoutParams(lp);
((ViewGroup) balloon.findViewById(R.id.balloonBody)).addView(view);
balloon.startAnimation(AnimationUtils.loadAnimation(mContext, R.anim.bounce_in));
addView(balloon);
}
So he manually creates a balloon view and attaches it to the MapView.
I've been trying to emulate this same thing using V2 but I haven't been able and I don't even know if this is possible at all. For example, I use "GoogleMap" instead of "MapView" and I'm not sure if this has anything to do with some of the differences between V1 and V2.
I'm going to add what I have so far just as a reference. I tried to replicate the code from the other project and try to modify it so it will work in this one but I haven't been able to even compile it.
public boolean onMarkerClick(Marker marker) {
map.removeAllViews();
MapView.LayoutParams lp = new MapView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
marker.getPosition(),
Tools.dipsToPixels(0.0f, this),
Tools.dipsToPixels(-12.0f, this),
MapView.LayoutParams.BOTTOM_CENTER);
if (centerPopup) {
getController().animateTo(point);
mIgnoreNextChangeEvent = true;
}
View balloon = mInflater.inflate(R.layout.balloon, null);
balloon.setLayoutParams(lp);
((ViewGroup) balloon.findViewById(R.id.balloonBody)).addView(view);
balloon.startAnimation(AnimationUtils.loadAnimation(mContext, R.anim.bounce_in));
addView(balloon);
return false;
}
You cannot synchronize scrolling map with any view that could be over it and even if you completed this kind of solution it would look laggy.
Have you tried this workaround: https://stackoverflow.com/a/16147630/2183804 ?

LWUIT: Load images in background thread

I have a list that contains about 20 image URLs and some other things.
I want to display the other things (description) and allow the user to interact with the app while I load the 20 images.
What I noticed is that no matter what I tried, I can't interact with the form until the images finished loading even though I am doing the loading in another thread.
This is my solution I am using now.
private Container createServerItems() throws Exception {
Container list = new Container(new BoxLayout(BoxLayout.Y_AXIS));
final int size = mediaList.size();
final Button buttons[] = new Button[size];
System.out.println("In here: " + size);
for (int i = 0; i < size; i++) {
Container mainContainer = new Container(new BorderLayout());
Media m = new Media();
m.fromJSONString(mediaList.elementAt(i).toString());
buttons[i] = new Button("please wait");
final int whichButton = i;
Display.getInstance().callSerially(new Runnable() {
public void run() {
try {
System.out.println(MStrings.replaceAll(m.getImgURL(), "\"", ""));
final StreamConnection streamConnection = (StreamConnection) Connector.open(MStrings.replaceAll(m.getImgURL(), "\"", ""));
Image image = Image.createImage(streamConnection.openInputStream());
streamConnection.close();
buttons[whichButton].setText("");
buttons[whichButton].setIcon(image.scaled(32, 32));
} catch (Exception e) {
}
}
});
TextArea t = new TextArea(m.getDesc());
t.setEditable(false);
t.setFocusable(false);
t.setGrowByContent(true);
mainContainer.addComponent(BorderLayout.WEST, buttons[i]);
mainContainer.addComponent(BorderLayout.CENTER, t);
list.addComponent(mainContainer);
}
return list;
}
APPROACH I : LWUIT 1.5 has a powerful LWUIT4IO library to address your problem.
An excerpt from Shai's Blog link
A feature in LWUIT4IO to which I didn't give enough spotlight is the
cache map, its effectively a lean hashtable which stores its data
using weak/soft references (depending on the platform) and falls back
to storage when not enough memory is available. Its a great way to
cache data without going overboard. One of the cool things about it is
the fact that we use it seamlessly for our storage abstraction (which
hides RMS or equivalent services) in effect providing faster access to
RMS storage which is often slow on devices.
Another useful link is here
The idea is to delegate the Network IO functionality to a singleton to avoid any UI deadlocks, like the one you are facing.
A very good video demo here by vprise, explains how to bind GUI functionality to your netbeans. In this video at around 7:00 mins it explains the use of ImageDownloadService class which binds the component to its thumbnail url which will seamlessly fetch from the network and populate the Image.
APPROACH II: Difficult one of create custom logic
Create a singleton that will interface with the network to fetch the
data
Use a queue to handle the sequential image download services
Create a new thread for this singleton and wait on the queue.
With each image download service bind a listener with the invoking
component so that it easier to update the right component.
According to the lwuit spec, callSerially() executes on the Event Dispatch Thread, which means that it will block other events until it completes. You need to move your code to load the image outside of that method and keep only the setText and setIcon calls in callSerially().

Categories

Resources