Dynamically loading large data in jTable using SwingWorker

给你一囗甜甜゛ 提交于 2020-01-17 07:10:28

问题


In Netbeans, I am trying to create a Desktop Application whose UI looks like below:

I am executing "adb logcat command" through Java code which loads 1000s of lines of logs in few seconds & I intend to display all of this information through jTable in NetBeans.

Using parameter: adb logcat -t 100 -> I am restricting the logs to 100 lines only right now. However the applet becomes unresponsive (or gets stuck in process() method) for 1000 lines or when removing such restriction on number of lines.

I am not sure whether I have properly implemented the SwingWorker thread in my code. I am looking for suggestions on how to improve the code for loading large amount of data dynamically without applet becoming unresponsive.

Following is the implemented code for the applet... with 2 functions:

  1. viewLogs() called from init() method of applet.
  2. SwingWorker implementation.

        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);
    }
    

    }


回答1:


The key problem is...

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

This is blocking the Event Dispatching Thread, preventing any possible updates from occurring until the Process completes, kind of defeating the purpose of using a SwingWorker.

You'd be better off executing the Process in the SwingWorker directly, something like...

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();
            }
        }
    }
}

Okay, this might look a little "heavy" but it does two important things:

  1. It off loads the reading of the process's InputStream to another Thread, which allows us to...
  2. waitFor the process to exit so we get the exit value, which can be useful in diagnosing why somethings don't work from time to time

Other observations

  • Applet's by their very nature run under a tight security constraint, typically meaning that they aren't allowed to execute programs on other machines.
  • Applet's are also no longer support. See Java Plugin support deprecated and Moving to a Plugin-Free Web for more details


来源:https://stackoverflow.com/questions/42969696/dynamically-loading-large-data-in-jtable-using-swingworker

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!