Finalizar ImputStream

Minha aplicação, ao apresentar uma tabela de dados, a cada 2 segundos pede o ImputStream para ler (input.read()), assim, se chegarem dados atualizados a tabela é atualizada no display.

Acontece que quando mando o ImputStream ler e não há dados chegando ele fica esperando e só sai quando algum dado chegar. Dessa forma, ao sair da tabela de dados o meu ImputStream fica lendo, esperando algum dado chegar e isso gera problemas quando tento abrir uma outra tabela.

Resumindo: Como faço para fazer um ImputStream parar de esperar os dados chegarem depois que eu dei o comando input.read()?

Tenta ae !!! input.close(); :slight_smile:

O metodo read() da classe InputStream é sincrono.
Tente usar esta classe que cuida disso pra vc.

Classe TrataTeclado

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package br.org.luca.event;

import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.EventListenerList;


/**
 * Classe responsável em tratar as entradas do teclado e
 * notificar as classes registradas.
 * @author Luca Martins
 */
public class TrataTeclado extends Thread{
    private BufferedInputStream in = null;
    private static final Integer BUFFER_SIZE = 255;
    private EventListenerList eventList = null;
    private volatile boolean run = false;
    private boolean reverse = false;
    
    /**
     * Construtor - Instancia e inicia esta Thread
     */
    public TrataTeclado(){
        eventList = new EventListenerList();        
        in = new BufferedInputStream(System.in);
        start();
    }    
    
    /**
     * Registra a classe para ser notificada quando houver um comando
     * @param l Classe a ser notificada
     */
    public void addEventoTecladoListener( CommandListener l ){
        eventList.add(CommandListener.class, l);
    }
    /**
     * Desregistra a classe da lista de eventos
     * @param l Classe a ser removida
     */
    public void removeEventoTecladoListener( CommandListener l ){
        eventList.remove(CommandListener.class, l);
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void start(){
        run = true;
        super.start();
    }
    /**
     * Dispara os eventos para as classes registradas
     * @param toString Comando que será enviado para as classes
     */
    private void fireTecladoEvent(String toString) {
        CommandListener listeners[] = eventList.getListeners( CommandListener.class );
        EventoTeclado evt = new EventoTeclado(this, 1);
        String str[] = parse(toString);
        
        evt.setCommand(str[0]);
        evt.setParam(str[1]);
        for( CommandListener listener : listeners ){
            listener.commandReceived(evt);
        }
    }    

    /**
     * Instrui se o comando recebido da entrada deve ser
     * revertido antes de notificar as classes do evento.
     * <br><br><font size=3 color='red'>Atenção! Este metodo foi criado
     * para corrigir um bug no netbeans 6.0, que em determinados momentos recebe
     * o input de forma invertida.</font>
     * @param reverse Se a string deve ser invertida {@code Boolean.TRUE}
     * caso contrario {@code Boolean.FALSE}
     */
    public void setReverseOn( boolean reverse ){
        this.reverse = reverse;
    }
    
    /**
     * Metodo que faz a execução dessa Thread finalizar
     */
    public void paraTudo(){
        run = false;
    }

    private String[] parse( String cmd ){
        String ret[] = new String[2];
        Integer index = cmd.indexOf(" ");
        if( index <= 0 ){
            ret[ 0 ] = cmd;
        }else{
            ret[ 0 ] = cmd.substring(0, index);
            ret[ 1 ] = cmd.substring(index);
        }
        
        return ret;
    }

    
    /**
     * Consome a entrada do teclado
     */
    public void run(){
        byte buffer[] = new byte[ BUFFER_SIZE + 1 ];
        int read = -1;
        StringBuffer strb = new StringBuffer();
        
        while(run){
        
            try {
                //Aguarda existir algo na entrada
                while (in.available() <= 0) {
                    Thread.sleep(100);
                }
                
                while( in.available() > 0  ){
                    read = in.read(buffer);
                    strb.append( new String( buffer, "UTF-8").trim() );
                    Arrays.fill(buffer, (byte)0);
                }
                
                /*fireTecladoEvent( strb.reverse().toString() );*/
                fireTecladoEvent( reverse ? strb.reverse().toString() : strb.toString() );
                strb.delete(0, strb.length() );
                Thread.sleep(10);
            } catch (Exception ex) {
                Logger.getLogger(TrataTeclado.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
    }
}

Classe EventoTeclado

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package br.org.luca.event;

import java.awt.AWTEvent;
import java.awt.Event;

/**
 *
 * @author Luis.Leao
 */
public class EventoTeclado extends AWTEvent{
        private String cmd, param;

    public String getParam() {
        return param;
    }

    protected void setParam(String param) {
        this.param = param;
    }
        
    protected EventoTeclado( Event ev ){
        super(ev);
//            eventList = new EventListenerList();
    }
    protected EventoTeclado( Object src, int id ){
        super(src, id);
//            eventList = new EventListenerList();
    }        

    protected void setCommand( String cmd ){
        this.cmd = cmd;
    }
    public String getCommand(){
        return cmd;
    }
}

Interface CommandListener

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package br.org.luca.event;

import java.util.EventListener;

/**
 *
 * @author Luis.Leao
 */
public interface CommandListener extends EventListener{
    public void commandReceived(EventoTeclado evt);
}

Lembre-se ao finalizar sua aplicação chamar o metodo TrataTeclado.paraTudo().
Ela implementa o esquema de evento, então quando vc quiser que alguem receba o que foi digitado na entrada vc deve adicionar ao listener da classe TrataTeclado.
Qualquer Duvida estamos aqui!

Foi mal, esqueci de colocar um exemplo de uso!!

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package br.org.luca;

import br.org.luca.event.CommandListener;
import br.org.luca.event.EventoTeclado;
import br.org.luca.event.TrataTeclado;
import br.org.p2p.SharedFile;
import br.org.p2p.SharedFileManager;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Luis.Leao
 */

public class Main {
    
    //Debugger debug = Debugger.getInstance();
    TrataTeclado trataTeclado = new TrataTeclado();
    volatile boolean run = true, pause = false;

    public Main(){
        trataTeclado.addEventoTecladoListener(new CommandListener() {
            public void commandReceived(EventoTeclado evt) {
                if( evt.getCommand().equalsIgnoreCase("quit") ){
                    para();
                }else if( evt.getCommand().equalsIgnoreCase("pause") ){
                    pause();
                }else
                    System.err.println("Comando invalido: " + evt.getCommand());
            }
        });
//        System.setOut(debug);
//        trataTeclado.setReverseOn(true);
        for( long i = 0; run; i++ ){
            try {
                do{
                    Thread.sleep(10);
                }while( pause && run );
                System.out.printf("%d\r\n", i);
            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }
        }    
//        trataTeclado.setReverseOn(false);
    }

    public void para(){
        run = false;
        trataTeclado.paraTudo();
    }
    public void pause(){
        pause = !pause;
    }
    public static void main( String args[] ) throws InterruptedException{
        new Main();
    }
}  

O problema é que o usuário pode abrir outra tabela e uma vez fachado com close() acredito que o ImputStream não possa ser aberto novamente.

lucamartins… Valeu pelas dicas cara, mas pelo que eu saiba o JME não disponibiliza a classe BufferedInputStream. Uso o ImputStream para receber os dados de uma conexão via Socket.

Foi mal, é pq vc num disse que era JME. Mas assim, vc pode usar essa minha classe para Socket tb. Altere a classe e passe o Socket.getInputStream() como parametro do construtor. Assim, não vai importar se travar, já que vai está em outra classe.

Tente usa-la assim.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package br.org.luca.event;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.EventListenerList;


/**
 * Classe responsável em tratar as entradas do teclado e
 * notificar as classes registradas.
 * @author Luca Martins
 */
public class TrataTeclado extends Thread{
    private InputStream in = null;
    private static final Integer BUFFER_SIZE = 255;
    private EventListenerList eventList = null;
    private volatile boolean run = false;
    private boolean reverse = false;
    
    /**
     * Construtor - Instancia e inicia esta Thread
     */
    public TrataTeclado(InputStream in){
        eventList = new EventListenerList();        
        this.in = in;
        start();
    }        
    
    /**
     * Registra a classe para ser notificada quando houver um comando
     * @param l Classe a ser notificada
     */
    public void addEventoTecladoListener( CommandListener l ){
        eventList.add(CommandListener.class, l);
    }
    /**
     * Desregistra a classe da lista de eventos
     * @param l Classe a ser removida
     */
    public void removeEventoTecladoListener( CommandListener l ){
        eventList.remove(CommandListener.class, l);
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void start(){
        run = true;
        super.start();
    }
    /**
     * Dispara os eventos para as classes registradas
     * @param toString Comando que será enviado para as classes
     */
    private void fireTecladoEvent(String toString) {
        CommandListener listeners[] = eventList.getListeners( CommandListener.class );
        EventoTeclado evt = new EventoTeclado(this, 1);
        String str[] = parse(toString);
        
        evt.setCommand(str[0]);
        evt.setParam(str[1]);
        for( CommandListener listener : listeners ){
            listener.commandReceived(evt);
        }
    }    

    /**
     * Instrui se o comando recebido da entrada deve ser
     * revertido antes de notificar as classes do evento.
     * <br><br><font size=3 color='red'>Atenção! Este metodo foi criado
     * para corrigir um bug no netbeans 6.0, que em determinados momentos recebe
     * o input de forma invertida.</font>
     * @param reverse Se a string deve ser invertida {@code Boolean.TRUE}
     * caso contrario {@code Boolean.FALSE}
     */
    public void setReverseOn( boolean reverse ){
        this.reverse = reverse;
    }
    
    /**
     * Metodo que faz a execução dessa Thread finalizar
     */
    public void paraTudo(){
        run = false;
    }

    private String[] parse( String cmd ){
        String ret[] = new String[2];
        Integer index = cmd.indexOf(" ");
        if( index <= 0 ){
            ret[ 0 ] = cmd;
        }else{
            ret[ 0 ] = cmd.substring(0, index);
            ret[ 1 ] = cmd.substring(index);
        }
        
        return ret;
    }

    
    /**
     * Consome a entrada do teclado
     */
    public void run(){
        byte buffer[] = new byte[ BUFFER_SIZE + 1 ];
        int read = -1;
        StringBuffer strb = new StringBuffer();
        
        while(run){
        
            try {
                //Aguarda existir algo na entrada
                while (in.available() <= 0) {
                    Thread.sleep(100);
                }
                
                while( in.available() > 0  ){
                    read = in.read(buffer);
                    strb.append( new String( buffer, "UTF-8").trim() );
                    Arrays.fill(buffer, (byte)0);
                }
                
                /*fireTecladoEvent( strb.reverse().toString() );*/
                fireTecladoEvent( reverse ? strb.reverse().toString() : strb.toString() );
                strb.delete(0, strb.length() );
                Thread.sleep(10);
            } catch (Exception ex) {
                Logger.getLogger(TrataTeclado.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
    }
}

[quote=lucamartins]Foi mal, é pq vc num disse que era JME. Mas assim, vc pode usar essa minha classe para Socket tb. Altere a classe e passe o Socket.getInputStream() como parametro do construtor. Assim, não vai importar se travar, já que vai está em outra classe.
[/quote]

No JME o SocketConnection usa o método .openInputStream() para abrir um InputStream. Não posso fazer isso no construtor e chamar uma nova classe porque de qualquer forma o antigo InputStream vai estar aberto e esperando os dados com o métodos read() oque resultará no mesmo problema atual.

A única forma que vi até agora é colocar este InputStream.read() dentro de uma Thread e quando eu quiser pará-lo chamar o Thread.interrupt(), o problema é que o interrupt() gera Exceções nos celulares Nokia, exeções estas que fazem a aplicação parar geral.

[quote=JavaES][quote=lucamartins]Foi mal, é pq vc num disse que era JME. Mas assim, vc pode usar essa minha classe para Socket tb. Altere a classe e passe o Socket.getInputStream() como parametro do construtor. Assim, não vai importar se travar, já que vai está em outra classe.
[/quote]

No JME o SocketConnection usa o método .openInputStream() para abrir um InputStream. Não posso fazer isso no construtor e chamar uma nova classe porque de qualquer forma o antigo InputStream vai estar aberto e esperando os dados com o métodos read() oque resultará no mesmo problema atual.

A única forma que vi até agora é colocar este InputStream.read() dentro de uma Thread e quando eu quiser pará-lo chamar o Thread.interrupt(), o problema é que o interrupt() gera Exceções nos celulares Nokia, exeções estas que fazem a aplicação parar geral.[/quote]

Eu não conheço quase nada de programação para movéis, então me desculpa se falar algo errado. :slight_smile:
O que acontece é que existe alguma maneira de vc pegar o InputStream do SocketConnection, não tem? Então, para cada socket que vc abrir vc cria uma classe chamada TrataTeclado, que deve ser obviamente renomeada. Assim, cada cliente tem seu esquema de controle do comando recebido. A ideia, eu acho, que está implementado nessa minha classe, já que ela bufferiza e notifica a galera que tem interesse naquela informação.

Isso num fórum de Java Micro Edition 8)

Isso num fórum de Java Micro Edition 8)[/quote]
Nô… Fui muito mané! Vou prestar mais atenção… É pq eu fui direto no “Tópicos Recentes”…

O que vale é a intenção.

Não consegui resolver da forma que eu queria, mas, como o prazo está apertado eu fiz da seguinte forma:
1º- Quando eu saio da tabela envio uma menssagem “VOLTAR” ao servidor;
2º- Ao receber a menssagem “VOLTAR” o servidor me responde “OK”;
3º- Como o InputStream.read() fica esperando receber dados para continuar, ao receber a menssagem “OK” ele a lê e dá continuidade ao código o que permite ao código verificar se deve chamar o InputStream.read() novamente ou não;
4º- Antes de chamar o InputStream.read() novamente o código é avisado de que não deve chamá-lo denovo, assim ele volta para a tela com a lista de tabelas.

Não deixa de ser uma solução eficaz.