JavaFx Table View Memory leakages - javafx-tableview

I have created table View in JavaFx 2x,It's has more than 10K rows and each row has 20 columns, Whenever table view is loading java heap old gen memory is increasing and it's not releasing. After loading the same table for 2-3 times(refresh button and every time before loading the table clearing all the references mentioned below). My Application is freezing or goes to not responding state, I have tried have all the options clear the references form memory but no luck
#FXML
private TableView<PersonModel> personlicense;
private void initTable(){
licState
.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<PersonModel, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(
final CellDataFeatures<PersonModel, String> cdf) {
return cdf.getValue().iconStateProperty();
}
});
colCompliance
.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<PersonModel, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(
final CellDataFeatures<PersonModel, String> cdf) {
return cdf.getValue().complianceDetailStrProperty();
}
});
}
priavte void populate(){
final ObservableList<PersonModel> itemsMultiTable = personlicense.getItems();
if (!itemsMultiTable.isEmpty()) {
itemsMultiTable.removeAll(itemsMultiTable);
clean();
}
for (final Person personObj : selectedPersons) {
final PersonModel LicModel = personObj.getLicense();
itemsMultiTable.add(LicModel);
}
}
private void clean(){
Class tcb=TableCellBehavior.class;
try{
Method anchormethod=tcb.getDeclaredMethod("setAnchor",TableView.class,TablePosition.class);
anchormethod.setAccessible(true);
anchormethod.invoke(null,resumeTable,null);
}
catch(Throwable t){
throw new RuntimeException(t);
}
personlicense.setFocusModel(null);
personlicense.setOnMouseClicked(null);
personlicense.setSelectionModel(null);
personlicense.getColumns().clear();
personlicense.getItems().clear();
}
I had seen some posts in this forum are suggesting to upgrade to java8, but my client is not willing to upgrade
is there any possible solution to release the memory...?
MAT Analysis is below
MAT analysis report
Thank you

Related

Peformance issues when creating nodes using FXML [duplicate]

Problem
I want to add custom made panels, built via javafx scene builder, to a gridpane at runtime. My custom made panel exsits of buttons, labels and so on.
My Attempt
I tried to extend from pane...
public class Celli extends Pane{
public Celli() throws IOException{
Parent root = FXMLLoader.load(getClass().getResource("Cell.fxml"));
this.getChildren().add(root);
}
}
... and then use this panel in the adding method of the conroller
#FXML
private void textChange(KeyEvent event) {
GridPane g = new GridPane();
for (int i=0 : i<100; i++){
g.getChildren().add(new Celli());
}
}
}
It works, but it performs very very poor.
What I am looking for
Is there a way to design panels via javafx scene builder (and as a result having this panels in fxml) and then add it to a gridpane at runtime without make use of this fxmlloader for each instance. I think it performs poor because of the fxml loader. When I add a standard button e.g. whitout fxml it is very much faster.
Short answer: No, it is not (as of JavaFX 2.x and 8.0). It may be in a future version (JFX >8)
Long answer:
The FXMLLoader is currently not designed to perform as a template provider that instantiates the same item over and over again. Rather it is meant to be a one-time-loader for large GUIs (or to serialize them).
The performance is poor because depending on the FXML file, on each call to load(), the FXMLLoader has to look up the classes and its properties via reflection. That means:
For each import statement, try to load each class until the class could successfully be loaded.
For each class, create a BeanAdapter that looks up all properties this class has and tries to apply the given parameters to the property.
The application of the parameters to the properties is done via reflection again.
There is also currently no improvement for subsequent calls to load() to the same FXML file done in the code. This means: no caching of found classes, no caching of BeanAdapters and so on.
There is a workaround for the performance of step 1, though, by setting a custom classloader to the FXMLLoader instance:
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
public class MyClassLoader extends ClassLoader{
private final Map<String, Class> classes = new HashMap<String, Class>();
private final ClassLoader parent;
public MyClassLoader(ClassLoader parent) {
this.parent = parent;
}
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> c = findClass(name);
if ( c == null ) {
throw new ClassNotFoundException( name );
}
return c;
}
#Override
protected Class<?> findClass( String className ) throws ClassNotFoundException {
// System.out.print("try to load " + className);
if (classes.containsKey(className)) {
Class<?> result = classes.get(className);
return result;
} else {
try {
Class<?> result = parent.loadClass(className);
// System.out.println(" -> success!");
classes.put(className, result);
return result;
} catch (ClassNotFoundException ignore) {
// System.out.println();
classes.put(className, null);
return null;
}
}
}
// ========= delegating methods =============
#Override
public URL getResource( String name ) {
return parent.getResource(name);
}
#Override
public Enumeration<URL> getResources( String name ) throws IOException {
return parent.getResources(name);
}
#Override
public String toString() {
return parent.toString();
}
#Override
public void setDefaultAssertionStatus(boolean enabled) {
parent.setDefaultAssertionStatus(enabled);
}
#Override
public void setPackageAssertionStatus(String packageName, boolean enabled) {
parent.setPackageAssertionStatus(packageName, enabled);
}
#Override
public void setClassAssertionStatus(String className, boolean enabled) {
parent.setClassAssertionStatus(className, enabled);
}
#Override
public void clearAssertionStatus() {
parent.clearAssertionStatus();
}
}
Usage:
public static ClassLoader cachingClassLoader = new MyClassLoader(FXMLLoader.getDefaultClassLoader());
FXMLLoader loader = new FXMLLoader(resource);
loader.setClassLoader(cachingClassLoader);
This significantly speeds up the performance. However, there is no workaround for step 2, so this might still be a problem.
However, there are already feature requests in the official JavaFX jira for this. It would be nice of you to support this requests.
Links:
FXMLLoader should be able to cache imports and properties between to load() calls:
https://bugs.openjdk.java.net/browse/JDK-8090848
add setAdapterFactory() to the FXMLLoader:
https://bugs.openjdk.java.net/browse/JDK-8102624
I have had a similar issue. I also had to load a custom fxml-based component several times, dynamically, and it was taking too long. The FXMLLoader.load method call was expensive, in my case.
My approach was to parallelize the component instantiation and it solved the problem.
Considering the example posted on the question, the controller method with multithread approach would be:
private void textChange(KeyEvent event) {
GridPane g = new GridPane();
// creates a thread pool with 10 threads
ExecutorService threadPool = Executors.newFixedThreadPool(10);
final List<Celli> listOfComponents = Collections.synchronizedList(new ArrayList<Celli>(100));
for (int i = 0; i < 100; i++) {
// parallelizes component loading
threadPool.execute(new Runnable() {
#Override
public void run() {
listOfComponents.add(new Celli());
}
});
}
// waits until all threads completion
try {
threadPool.shutdown();
threadPool.awaitTermination(3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// seems to be a improbable exception, but we have to deal with it
e.printStackTrace();
}
g.getChildren().addAll(listOfComponents);
}
Just adding code for "caching of already loaded classes" in #Sebastian sir given code. It is working for me. Please suggest changes in it for better performance.
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
System.out.println("In Class loader");
Class result;
System.out.println(" >>>>>> Load class : "+name);
result = (Class)classes.get(name);
if(result != null){
System.out.println(" >>>>>> returning cached class.");
return result;
}else{
Class<?> c = findClass(name);
if ( c == null ) {
throw new ClassNotFoundException( name );
}
System.out.println(" >>>>>> loading new class for first time only");
return c;
}
}

Why is firebase populating my viewholder with the same image from Firebase Storage

I have a blog app that consists of username,profileImage,description and postImage. I am using this code to retrieve these items from firebase
FirebaseRecyclerAdapter<Blog,BlogViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Blog, BlogViewHolder>(
Blog.class,
R.layout.blog_row,
BlogViewHolder.class,
mDatabase.orderByChild("TimeOrder")
) {
#Override
protected void populateViewHolder(final BlogViewHolder viewHolder, Blog model, int position) {
viewHolder.setDescription(model.getDescription());
if (isAdded()) {
viewHolder.setImage(getActivity(), model.getPostimage());
}
viewHolder.setUid(model.getUid());//get username and profile picture from this
Everything is fine except that the about two postImages are repeated throughout the recyclerview. The profile picture also are from the same user ie One or two pictures are used as profile pictures of the rest of the users.
This is the code for setImage
public void setImage(final Context con, final String image){
final ImageView imageView = view.findViewById(R.id.post_image);
if (postbool) {
Picasso.with(con).load(image).placeholder(R.drawable.unnamed).error(R.drawable.imageerror).networkPolicy(NetworkPolicy.OFFLINE).into(imageView, new Callback() {
#Override
public void onSuccess() {
postbool = false;
}
#Override
public void onError() {
Picasso.with(con).load(image).placeholder(R.drawable.unnamed).into(imageView);
postbool = false;
}
});
}
}
This are a few screenshots. The profile picture is the same.
Where am I going wrong?
This might be due to cache issues! My suggestion, always reset all the views in the ViewHolder before populating values.
#Override
protected void populateViewHolder(final BlogViewHolder viewHolder, Blog model, int position) {
**reset all views**
viewHolder.setDescription("");
viewHolder.imageview.setImageDrawable(null);
viewHolder.setUid("");
viewHolder.setDescription(model.getDescription());
if (isAdded()) {
viewHolder.setImage(getActivity(), model.getPostimage());
}
viewHolder.setUid(model.getUid());//get username and profile picture from this
Please let me know how it goes!

How to make always visible headers of rows in RowsFragment

Here is what i have now.
Simply my RowsFragment is look like this,
public static class SampleFragmentB extends RowsFragment {
private final ArrayObjectAdapter mRowsAdapter;
public SampleFragmentB() {
mRowsAdapter = new ArrayObjectAdapter(new ShadowRowPresenterSelector());
setAdapter(mRowsAdapter);
setOnItemViewClickedListener(new OnItemViewClickedListener() {
#Override
public void onItemClicked(
Presenter.ViewHolder itemViewHolder,
Object item,
RowPresenter.ViewHolder rowViewHolder,
Row row) {
Toast.makeText(getActivity(), "Implement click handler", Toast.LENGTH_SHORT)
.show();
}
});
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createRows();
getMainFragmentAdapter().getFragmentHost().notifyDataReady(getMainFragmentAdapter());
}
private void createRows() {
String json = Utils.inputStreamToString(getResources().openRawResource(
R.raw.page_row_example));
CardRow[] rows = new Gson().fromJson(json, CardRow[].class);
for (CardRow row : rows) {
mRowsAdapter.add(createCardRow(row));
}
}
private Row createCardRow(CardRow cardRow) {
PresenterSelector presenterSelector = new CardPresenterSelector(getActivity());
ArrayObjectAdapter adapter = new ArrayObjectAdapter(presenterSelector);
for (Card card : cardRow.getCards()) {
adapter.add(card);
}
HeaderItem headerItem = new HeaderItem(cardRow.getTitle());
return new CardListRow(headerItem, adapter, cardRow);
}
}
This is what i exactly want to do,
So I want to make always visible Header of each row without selecting into or focusing into RowsFragment. I'am using leanback v24 to add multiple rows into each header item.
You might want to check the Sofa library for Android TV that extends the Leanback library capabilities by offering a set of more powerful features. In BrowseSupportFragment, mRowsFragment.setExpand should be true. Additional reference: how to always show headers in RowsFragment

Concurrent task updating complex object JavaFX - swingworker equivalent?

I want to run a task in background updating intermediate results in the view.I am trying to implement MVC JavaFX application. The task is defined in the Model.
I want to send to the main threath partial results in order to show them in the View.
I use updateValue() to do so. Also, I define object property and a listener in the controller.
My problem: The method changed() from the listener, is not being fired each time that updateValue() is executed in the Task. Why? How can I force it to do this?.
I have not found much complex examples.
What I have so far:
Model.cpp
ComplexObject _complexO;
public Task<ComplexObject> getModelTask() {
return new Task<ComplexObject>() {
#Override
protected ComplexObject call() throws Exception {
int numberOfFiles = 0;
boolean filesToRead = true;
while (filesToRead){
// ....
_complexO = new ComplexObject();
try{
//..
if(f.exists()){
_complexO.initialize();
numberOfScans ++;
}
else{
_complexO.initializeToNull();
}
String stringNumber = Converter.toString(numberOfFiles);
updateMessage(stringNumber);
updateValue(_complexO );
} catch(Exception ex){
ex.printStackTrace();
_complexO = null;
return _complexO;
}
filesToRead = areThereFilesToRead();
}
return _complexO;
}
};
}
Controller.cpp
...
Task< ComplexObject> task = _model.getModelTask();
_AJavaFXTextField.textProperty().bind(task.messageProperty());
_AJavaFXTextField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue observable, String oldValue, String newValue) {
System.out.println("Success with messageProperty!!" + newValue);
}
});
SimpleObjectProperty<ComplexObject> complexObjectProperty = new SimpleObjectProperty<>();
complexObjectProperty.bind(task.valueProperty());
complexObjectProperty.addListener(new ChangeListener<ComplexObject>(){
#Override
public void changed(ObservableValue<? extends ComplexObject> observable, ComplexObject oldValue, ComplexObject newValue) {
if(newValue.data == null ) {
System.out.println("value is new!!! " + scansNumber);
}
else if(newValue.isValid()){
System.out.println("I want to plot newValue data here");
}
}
});
Thread th= new Thread(task);
System.out.println("call TASK");
th.start();
}
My questions/conclusions here:
How to force to all times that I execute in the task updateValue() to really execute the listener - so execute the code where I want to plot data.
Why it is more times fire the bind for the messageProperty than the valueProperty? - it should be the same number of times.
Why I find that the code of the listener is fired more times when debug mode than normal execution?
Any recomendation of good sources about this topic (from a complex point of view) would be great.
I am looking from something in JavaFX to replace SwingWorker.
What I really whant at the end: To return a list of complexObjects from the task, and ideally, updateValue() would send the objects one per one (partial results)
I have followed:
https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html
Thanks very much for any contribuction
Task only guaranties that a value passes to updateValue or a value passed later will be set to the value property. This is done to increase performance of the application thread by limiting the number of changes the listeners are notified of.
Why it is more times fire the bind for the messageProperty than the valueProperty? - it should be the same number of times.
As described above there simply is no guaranty about the number of updates.
Why I find that the code of the listener is fired more times when debug mode than normal execution?
In general debugging makes your program smaller. The smaller the update frequency from the thread of your Task, the smaller the number of updates between the times the Task class updates the properties and the smaller the number of skipped. (The updates are probably executed every frame or every few frames.) If you even use a break-point/stepper in the task, you probably make the Task extremely slow while the application thread runs at normal speed.
It should be easy enough to implement publish on your own by using a List to buffer the updates
public abstract class JavaFXWorker<S, T> extends Task<S> {
private List<T> chunks = new ArrayList<>();
private final Object lock = new Object();
private boolean chunkUpdating = false;
protected final void publish(T... results) {
synchronized (lock) {
chunks.addAll(Arrays.asList(results));
if (!chunkUpdating) {
chunkUpdating = true;
Platform.runLater(() -> {
List<T> cs;
synchronized (lock) {
cs = chunks;
// create new list to not unnecessary lock worker thread
chunks = new ArrayList<>();
chunkUpdating = false;
}
try {
process(cs);
} catch (RuntimeException ex) {
}
});
}
}
}
protected void process(List<T> chunks) {
}
}
Sample use
#Override
public void start(Stage primaryStage) {
ListView<Integer> lv = new ListView<>();
Button btn = new Button("Run");
btn.setOnAction((ActionEvent event) -> {
JavaFXWorker<Void, Integer> worker = new JavaFXWorker<Void, Integer>() {
#Override
protected Void call() throws Exception {
final int maxCount = 100;
Random random = new Random();
int breakIndex = random.nextInt(maxCount-1)+1;
for (int i = 0; i < breakIndex; i++) {
publish(i);
}
// some break simulating a part long part of the task with no updates
Thread.sleep(3000);
for (int i = breakIndex; i <= maxCount; i++) {
publish(i);
}
return null;
}
#Override
protected void process(List<Integer> chunks) {
lv.getItems().addAll(chunks);
}
};
new Thread(worker).start();
});
Scene scene = new Scene(new VBox(btn, lv));
primaryStage.setScene(scene);
primaryStage.show();
}

Deleting multiple rows from TableView

#FXML
private void handleDeleteAction(ActionEvent event) {
for (Transaction transaction : transactionsTable.getSelectionModel().getSelectedItems()) {
RemoveTransactionsCommand removeTransactionsCommand = new RemoveTransactionsCommand(transaction, transactionsTable.getSelectionModel().getSelectedItems(), data);
commandRegistry.executeCommand(removeTransactionsCommand);
}
}
Why it won't work in case where I select more than one row, I mean it delete one row (sometimes two, but can't find what decide about it)
Here is command implementation:
public class RemoveTransactionsCommand implements Command {
private ObservableList<Transaction> selectedItems;
private Transaction transactionToRemove;
private Account account;
public RemoveTransactionsCommand(Transaction transactionToRemove, ObservableList<Transaction> selectedItems, Account account) {
this.account = account;
this.transactionToRemove = transactionToRemove;
this.selectedItems = selectedItems;
}
#Override
public String getName() {
int presentSize = selectedItems.size();
return presentSize + "transaction/s removed";
}
#Override
public void execute() {
account.removeTransaction(transactionToRemove);
}
}
And removal command:
public void removeTransaction(Transaction transaction) {
this.transactions.remove(transaction);
}
Additionally I wanted to know the size of actual delete operation but what I pass as a 2nd argument isn't static and for example when every row is deleted it will be 0.
Any advices how to improve it?
Full project can be found here
The problem is that the selected items list may change when the list of items in the table changes. So the list gets modified while you are trying to iterate through it.
You should create a copy of the list of selected items and iterate through it instead:
#FXML
private void handleDeleteAction(ActionEvent event) {
List<Transaction> selectedTransactions = new ArrayList<>(transactionTable.getSelectionModel().getSelectedItems());
for (Transaction transaction : selectedTransactions) {
RemoveTransactionsCommand removeTransactionsCommand = new RemoveTransactionsCommand(transaction, selectedTransactions, data);
commandRegistry.executeCommand(removeTransactionsCommand);
}
}
(and change the type of selectedItems in RemoveTransactionsCommand to List<Transaction>).

Resources