【问题标题】:Dynamically loading large data in jTable using SwingWorker使用 SwingWorker 在 jTable 中动态加载大数据
【发布时间】:2017-03-23 07:28:39
【问题描述】:

在 Netbeans 中,我正在尝试创建一个 UI 如下所示的桌面应用程序:

我正在通过 Java 代码执行“adb logcat 命令”,它会在几秒钟内加载 1000 行日志,并且我打算通过 NetBeans 中的 jTable 显示所有这些信息。

使用参数:adb logcat -t 100 -> 我现在将日志限制为 100 行。 但是,小程序在 1000 行或取消对行数的限制时变得无响应(或卡在 process() 方法中)。

我不确定我是否在我的代码中正确实现了 SwingWorker 线程。我正在寻找有关如何改进代码以动态加载大量数据而不会导致小程序无响应的建议。

以下是小程序的实现代码...具有2个功能:

  1. 从applet的init()方法调用viewLogs()。
  2. SwingWorker 实现。

        public void viewLogs() throws IOException {
    
        String[] command = {"CMD","/C", "adb logcat -t 100"};
        ProcessBuilder probuilder = new ProcessBuilder( command );
        probuilder.directory(new File("c:\\Users\\k.garg\\Desktop\\"));
        Process process = probuilder.start();
    
        InputStream is = process.getInputStream();      
        InputStreamReader isr = new InputStreamReader(is);
        br = new BufferedReader(isr);
    
        DefaultTableModel model = (DefaultTableModel)jTable1.getModel();
        worker.execute();
    
        try {
            int exitVal = process.waitFor();
            System.out.println("exitVal = " + exitVal);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public class TableSwingWorker extends SwingWorker<DefaultTableModel, Object[]>{
    private DefaultTableModel tableModel;
    public TableSwingWorker(DefaultTableModel tableModel){
        this.tableModel = tableModel;
    }
    
    @Override
    protected DefaultTableModel doInBackground() throws Exception {
        Thread.sleep(2000); //added for initial UI to load
        System.out.println("Start populating");
        String line, date, time, loglevel, PID, TID, tag, message="";
        String log;
        int count = 0;
        while ((log = br.readLine()) != null) {
            count++;
    
            String[] splitLog = log.trim().split("\\s+");
            line = Integer.toString(count);
            date = splitLog[0];
            time = splitLog[1];
            PID = splitLog[2];
            TID = splitLog[3];
            loglevel = splitLog[4];
            tag = splitLog[5];
            for(int i=6; i<splitLog.length;i++){
                message += splitLog[i];
            }
            publish(new Object[]{line, date, time, PID, TID, loglevel, tag, message});
        }
        return tableModel;
    }
    
    @Override
    protected void process(List<Object[]> chunks) {
        System.out.println("Adding " + chunks.size() + " rows");
        for(Object[] row: chunks)
            tableModel.insertRow(0,row);
    }
    

    }

【问题讨论】:

标签: java swing file-io jtable swingworker


【解决方案1】:

关键问题是……

try {
    int exitVal = process.waitFor();
    System.out.println("exitVal = " + exitVal);
} catch (InterruptedException e) {
    e.printStackTrace();
}

这会阻塞事件调度线程,在Process 完成之前阻止任何可能的更新发生,有点违背使用SwingWorker 的目的。

你最好直接在SwingWorker 中执行Process,比如...

public class TableSwingWorker extends SwingWorker<Integer, Object[]> {

    private DefaultTableModel tableModel;
    private int count;

    public TableSwingWorker(DefaultTableModel tableModel) {
        this.tableModel = tableModel;
    }

    @Override
    protected Integer doInBackground() throws Exception {
        count = 0;
        
        String[] command = {"CMD", "/C", "adb logcat -t 100"};
        ProcessBuilder probuilder = new ProcessBuilder(command);
        probuilder.directory(new File("c:\\Users\\k.garg\\Desktop\\"));
        Process process = probuilder.start();

        InputConsumer consumer = new InputConsumer(process.getInputStream());
        consumer.start();
        
        int result = process.waitFor();
        consumer.join();

        return result;
    }

    @Override
    protected void process(List<Object[]> chunks) {
        System.out.println("Adding " + chunks.size() + " rows");
        for (Object[] row : chunks) {
            tableModel.insertRow(0, row);
        }
    }
    
    protected void processOutput(String text) {
            count++;

            String[] splitLog = text.trim().split("\\s+");
            String line = Integer.toString(count);
            String date = splitLog[0];
            String time = splitLog[1];
            String PID = splitLog[2];
            String TID = splitLog[3];
            String loglevel = splitLog[4];
            String tag = splitLog[5];
            
            StringBuilder message = new StringBuilder(64);
            for (int i = 6; i < splitLog.length; i++) {
                message.append(splitLog[i]);
            }
            publish(new Object[]{line, date, time, PID, TID, loglevel, tag, message});
    }

    public class InputConsumer extends Thread {

        private InputStream is;

        public InputConsumer(InputStream is) {
            this.is = is;
            start();
        }

        @Override
        public void run() {
            try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
                String text = null;
                while ((text = br.readLine()) != null) {
                    processOutput(text);
                }
            } catch (IOException exp) {
                exp.printStackTrace();
            }
        }
    }
}

好的,这可能看起来有点“沉重”,但它做了两件重要的事情:

  1. 它将进程InputStream 的读取卸载到另一个Thread,这使我们能够...
  2. waitFor 进程退出,因此我们得到了退出值,这对于诊断为什么某些事情有时无法正常工作很有用

其他观察

【讨论】:

  • 非常感谢。完美运行。
猜你喜欢
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
  • 2011-01-21
  • 2012-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多