события Java и слушатели, плохая реализация? - PullRequest
0 голосов
/ 06 февраля 2011

В настоящее время я реализую пользовательские события и слушателей в соответствии с кодом, размещенным ниже.Мне сказали, что это очень грязная реализация, и это нужно изменить.Тем не менее, я очень плохо знаком с Java и Android и не вижу, что не так с текущей реализацией. Способ, которым у меня есть это ниже, работает и, кажется, делает все, что мне тоже нужно.Мне было интересно, могут ли некоторые люди взглянуть на мой код и дать несколько советов о том, что я должен изменить и что я делаю неправильно. Взяв мой пример и изменив его, чтобы я мог видеть, о чем вы говоритес благодарностью.

Заранее спасибо!

/* SmartApp.java */
public class SmartApp extends Activity 
{
    private ConnectDevice cD = new ConnectDevice();
    private DataRobot dR = new DataRobot();
    private DataBuilder dB = new DataBuilder();
    private DataSender dS = new DataSender();
    public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.intro);

    cD.addDataReceivedListener(new DataReceivedListener() {
        @Override
        public void dataReceivedReceived(DataReceivedEvent event) {
            // TODO Auto-generated method stub
            dR.analyzeData(event.getData());
        }
    });
    dR.addDataAnalyzedListener(new DataAnalyzedListener() {
        @Override
        public void dataAnalyzedReceived(DataAnalyzedEvent event) {
            // TODO Auto-generated method stub
            dB.submitData(event.getData());
        }
    });
    dB.addDataBuilderListener(new DataBuilderListener() {
        @Override
        public void dataBuilderReceived(DataBuilderEvent event) {
            // TODO Auto-generated method stub
            dS.sendData(event.getData());
        }
    });
      }
}  

/* ConnectDevice.java
 * This class is implementing runnable because i have a thread running that is checking
 * the contents of a socket. Irrelevant to events. */
public class ConnectDevice implements Runnable {

    private List _listeners = new ArrayList();
    private String data;

    /* Constructor */
    public ConnectDevice() {// does some socket stuff here, irrelevant to the events}
    public void run() {// does some socket stuff here, irrelevant to the events}

    public synchronized void addDataReceivedListener(DataReceivedListener listener) {
        _listeners.add(listener);
    }
    public synchronized void removeDataReceivedListener(DataReceivedListener listener) {
        _listeners.remove(listener);
    }
    private synchronized void fireDataReceivedEvent(String temp) {
        DataReceivedEvent dRE = new DataReceivedEvent(this, temp);
        Iterator listeners = _listeners.iterator();
        while(listeners.hasNext()) {
            ((DataReceivedListener)listeners.next()).dataReceivedReceived(dRE);
        }
    }
    public interface DataReceivedListener {
        public void dataReceivedReceived(DataReceivedEvent event);
    }
}  

/* DataRobot.java */
public class DataRobot {
    /* This class is for analyzing the data */
    private List _listeners = new ArrayList();
    private String data;
    public boolean analyzeData(String temp) {
        /* Analyze the data
         * This function analyzes the data, as explained in the OP
         * This function fires the analyzed data event when finished
             * analyzing the data.
         */
        data = temp;
        fireDataAnalyzedEvent(data); // this fires the dataanalyzedevent
        return true; //for now this will always return true
    }

    public synchronized void addDataAnalyzedListener(DataAnalyzedListener listener) {
        _listeners.add(listener);
    }
    public synchronized void removeDataAnalyzedListener(DataAnalyzedListener listener) {
        _listeners.remove(listener);
    }
    private synchronized void fireDataAnalyzedEvent(String temp) {
        DataAnalyzedEvent dRE = new DataAnalyzedEvent(this, temp);
        Iterator listeners = _listeners.iterator();
        while(listeners.hasNext()) {
            ((DataAnalyzedListener)listeners.next()).dataAnalyzedReceived(dRE);
        }
    }
    public interface DataAnalyzedListener {
        public void dataAnalyzedReceived(DataAnalyzedEvent event);
    }
}  

/* DataBuilder.java */
public class DataBuilder {
    private List _listeners = new ArrayList();
    private String data;
    public boolean submitData(String temp) {
            /* Builds the data
             * This function builds the data, as explained in the OP
             * This function fires the databuilder data event when finished
                     * building the data.
             */
        data = temp;
        fireDataBuilderEvent(data); //firing the databuilder event when finished
        return true;
    }
    public synchronized void addDataBuilderListener(DataBuilderListener listener) {
        _listeners.add(listener);
    }
    public synchronized void removeDataBuilderListener(DataBuilderListener listener) {
        _listeners.remove(listener);
    }
    private synchronized void fireDataBuilderEvent(String temp) {
        DataBuilderEvent dRE = new DataBuilderEvent(this, temp);
        Iterator listeners = _listeners.iterator();
        while(listeners.hasNext()) {
            ((DataBuilderListener)listeners.next()).dataBuilderReceived(dRE);
        }
    }
    public interface DataBuilderListener {
        public void dataBuilderReceived(DataBuilderEvent event);
    }
}  

/* DataSender.java */
/* this class has no event, because it is done firing events at this point */
public class DataSender {
    private String data;
    public boolean sendData(String temp) {
        data = temp;
        return true;
    }
}  

НижеВот объекты события для каждого события.Я определил все это в отдельном файле, но не уверен, что это хорошая процедура.

/* DataReceivedEvent.java */
public class DataReceivedEvent extends EventObject{
    private String data;
    public DataReceivedEvent(Object source, String temp) {
        super(source);
        // TODO Auto-generated constructor stub
        data = temp;
    }
    public String getData() {
            // this function is just an accessor function
        return data;
    }
}  

/* DataAnalyzedEvent.java */
public class DataAnalyzedEvent extends EventObject{
    private String data;
    public DataAnalyzedEvent(Object source, String temp) {
        super(source);
        // TODO Auto-generated constructor stub
        data = temp;
    }
    public String getData() {
            // this function is just an accessor function
        return data;
    }
}  

/* DataBuilderEvent.java */
public class DataBuilderEvent extends EventObject {
    private String data;
    public DataBuilderEvent(Object source, String temp) {
        super(source);
        // TODO Auto-generated constructor stub
        data = temp;
    }
    public String getData() {
            // this function is just an accessor function
        return data;
    }
}

Ответы [ 2 ]

2 голосов
/ 06 февраля 2011

Я согласен с @SingleShot в теории, для частей вашего Android-приложения, которые могут быть независимыми от Android, и до тех пор, пока накладные расходы, вносимые всеми слоями косвенности, не слишком сильно замедляют работу приложения.ИМХО, во многих приложениях это описание сравнительно мало соответствует.

В другом посте вы предложили свое решение для одного занятия для общения с другим занятием.В Android действия - это не просто объекты Java, которые вы можете волочить за собой.Они управляются ОС и имеют определенный жизненный цикл.Хотя шаблон наблюдатель / наблюдаемый в некоторых местах весьма восхитителен, он не подходит, когда соединение наблюдатель / наблюдаемый создаст проблемы со сборкой мусора.В частности, одно действие не может и не должно пытаться удерживать какой-либо интерфейс слушателя в другом действии.

Точно так же чистый шаблон наблюдатель / наблюдаемый может сломаться перед лицом баз данных, потоков, служби другие кусочки реальности Android.

Итак, в чистом Java-коде, изолированном от Android, то, что у вас, вероятно, в порядке.Однако не стоит рекомендовать его как решение для проблем, связанных с Android, если вы не знаете, , что он будет работать для этих проблем, специфичных для Android.И, когда вы начнете пытаться заставить свой код работать в приложении Android, не удивляйтесь, если вы столкнетесь с проблемами, пытаясь заставить реализацию шаблона учебника работать в рамках ограничений, наложенных на приложения Android.

2 голосов
/ 06 февраля 2011

Я бы не сказал, что это «очень грязная реализация». Использование обратных вызовов / наблюдателей / слушателей, по моему мнению, хорошая практика.

Когда я пишу приложения для Android, мне нравится делать слои таким образом, чтобы «приложение» было простой старой Java без импорта Android и теоретически могло использоваться в приложении Swing, веб-сайте на основе Java EE и т. Д. "часть строго пользовательского интерфейса.

Для чего я использую обратные вызовы, это чтобы код Android регистрировал интерес к событиям, происходящим в приложении. Например, в игре «Блэкджек» Activity может вызвать game.getDealer().playHand(), чтобы сообщить приложению выполнить логику игры дилера. Поскольку эта логика выполняется в приложении, события запускаются как cardDrawn(card), cardFlipped(card), handTotalChanged(handTotal) и т. Д. Часть приложения в Android слушает их и соответственно перерисовывает объекты на экране (но ничего не знает о Блэкджеке) .

На самом деле мои действия просто реализуют интерфейсы, такие как CardListener, HandListener и т. Д., Чтобы они могли получать событие напрямую (в отличие от того, как вы это делаете), но ваш стиль не обязательно плохой.

...