【发布时间】:2018-12-05 03:36:06
【问题描述】:
我正在 JavaFX 中创建一个发票系统,并使用带有“发票”对象的 cellValueFactory 将数据从 sqlite 文件加载到 tableview 中。 我决定加载最新的 100 个条目以获得更好的性能,然后通过调用 sqlite 数据库并检索下一个向上或向下的 100 个按钮,使用两个按钮在发票对象之间导航。每次使用按钮并显示下一个 100 或 -100 时,它都会使用少量内存并被保留且无法恢复,使用时间越长就会成为问题。
我从其他线程中听说这可能是由于侦听器中的强引用引起的,但我不确定。
没有错误,只是我无法修复的小内存泄漏。 我没有显示我的所有代码,希望不会使我的代码过于复杂,但如果需要,请告诉我。
我是一名高中生,一直在自学 Swing,然后在 3 个月前转到 javaFX,我对 GUI 编程比较陌生,所以如果对我的代码风格或任何不良习惯有任何提示,请我很想学习。
主类(启动器)
package main;
import dbUtil.sqlitedb;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.stage.Stage;
import java.util.ArrayList;
//this class launches gui of invoices then distributes the data to the classes.
public class main extends Application {
/*
The main class is to access data and process it to and from the sqlitedb object and the invoiceController.
*/
private boolean saved = true;
private Parent root;
private static sqlitedb dataBase;
private static invoiceDataBaseController invoicesController;
private Scene scene;
private static ArrayList<invoiceOBJ> invoiceDataBase;
private static int indexStart = 100;
public static void main(String[] args) {
launch(args);
}
public main() {
invoiceDataBase = new ArrayList<>();
}
public void loadInvoices() {
//dataBase.generateInvoices_test();
invoiceDataBase = dataBase.listInvoices(indexStart);
}
public void setIndexStart(int amount) {
//the indexStart for the sqlitedb class to use for portioning invoices.
if (indexStart + amount == 0 || indexStart + amount < 0) {
} else {
indexStart += amount;
}
}
// To reset table view's contents with new invoice page.
public void refreshTable() {
dataBase.connect();
invoiceDataBase = dataBase.listInvoices(indexStart);
invoicesController.addTableItems(invoiceDataBase);
dataBase.disconnect();
}
@Override
public void start(Stage primaryStage) throws Exception {
initialize(primaryStage);
}
public Scene getScene() {
return scene;
}
public void Loading(Alert alert) {
// Loading alert before showing main gui
alert.setHeaderText("Loading Files");
// System.out.println("loading");
alert.show();
}
public void initialize(Stage stage) {
try {
dataBase = new sqlitedb();
//System.out.println("Loading files");
//saveInvoicesAndCustomers(generateCustomersAndInvoices());
FXMLLoader loader = new FXMLLoader(getClass().getResource("main.fxml"));
Alert alert = new Alert(Alert.AlertType.INFORMATION, "Loading data..");
Loading(alert);
loadInvoices();
root = loader.load();
invoicesController = loader.getController();
invoicesController.setStageAndListeners(stage, this, invoiceDataBase);
scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("resources/fxml.css").toExternalForm());
stage.setTitle("JavaInvoice");
stage.setScene(scene);
stage.show();
alert.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
sqliteDB 对象中的相关方法:
sqlitedb 中的此方法用于调用初始发票,然后调用 稍后在控制器中。
public ArrayList<invoiceOBJ> listInvoices(int indexStart) {
//invoiceAmount = invoices to index.
ArrayList<invoiceOBJ> invoices = new ArrayList<>();
Long time = System.currentTimeMillis(); //made to test indexing time
//System.out.println(indexStart + "index start");
try {
//System.out.println("in list Invoices");
stmt = c.createStatement();
stmt.setFetchSize(1000);
ResultSet rs = stmt.executeQuery(String.format("SELECT id,year,vin,carModel,condition,licenseState,regNum,stage,vehicleID,paintCode,dateOfInvoice," +
"bodyStyle,manufacturer, customerID FROM invoices LIMIT 100 OFFSET (SELECT COUNT(*) FROM invoices)-%d", indexStart));
int id;
String customerID;
String year;
String vin;
String carModel;
String condition;
String licenseState;
String regNum;
String stage;
String vehicleID;
String paintCode;
String dateOfInvoice;
String bodyStyle;
String manufacturer;
c.setAutoCommit(false);
stmt.setFetchSize(1000);
while (rs.next()) {
id = rs.getInt(1);
year = rs.getString(2);
vin = rs.getString(3);
carModel = rs.getString(4);
condition = rs.getString(5);
licenseState = rs.getString(6);
regNum = rs.getString(7);
stage = rs.getString(8);
vehicleID = rs.getString(9);
paintCode = rs.getString(10);
dateOfInvoice = rs.getString(11);
bodyStyle = rs.getString(12);
manufacturer = rs.getString(13);
customerID = rs.getString(14);
// System.out.println(String.format("ID: %d , CustomerID: %s Year: %s, Vin: %s, \ncarModel %s, condition: %s, licenseState: %s \n" +
// "regNum: %s, stage: %s vehicleID: %s, paintCode: %s, dateOfInvoice: %s, bodyStyle:%s", id, customerID, year, vin, carModel
// , condition, licenseState, regNum, stage, vehicleID, paintCode, dateOfInvoice, bodyStyle));
//add to invoice list.
invoices.add(new invoiceOBJ(id,
carModel, manufacturer,
vin, condition, licenseState,
regNum, stage, vehicleID, paintCode,
bodyStyle, year, dateOfInvoice, findCustomer(customerID)));
// System.out.println("added A customer");
}
stmt.close();
rs.close();
c.close();
//System.out.println("load complete..");
} catch (Exception e) {
e.printStackTrace();
}
// System.out.println(System.currentTimeMillis() - time);
return invoices;
}
public HashMap<String, String> findCustomer(String id) {
String sql = String.format("SELECT firstName, lastName,id, date FROM customers WHERE id=%s", id);
HashMap<String, String> customerData = new HashMap<>();
try {
Statement stmt = c.createStatement();
ResultSet data = stmt.executeQuery(sql);
customerData.put("firstName", data.getString("firstName"));
customerData.put("lastName", data.getString("lastName"));
customerData.put("date", data.getString("date"));
customerData.put("id", data.getString("id"));
stmt.close();
data.close();
} catch (Exception e) {
e.printStackTrace();
}
return customerData;
}
invoiceController 对象:
package main;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class invoiceDataBaseController implements Initializable {
main main;
@FXML
private Button next = new Button();
private invoiceLoader customerPage;
@FXML
private TableView<invoiceOBJ> invoices = new TableView<>();
@FXML
private Button back = new Button();
@FXML
private TextField searchField = new TextField();
@FXML
private Button confirmButton = new Button();
@FXML
private StackPane root = new StackPane();
@FXML
private ChoiceBox choice = new ChoiceBox();
private Stage mainStage;
public invoiceDataBaseController() {
customerPage = new invoiceLoader();
}
public TextField getSearchField() {
return searchField;
}
//Setup the table of people
public void setTable() {
choice.getItems().addAll("ID", "FirstName", "LastName", "Date", "Manufacturer");
//set specific columns to table.
TableColumn<invoiceOBJ, String> id = new TableColumn<>("ID:");
TableColumn<invoiceOBJ, String> firstName = new TableColumn<invoiceOBJ, String>("First Name");
TableColumn<invoiceOBJ, String> lastName = new TableColumn<invoiceOBJ, String>("Last Name");
TableColumn<invoiceOBJ, String> dateOfInvoice = new TableColumn<invoiceOBJ, String>("Date");
TableColumn<invoiceOBJ, String> manufac = new TableColumn<invoiceOBJ, String>("Manufacturer");
TableColumn<invoiceOBJ, String> model = new TableColumn<invoiceOBJ, String>("Model");
TableColumn<invoiceOBJ, String> vinNum = new TableColumn<invoiceOBJ, String>("Last 6 VIN");
invoices.setEditable(true);
//get data from objects.
id.setCellValueFactory(p -> p.getValue().getGraphicalData("id"));
firstName.setCellValueFactory(param -> param.getValue().getCustomer().getFirstName());
lastName.setCellValueFactory(cellData -> cellData.getValue().getCustomer().getLastName());
dateOfInvoice.setCellValueFactory(param -> param.getValue().getGraphicalData("dateOfInvoice"));
manufac.setCellValueFactory(param -> param.getValue().getGraphicalData("manufacturer"));
model.setCellValueFactory(param -> param.getValue().getGraphicalData("carModel"));
vinNum.setCellValueFactory(param -> param.getValue().getGraphicalData("vin"));
//set how dates get sorted
dateOfInvoice.setComparator((t, t1) -> {
try {
SimpleDateFormat format = new SimpleDateFormat("MMM/dd/yyyy");
return Long.compare(format.parse(t).getTime(), format.parse(t1).getTime());
} catch (ParseException p) {
p.printStackTrace();
}
return -1;
});
id.setComparator(Comparator.comparingInt(Integer::parseInt));
//end
//Add values to table view columns and rows.
//end
invoices.getColumns().addAll(id, firstName, lastName, dateOfInvoice, manufac, model, vinNum);
// dateOfInvoice.setSortType(TableColumn.SortType.DESCENDING);
id.setSortType(TableColumn.SortType.DESCENDING);
invoices.getSortOrder().add(id);
choice.setValue("FirstName");
//end of making columns,
}
public void addTableItems(ArrayList<invoiceOBJ> invoiceDataBase) {
// System.out.println(Arrays.toString(invoiceDataBase.toArray()) + " table");
//add invoices list to observable list. (GUI format)
ObservableList<invoiceOBJ> custList = FXCollections.observableArrayList(invoiceDataBase);
//Put list to filtered List
FilteredList<invoiceOBJ> flInvoiceOBJS = new FilteredList(custList, p -> true);
//add search to filter list values.
getSearchField().textProperty().addListener(((observable, oldValue, newValue) -> {
switch (choice.getValue().toString()) {
case "FirstName":
flInvoiceOBJS.setPredicate(p -> p.getCustomer().getFirstName().getValue().toLowerCase().contains(newValue.toLowerCase()));
break;
case "LastName":
flInvoiceOBJS.setPredicate(p -> p.getCustomer().getLastName().getValue().toLowerCase().contains(newValue.toLowerCase()));
break;
case "Date":
flInvoiceOBJS.setPredicate(p -> p.getGraphicalData("dateOfInvoice").getValue().toLowerCase().contains(newValue.toLowerCase()));
break;
case "Manufacturer":
flInvoiceOBJS.setPredicate(p -> p.getGraphicalData("manufacturer").getValue().toLowerCase().contains(newValue.toLowerCase()));
break;
case "ID":
flInvoiceOBJS.setPredicate(p -> p.getData().get("id").contains(newValue.toLowerCase()));
break;
}
}));
//add search to choiceBox changes.
choice.valueProperty().addListener(((observable, oldValue, newValue) -> {
switch (choice.getValue().toString()) {
case "FirstName":
flInvoiceOBJS.setPredicate(p -> p.getCustomer().getFirstName().getValue().toLowerCase().contains(getSearchField().getText().toLowerCase()));
break;
case "LastName":
flInvoiceOBJS.setPredicate(p -> p.getCustomer().getLastName().getValue().toLowerCase().contains(getSearchField().getText().toLowerCase()));
break;
case "Date":
flInvoiceOBJS.setPredicate(p -> p.getGraphicalData("dateOfInvoice").getValue().toLowerCase().contains(getSearchField().getText().toLowerCase()));
break;
case "Manufacturer":
flInvoiceOBJS.setPredicate(p -> p.getData().get("manufacturer").contains(getSearchField().getText().toLowerCase()));
break;
case "ID":
flInvoiceOBJS.setPredicate(p -> p.getData().get("manufacturer").contains(getSearchField().getText().toLowerCase()));
break;
}
}));
//put filtered list through sorted list
SortedList<invoiceOBJ> sortedCusts = new SortedList<>(flInvoiceOBJS);
//add comparators (date)
sortedCusts.comparatorProperty().bind(invoices.comparatorProperty());
//finally, add the items to the table view to show
invoices.setItems(sortedCusts);
}
private class pageButtonListener implements EventHandler<MouseEvent> {
private main root;
private int indexIncrementor;
// for indexing new invoices in sqlitedb
public pageButtonListener(main root, int indexIncrementor){
this.root =root;
this.indexIncrementor = indexIncrementor;
}
@Override
public void handle(MouseEvent event) {
root.setIndexStart(indexIncrementor);
root.refreshTable();
}
}
public void setStageAndListeners(Stage prime, main root, ArrayList<invoiceOBJ> invoiceDataBase) {
pageButtonListener listener = new pageButtonListener(root,100);
pageButtonListener backButtonListener = new pageButtonListener(root,-100);
main = root;
mainStage = prime;
setTable();
addTableItems(invoiceDataBase);
next.setOnMouseClicked(listener);
back.setOnMouseClicked(backButtonListener);
}
public void getSelected() {
invoiceOBJ invoice = invoices.getSelectionModel().getSelectedItem();
}
@Override
public void initialize(URL location, ResourceBundle resources) {
confirmButton.setOnAction(e -> {
try {
invoiceOBJ selectedInvoiceOBJ = invoices.getSelectionModel().getSelectedItem();
if (selectedInvoiceOBJ == null) {
Alert noCustomer = new Alert(Alert.AlertType.ERROR, "No Customer Selected!!");
noCustomer.setHeaderText("Error, missing invoiceOBJ");
noCustomer.show();
} else {
//send user to view invoice INCOMPLETE
customerPage.initialize(mainStage, main, selectedInvoiceOBJ);
}
} catch (Exception err) {
err.printStackTrace();
}
});
}
}
InvoiceOBJ:
package main;
import javafx.beans.property.SimpleStringProperty;
import java.util.HashMap;
public class invoiceOBJ {
private HashMap<String, String> invoiceData;
private int customerID;
private String customerIDToString;
private customer cust = new customer();
public SimpleStringProperty getGraphicalData(String key){
//return hashmap key value into graphical data.
return new SimpleStringProperty(invoiceData.get(key));
}
public HashMap<String, String> getData() {
return invoiceData;
}
public int getCustomerID(){
return customerID;
}
public String getCustomerIDToString(){
return customerIDToString;
}
public customer getCustomer(){
return cust;
}
@Deprecated // reminder to change this god awful system of passing several variables.
public invoiceOBJ(int idOfInvoice,
String carModel, String manufacturer,
String vin, String condition, String licenseState,
String regNum, String stage, String vehicleID, String paintCode,
String bodyStyle, String year, String dateOfInvoice, HashMap<String,String> customerData) {
cust.setData(customerData);
invoiceData = new HashMap<>();
this.customerID = Integer.parseInt(customerData.get("id"));
this.customerIDToString = customerData.get("id");
invoiceData.put("id", Integer.toString(idOfInvoice));
invoiceData.put("carModel", carModel);
invoiceData.put("manufacturer", manufacturer);
invoiceData.put("vin", vin);
invoiceData.put("condition", condition);
invoiceData.put("licenseState", licenseState);
invoiceData.put("regNum", regNum);
invoiceData.put("stage", stage);
invoiceData.put("vehicleID", vehicleID);
invoiceData.put("paintCode", paintCode);
invoiceData.put("bodyStyle", bodyStyle);
invoiceData.put("year", year);
invoiceData.put("dateOfInvoice", dateOfInvoice);
//put into hashmap for easy access of data later.
}
public invoiceOBJ(HashMap<String, String> data, HashMap<String,String> customerData) {
invoiceData = new HashMap<>(data);
cust.setData(customerData);
this.customerID = Integer.parseInt(customerData.get("id"));
this.customerIDToString = Integer.toString(customerID);
}
}
【问题讨论】:
标签: java sqlite javafx memory-leaks