Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: AudioRecorder класс. Не корректное поведение

Всем привет форумчане!

Просто молю Вас о помощи с поиском причины следующей проблемы:

Имеем класс, задача которого во время входящего звонка начать запись звука, далее его преобразование и запись в PCM формате. 

Имеем класс startRecording() который выполняет сию функцию.

Проблема в том, что при вызове метода recorder.StartRecording()  метод recorder.getRecordingState()  ИНОГДА!!! возвращает нам RECORDERSTATE_STOPPED
 
Проблема заключается в том, что бывает 100 раз под ряд все работает хорошо, а бывает 40 хорошо, далее 20 раз не возможно начать запись - выходим из метода с дебаг логами, далее опять 40 хорошо. Никаких значимых влияющих факторов не нашел. Перезагрузка телефона помогает иногда. Иногда не помогает. Как видно из кода повторная инициализация не помогает. Повторная попытка запустить запись тоже.


   
Код

private void startRecording() {

        RLog.log(LogLevel.LOW, TAG, "startRecording()");

        //Create Recorder
        recorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_DOWNLINK, 44100,  // (Rx audio source)
                AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, BufferElements2Rec * BytesPerElement);
        //Check Recorder State
        if (recorder.getState() != AudioRecord.STATE_INITIALIZED) {
            recorder.release();
            recorder = null;
            log(LogLevel.LOW, TAG, "Audio preparation failed");
            return;
        }
        recorder.startRecording();
        log(LogLevel.LOW, TAG, "recorder.getRecordingState()" + recorder.getRecordingState());

        if(recorder.getRecordingState()==AudioRecord.RECORDSTATE_STOPPED){
            RLog.log(LogLevel.LOW, TAG, "AudioRecord.startRecording() failed. Try one more time");
            if(audioRecorderOneMoreTryFlag){
                recorder.release();
                recorder = null;
                audioRecorderOneMoreTryFlag = false;
                waitLoop(5);
                startRecording();
            }else{
                log(LogLevel.LOW, TAG, "AudioRecord object failed again. FAIL. ");

                //Debug info TODO: delete after fix
                log(LogLevel.LOW, TAG, "recorder.getRecordingState()" +recorder.getRecordingState());
                log(LogLevel.LOW, TAG, "recorder.getState()" +recorder.getState());
                log(LogLevel.LOW, TAG, "recorder.getAudioSessionId()" +recorder.getAudioSessionId());
                log(LogLevel.LOW, TAG, "recorder.getAudioSource" +recorder.getAudioSource());
             
                //EXIT 
                return;
               
       
            }
            return;
        }





В чем по Вашему может быть дело?  
Буду благодарен любой помощи !
Ответ:
Сейчас развернутый ответ дать не успею; вкратце - мне помог .
Вопрос: Как объявить статический класс?

В Android Studio заметил интересную вещь, есть некий класс (AlertDialog.Builder), объявлен как static, но в то же время можно создавать его экземпляр. Как такое может быть? Я знаком со статическими полями, методами, а вот можно ли объявлять весь класс статическим? Пробовал сделать это в Eclipse-подчеркивает красным, не дает. Помогите пожалуйста разобраться
Ответ: Статический внутренний класс должен обращаться к нестатическим членам своего внешнего класса при помощи объекта, т.е. он не может обращаться напрямую на нестатические члены своего внешнего класса(тоесть объект внемшего класса не создаётся)

Внутренний класс(non-static) имеет доступ ко всем переменным и методам своего внешнего класса и может непосредственно ссылаться на них(значит объект внешнего класса создаётся и существует, как минимум, пока существует объект внутреннего класса). Если вам понадобится получить ссылку на объект внешнего класса, запишите имя внешнего класса, за которым следует точка, а затем ключевое слово this.

Вопрос: Класс не видит ресурсы через контекст

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

Приложение при первом запуске создаёт БД. Соответственно есть 2 класса-синглтона:
MyApplication унаследованный от Application - класс для преинициализации всего что мне нужно будет в дальнейшем, в т.ч. вызов класса Db;
Db унаследованный от SQLiteOpenHelper для работы с БД. Всё тривиально, реализованы методы onCreate и onUpgrade + мои собсвенные.

Я не хотел хардкодить SQL-инструкции ни в классе MyApplication ни в Db, а убрал их в string-array в в xml-файл с ресурсами в res\values-ru. Доступ к массиву получаем
Java
1
String[] groupArray = context.getResources().getStringArray(R.array.groups);
Так вот в классе MyApplication массив groupArray формируется нормально, а в классе Db нет. Если попытаться вызвать метод getResources() происходит ошибка:

java.lang.RuntimeException: Unable to create application com.android.tools.fd.runtime.BootstrapApplication: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference

Но ведь я получаю контекст методом getApplicationContext() в классе MyApplication и передаю его параметром при вызове класса Db. Там в классе Db в конструкторе ссылка на контекст присваивается приватному полю context. По идее должно работать. Но нет.

Файл с массивом SQL-инсертов:
XML
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="groups">
        <item>Insert into groups (groups,group_runame) VALUES (\'string1\',\'string1\')</item>
          ................................................................................................................
        <item>Insert into groups (groups,group_runame) VALUES (\'string2\',\'string2\')</item>
    </string-array>
</resources>
MyApplication
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package ru.arvalon.mytraining;
 
import android.app.Application;
import android.util.Log;
import android.widget.ArrayAdapter;
 
/**
 * Created by arvalon on 04.05.2016.
 */
public class MyApplication extends Application {
 
    private static  MyApplication singleton;
    private Db db;
 
    public static MyApplication getInstance(){
        return singleton;
    }
 
 
    @Override
    public void onCreate() {
        super.onCreate();
        singleton=this;
        db=Db.getInstance(getApplicationContext());
        
        String[] groupArray = getResources().getStringArray(R.array.groups); // ТУТ РАБОТАЕТ!
        for(int i=0;i<groupArray.length;i++){
            db.addGroup(groupArray[i]);
        }
    }
}
Класс Db
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package ru.arvalon.mytraining;
 
import android.app.Application;
import android.content.ContentValues;
import android.content.Context;
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import android.widget.ArrayAdapter;
 
public class Db extends SQLiteOpenHelper {
 
    private Context context;
    public static Db instance;
 
    private Db(Context context) {
        super(context, DB_NAME, null, VERSION);
        getWritableDatabase();
        this.context=context;
    }
 
    public static Db getInstance(Context context){
        if (instance==null){
            instance= new Db(context);
        }
        return instance;
    }
 
    @Override
    public void onCreate(SQLiteDatabase db) {
        
        String[] groupArray = context.getResources().getStringArray(R.array.groups); // НА ЭТОЙ СТРОЧКЕ ОШИБКА
       
    }
 
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        
    }
 
    public void addGroup(String group){
        SQLiteDatabase db=getWritableDatabase();
        try {
            db.beginTransaction();
            db.execSQL(group);
 
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();
        }
    }
}
Немного почистил классы от лишнего кода, оставил только прохождение к методу onCreate базы и строчку с ошибкой в нём.
Можете подсказать, почему не доступны ресурсы в классе Db, ошибка NullPointerException?
Ответ:
Сообщение от Паблито
this.context=context;
getWritableDatabase();
Действительно, заработало! Спасибо!

Добавил в конструктор getWritableDatabase() т.к. БД SQLLite не создаётся пока что-нибудь не вызвать с getWritableDatabase(), но отдельный метод-заглушку с getWritableDatabase() в классе Db писать не хотел. Опытным путём просто добавил getWritableDatabase() без какой-либо ссылки в конструктор, но добавлять надо было после инициализации поля context.
Вопрос: Использование класса

Небольшая предыстория, пишу крестики-нолики, есть начальное активити, с настройками, а есть акивити с самой игрой. Короче говоря, в том активити, что с игрой как-то стало многова-то кода, вот я и решил попробовать вынести хотя бы метод проверки победителя в другой класс (файл)

Теперь вопросы,
1. Стоит ли каждый раз создавать класс при вызове ф-ции, или просто объявить его глобально и создать в oncreate?

2. Вызываю ф-цию вот так:
Java
1
new CheckWin(this, game, _x_, c);
,
соответственно сам класс:
Java
1
2
3
public class CheckWin {
...
    public CheckWin(XO xo_, String game, int _x_, int c) {
В общем мне показалось, что так кода меньше, да и капельку удобнее. Это вообще правильно? Или лучше в конструкторе класса только присваивать значения переменным, а уж потом вызывать саму ф-цию?

3.И, допустим, мне из класса нужно вызвать, например, Toast, пока лучшего способа, кроме как передать класс, как значение переменной при вызове ф-ции я не придумал. (в примере кода во втором пункте это видно). Ну и в идеале, мне бы ещё возможность взаимодействовать с интерфейсом из класса, что при таком подходе вполне себе можно. Только вот мне почему-то кажется, что это не самый лучший способ... Короче вопрос, мой способ нормальный, или это нужно делать как-то по-другому?
Ответ: Да, делаю я это скорее просто поразвлечься, но всё-таки хотелось бы узнать, как это надо делать правильно, ну и буду не против, если дадите пару советов или каких-нибудь ссылок по поводу вынесения ф-ций в отдельные файлы(классы) и как их потом юзать.

Добавлено через 4 часа 30 минут
Ну и если можно, то ответьте хотя бы на первый вопрос.
И да, в моём случае всяких проблем с памятью не должно возникнуть? Ну, например, что класс не будет выгружаться из памяти, или что-то вроде того? Кстати, то, что я передаю экземпляр активити в виде переменной, это получается работает просто как ссылка?
Вопрос: Класс ждет действия и "дарит" данные активности

Вот сижу и думаю:
А реально сделать класс, который будет работать в отдельном потоке. Он постоянно проверяет что то (while (true)) и если действие происходит, то оно сообщает активити о действии. Тут все понятно. Но есть одно но, а что если мы запустили этот класс и стартанули другое активити, не завершая этого. Так вот, будет ли этот класс работать в это время? Крашнется ли все это? Или заработает все отлично и все будет обновляться и когда мы перейдем на тот класс снова, кнопкой назад, и тут будет все прекраснос обновленным листвью и т.д.?
Ответ: akyma40,

Не по теме:

этого гугл не выдаст,это основано на опыте более года дружбы с андрюхой


У вашего приложения ВСЕГДА должна быть КОНЦЕПЦИЯ и МАКЕТ, если нет чего-то из них,то в большом проекте будет туго, придется его переписывать часто, а кому кайф 10к кода переписывать?
Еще есть пару замечаний:
1) В этом классе можно хранить экземпляры объектов таких как БД, нотификации и т.д., но помните о том, что это как и сервис часть приложения, а значит он работает в основном потоке;
2) Для "тяжелых и долгих" операций используется всегда сервис, или хотя бы класс отдельный;
3) Для объектов БД и нотификаций лучше всего использовать паттерн Singleton, шаблон которого вы можете добавить из студии

Добавлено через 4 минуты
Забыл еще кое-что, как получить этот класс в активити:
Java
1
2
3
4
5
    private App app;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
     app = (App) getApplication();
Вопрос: SharedPreferences в другом классе

Здравствуйте. Вопрос такой.
есть основной класс MainActivity и другой класс, пытаюсь в нем сохранить переменную string в SharedPreferences что бы считать потом в классе MainActivity, но среда говорит что не правильно. А именно либо подчеркивает "this"

Java
1
2
3
4
        SharedPreferences sPref = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor ed = sPref.edit();
        ed.putString("yes","yes");
        ed.apply();
либо если делаю
Java
1
2
3
        SharedPreferences kmsset = getSharedPreferences("kms", MODE_PRIVATE);
        SharedPreferences.Editor editor = kmsset.edit();
        editor.putString("yes","yes");
то пишет что getSharedPreferences не знает что это такое.
Как обращаться к одной и тойже переменой из разных классов ?
Ответ: JerryLetehen, класс утилита, примерно как SharedPreferenceHelper, что выше. либо загруженные данные складывать в класс хранилище данных, либо уже в базу данных, либо на диск записывать в виде файла. но легче всего через SharedPreference
Вопрос: Кусок кода в отдельный класс

Ребята, всем доброй ночи. Написал я свою первую программу тест, но мама мия! У меня не activity а простыни какие то. И я понимаю, что со временем будет только хуже и жутко не удобно. Вычитал, что можно функции вынести в отдельный класс и подключатся к нему из главной activity, а вот сделать это на практике не могу. P.S. Может есть книги где можно почитать как это сделать?

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 if(reed==12){ // ecли пройдено 12 ячеек
                if(tobe){// если нажат пункт меню ToBe...
                    if(mySettings1.contains(Tobe_ArrayList)){// если сохранен Tobe_ArrayList
 
                        SharedPreferences.Editor editor = mySettings1.edit();
                        editor.remove("Tobe_ArrayList"); // удаляем Tobe_ArrayList
                        editor.apply();
 
 
                        displayResult2();
 
                    }
                    else {//ecли пройдено 12 ячеек и нажат пункт меню ToBe, но НЕ сохранен Tobe_ArrayList
 
                        displayResult();
 
                        listStr = new Gson().toJson(new ArrayList<Integer>(Arrayl));// сохраняю Arrayl в строку
 
                        Log.d("","Сохраненный Tobe_ArrayList:" + Arrayl);
 
                        SharedPreferences.Editor editor = mySettings1.edit();
                        editor.putString(Tobe_ArrayList, listStr);// cохраняем Arrayl в строке в SharedPreferences
                        editor.apply();
                    }
 
 
            }//End Push_ToBe
 
            }//if(reed==12)
 
          if(itenglish){// если нажат пункт меню IT English
 
            if(reed==12){// ecли пройдено 12 ячеек
 
                if(mySettings1.contains(ITenglish_ArrayList)){// если сохранен ITenglish_ArrayList
 
                    SharedPreferences.Editor editor = mySettings1.edit();
                    editor.remove("ITenglish_ArrayList"); // удаляем ITenglish_ArrayList
                    editor.apply();
 
 
                } // End ITenglish_ArrayList
 
                else{//ecли нажато меню IT English и пройдено 12 ячеек, но НЕ сохранен параметр ITenglish_ArrayList
 
                    displayResult();
 
                    listStr = new Gson().toJson(new ArrayList<Integer>(Arrayl));// сохраняю Arrayl в строку
                    System.out.println("Сохраненный ITenglish_ArrayList" + Arrayl);
 
                    SharedPreferences.Editor editor = mySettings1.edit();
                    editor.putString(ITenglish_ArrayList, listStr);// cохраняем Arrayl в строке в SharedPreferences
                    editor.apply();
                }
 
            }// End reed
 
          }// End itenglish
Ответ: есть несколько варриантов как это сделать, зависит от самой функции.
1) Делаются классы Utils, с паблик статик функциями, например если в приложении надо конвертировать миллисекуны в дни, или в часы, то делаем класс ConvertUtils, в нем деалаем:
Java
1
2
3
4
5
public static int milliToDays(long millisec){
int days = 0;
//конвертируем 
return days;
}
и теперь с мейн активити просто вызываем Названиекласса.названиефункции,int days = ConvertUtils.milliToDays(121211213);

таким образом все методы связанные в одну общую тему будут лежать в одном ютилс и можно с любого места в проекте их достать.

2) Создание обьектов или вью со своими функциями. например если в строчке есть кнопка и эдит текст, можно их запихнуть в один класс, и в нем выполнять операции связанные с этими двумя обьектами а в мейн только возвращать результат. это посложнее.
3) создание менеджеров. например у Вас в проекте повторяются ШаредПреференс, их можно запихнуть в менеджер, создать класс шаредпреференсменеджер, обычно такие классы синглтон, и в нем собрать список всех функций которые по теме шардпреференс. так же такой менеджер может быть статическим классом как в первом случае. сингл тон обычно не советуют использовать, он может делать лики, им надо уметь пользоваться и правельно передавать ему контекст.

есть еще варрианты, но думаю этого хватит чтоб навести порядок в проекте
еще, посмотрите что такое повторение кода, этого тоже надо избегать.
еще, посмотрите что такое нейминг, тоже облегчает работу
удачи
Вопрос: Как в отдельном классе сохранять переменные?

Добрый день!

есть класс, в нем сотни переменных, их значения меняются.

как сохранять их значения и как вызывать из другого класса напр. MainActivity и т.п.?

т.е. понимаю что мне SharPrefs надо, но как вынести в другой класс и этим пользоваться не понимаю...
Ответ: Думаю здесь вам поможет SQLite
Класс для работы с бд.
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
public class DataBaseHelper extends SQLiteOpenHelper {
 
    String DB_PATH = null;
    private static String DB_NAME = "DB_Tank_info16";
    private SQLiteDatabase myDataBase;
    private final Context myContext;
 
    public DataBaseHelper(Context context) {
        super(context, DB_NAME, null, 10);
        this.myContext = context;
        this.DB_PATH = "/data/data/" + context.getPackageName() + "/" + "databases/";
        Log.e("Path 1", DB_PATH);
 
 
    }
 
 
    public void createDataBase() throws IOException {
        boolean dbExist = checkDataBase();
        if (dbExist) {
        } else {
            this.getReadableDatabase();
            try {
                copyDataBase();
            } catch (IOException e) {
                throw new Error("Error copying database");
            }
        }
    }
 
    private boolean checkDataBase() {
        SQLiteDatabase checkDB = null;
        try {
            String myPath = DB_PATH + DB_NAME;
            checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
        } catch (SQLiteException e) {
        }
        if (checkDB != null) {
            checkDB.close();
        }
        return checkDB != null ? true : false;
    }
 
    private void copyDataBase() throws IOException {
        InputStream myInput = myContext.getAssets().open(DB_NAME);
        String outFileName = DB_PATH + DB_NAME;
        OutputStream myOutput = new FileOutputStream(outFileName);
        byte[] buffer = new byte[10];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }
        myOutput.flush();
        myOutput.close();
        myInput.close();
 
    }
 
    public void openDataBase() throws SQLException {
        String myPath = DB_PATH + DB_NAME;
        myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
 
    }
 
    @Override
    public synchronized void close() {
        if (myDataBase != null)
            myDataBase.close();
        super.close();
    }
 
 
    @Override
    public void onCreate(SQLiteDatabase db) {
    }
 
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (newVersion > oldVersion)
            try {
                copyDataBase();
            } catch (IOException e) {
                e.printStackTrace();
 
            }
    }
 
    //Добавление данных
    public long setInsert(String table, String nullColumnHack, ContentValues values)
    {
        return myDataBase.insert(table, nullColumnHack, values);
    }
 
 
    public  Cursor rawQuery()
 
    {
        Cursor c = myDataBase.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);
        return c;
    }
 
    //Удаление данных
    public  void delete(String table)
    {
        myDataBase.delete(table, null, null);
        myDataBase.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + table + "'");
    }
    //Чтение данных
    public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) {
        return myDataBase.query(table, null, null, null, null, null, null);
    }
}

В MainActivity
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
DataBaseHelper myDbHelper;
 
myDbHelper = new DataBaseHelper(getBaseContext());
        try {
            myDbHelper.createDataBase();
        } catch (IOException ioe) {
            throw new Error("Unable to create database");
        }
        try {
            myDbHelper.openDataBase();
        } catch (SQLException sqle) {
            try {
                throw sqle;
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
 
 
   ///Запись в бд (тут ваши переменные с класса)
                ContentValues contentValuesAll = new ContentValues();
                contentValuesAll.put("avg_damage_assisted", personaly_dannie.getStatistics().getAll().getAvg_damage_assisted());
                contentValuesAll.put("avg_damage_assisted_radio", personaly_dannie.getStatistics().getAll().getAvg_damage_assisted_radio());
             
 
                myDbHelper.delete("NicknameAll"); // очищаем таблицу
                myDbHelper.setInsert("NicknameAll", null, contentValuesAll); //Записываем данные

А так же чтения данных с бд
Java
1
2
3
4
5
 Cursor c = null;
        c = myDbHelper.query("NicknameAll", null, null, null, null, null, null);
        c.moveToFirst();
        setAvg_damage_assisted(c.getDouble(1));
        setAvg_damage_assisted_radio(c.getDouble(2));
Я бы на вашем месте реализовал так. При запуске приложения считывать данные с бд(если их еще нету), то указать нулевые значения. Все эти данные хранить в классе, который я указал вам выше. Чтоб не было необходимости вызывать все время БД для изменения данных. И при завершение работы приложения данные записывать в БД с того класса.
Вопрос: Параметр класса картинка или путь к ней?

Android Studio. Как создать параметр класса который отвечает за загрузку картинки. Например у меня три класса wall, door, window, отвечающие за отображение стены, двеи и окна. В классах есть другие параметры. Суть вопроса в том, как создать параметр класса указывающий на путь картинки или что-то такое и загрузить картинки в imageview, в зависимости от класса.
Ответ:
Сообщение от Дикутенз
Суть вопроса в том, как создать параметр класса указывающий на путь картинки или что-то такое и загрузить картинки в imageview, в зависимости от класса.
вот такие формулировки каждый раз выдают гуманитарии, которые зачем-то идут в программирование
ты пишешь какую-то дичь, я серьезно

и где код?
Вопрос: Ссылка на экземпляр объекта внутреннего класса

Интересная вещь-если написать внутренний класс, например, DrawView, создать его в onCreate MainActivity, а потом, используя ссылку на него в конструкторе этого вложенного класса попытаться повесить слушателя(drawView.setOnTouchListener) - то приложение крашится, а если написать просто setOnTouchListener (без явной ссылки на экземпляр), то все нормально. Почему так происходит? Спасибо заранее.
Ответ: Armagedo, Spelcrawler,ойй.. точно, я пытаюсь в конструкторе использовать ссылку на экземпляр класса, которую сам же и создаю. Лол. Затупил, спасибо.


Armagedo, не понял про козла. А под козлом вы имеете ввиду слушателя или экземпляр класса?

Добавлено через 7 минут
Armagedo, а, тут же экземпляр этого класса сам и будет слушателем, т.е. козлом. Спасибо