Страницы

Поиск по вопросам

четверг, 27 декабря 2018 г.

Слушатель выделения для ListView

Скажите, есть ли слушатель выделения элемента у ListView? Искал в гугле (на русском), но нашел только onClickListener'ы и тому подобные. Они реагируют на нажатие (когда палец отпустили), а мне нужно, чтобы слушатель реагировал на начало прикосновения к пункту списка, а потом на его отпускание. Есть такой слушатель предназначенный именно для ListView (а не onTouch)?


Ответ

Полагаю, что ваше решение - onTouchListener. Может и момент нажатия поймать, и момент отпускания.
OnTouchListener listener = new OnTouchListener() {
@Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //something break; case MotionEvent.ACTION_UP: //something } return true; } };
view.setOnTouchListener(listener);

Доступ к getAssets () из другого статического класса

Он работает с моей основной Activity и моим фрагментом, но если я использую метод LoadSound() в Sound классе, то getAssets() не работает.
public class CarnivoreFragment extends Fragment {
private int mCowSound; private View view;
private ImageButton mCowImageButton;
public CarnivoreFragment() { }
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_carnivore, container, false);
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
Sound.createOldSoundPool(); } else { Sound.createNewSoundPool(); }
mCowSound = Sound.loadSound("cow.wav");
mCowImageButton = (ImageButton) view.findViewById(R.id.imageButtonCow); mCowImageButton.setOnClickListener(onClickListener);
return view; }
View.OnClickListener onClickListener = new View.OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.imageButtonCow: Sound.playSound(mCowSound); Toast.makeText(view.getContext(), "Cow", Toast.LENGTH_SHORT).show();
break;
} } }; }
И мой класс "Sound":

public class Sound {
private static SoundPool mSoundPool; private static AssetManager mAssetManager; private static int mStreamID; private static Context context;
public Sound(Context context) { this.context = context; }
@TargetApi(Build.VERSION_CODES.LOLLIPOP) public static void createNewSoundPool() { AudioAttributes attributes = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_GAME) .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .build(); mSoundPool = new SoundPool.Builder() .setAudioAttributes(attributes) .build(); }
@SuppressWarnings("deprecation") public static void createOldSoundPool() { mSoundPool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0); }
public static int playSound(int sound) { if (sound > 0) { mStreamID = mSoundPool.play(sound, 1, 1, 1, 0, 1); } return mStreamID; }
public static int loadSound(String fileName) { mAssetManager = context.getAssets(); AssetFileDescriptor afd; try { afd = mAssetManager.openFd(fileName); } catch (IOException e) { e.printStackTrace(); Toast.makeText(context, "Не могу загрузить файл " + fileName, Toast.LENGTH_SHORT).show(); return -1; } return mSoundPool.load(afd, 1); }
}
Как решить эту проблему?


Ответ

Если создание экземпляров класса не входит в алгоритм использования класса Sound (так как все поля и методы в нем статические), то ваши методы не смогут получать контекст (так как конструктор не отрабатывает), который необходим для работы метода getAssets() В качестве решения можно предложить передавать контекст через параметры метода, в котором он требуется:
public static int loadSound(Context context, String fileName) { mAssetManager = context.getAssets(); .... }
Вызов из фрагмента:
mCowSound = Sound.loadSound(getActivity(), "cow.wav");
Если экземпляра активити будет недостаточно для контекста getAssets(), то нужно использовать другие способы доступа к контексту. Более правильно - получить экземпляр контекста один раз при создании фрагмента и "подсовывать" его везде, где требуется, а не вызывать каждый раз метод его получения.

Перевод строки в десятичное число. Java

Есть такие строки:
0x16 012 0b10 62
Нужно перевести их в:
22 10 2 62
соответственно, но при использовании Integer.parseInt(String, int) получаю NumberFormatException, как решить эту проблему?


Ответ

например, можно написать такую функцию
private static int StringToInteger(String input) { if(input.startsWith("0x")) { return Integer.parseInt(input.substring(2), 16); } else if(input.startsWith("0b")) { return Integer.parseInt(input.substring(2), 2); } else if(input.startsWith("0") && input.length() > 1) { return Integer.parseInt(input.substring(1), 8); } else { return Integer.parseInt(input); } }

Как стилизовать элемент счетчика?

  • 24

  • Как можно получить такой элемент как на картинке с помощью css (белая полоска зачеркивания идет перед цифрой)?
    P.S.: цифры при этом меняются динамически


    Ответ

    span { display: inline-block; background: #ffd800; font: 20px/1 Arial; width: 20px; border-radius: 5px; } span:before { content: ''; display: block; position: relative; top: 11px; left: 0; width: 20px; height: 2px; background: #fff; } 24

    Кастинг в коде это нормально?

    Кастинг в коде это нормальное явление или повод задуматься над тем что, что то с кодом не так?


    Ответ

    Кастинг, кастингу рознь. К примеру, если у вас в коде есть static_cast, то это может быть подозрительно, но вряд-ли опасно. Тем не менее, даже со static_cast нужно убедиться, что это не просто безответственная попытка «заткнуть» компилятор, а явное и нужное преобразование. Как правило, такие вещи нужны на стыке кода библиотек, но, в идеальном случае лучше избегать и static_cast
    Если у вас в коде появляется dynamic_cast, то есть вероятность, что вы неправильно используете полиморфизм. Тем не менее, с точки зрения корректности программы, dynamic_cast не является проблемой. Он не может ничего такого добавить, чтобы сделало программу некорректной(т.е. он не служит «затычкой» компилятора). Поэтому наличие dynamic_cast может служить признаком неправильного дизайна(и пессимизации), но не более того.
    Если у вас в коде есть const_cast, то наиболее вероятно, что у вас в коде имеет место ошибка дизайна, которая должна быть исправлена как можно скорее. В противном случае вы сами знаете, что делаете и const_cast там не случаен. Прибегать к нему стоит лишь в том случае, когда других вариантов уже не осталось. И даже в этом случае стоит 100 раз всё обдумать и взвесить, т.к. const_cast не снимает константность с объектов, которые были рождены таковыми изначально. Точнее он может снять, а может и не снять — UB, если не ошибаюсь будет в этом случае.
    Наконец, если у вас в коде есть reinterpret_cast и он не находится в коде, который работает на стыке кроссплатформенного модуля и модуля специфичного конкретной ОС, то у вас с большой долей вероятности есть проблема.
    Если же у вас в коде есть C-style касты, то, сначала, замените их на C++ аналоги, а потом удалите те, что не являются необходимостью.
    В целом, любой оператор явного преобразования является потенциальной проблемой, поэтому их использование желательно свести к минимуму. Каждое такое использование должно иметь смысл и быть необходимым.

    Как правильно обработать порядок арифметических операций?

    Делаю что-то вроде обработчика выражений, как в Excel...
    Есть входящая строка String inputStr = "5+5-10/8+8*2" (любые числа и действия).
    Как реализовать приоритет действий? Нужен алгоритм.


    Ответ

    Эта задача решается с использованием стека через формирование и подсчёт Обратной Польской Нотации .

    Как из String сделать &str (возникает ошибка времени жизни ссылки)

    Написал функцию:
    fn read_str<'a>() -> &'a str { let mut input = String::new(); io::stdin().read_line(&mut input).ok(); let output : &str = &input[..]; &output }
    При компиляции возникает ошибка
    src/main.rs:13:26: 13:31 error: `input` does not live long enough src/main.rs:13 let output : &str = &input[..]; ^~~~~ src/main.rs:10:30: 15:2 note: reference must be valid for the lifetime 'a as defined on the block at 10:29... src/main.rs:10 fn read_str<'a>() -> &'a str { src/main.rs:11 let mut input = String::new(); src/main.rs:12 io::stdin().read_line(&mut input).ok(); src/main.rs:13 let output : &str = &input[..]; src/main.rs:14 &output src/main.rs:15 } src/main.rs:11:32: 15:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 11:31 src/main.rs:11 let mut input = String::new(); src/main.rs:12 io::stdin().read_line(&mut input).ok(); src/main.rs:13 let output : &str = &input[..]; src/main.rs:14 &output src/main.rs:15 }
    Пробовал брать строку io::stdin().read_line(&mut input).ok(); в фигурные скобки, дабы ограничить &mut, но это не помогает.


    Ответ

    Вернуть из функции можно только ссылку на статический объект (с временем жизни 'static) или ссылку, которую вы получили во входных параметрах.
    Вы пытаетесь вернуть ссылку на объект созданный в стеке функции. После завершения функции все объекты в стеке будут уничтожены. Rust не позволит создать ссылку на объект, который она может пережить. Использование после освобождения (use after free)
    В вашем случае лучше всего вернуть String. Накладные расходы в этом случае невелики, так как почти вся информация внутри строки хранится в куче.

    Большинство проблем начинающих писать на Rust связаны с непониманием назначения различных типов указателей. Если не вдаваться в подробности, их там можно насчитать пять штук.
    Ссылки в Rust используются для передачи данных без передачи права владения. Например если у вас есть структура, в которой хранится строка:
    struct Person{ name:String }
    то выдавать информацию о ее содержимом лучше так:
    impl Person{ pub fn get_name(&self)->&str{ &self.name } }
    или можно вернуть копию строки:
    pub fn get_name_clone(&self)->String{ self.name.clone() }
    Но это приведет к дополнительным расходам на копирование строки. Расходы здесь возникают именно из-за копирования - вызова метода clone(), который создает вторую копию данных строки в куче, а не из-за того, что функция возвращает строку.
    Можно вернуть строку из структуры без копирования:
    pub fn get_name_own(self)->String{ self.name }
    Но после вызова этого метода исходный объект Person перестанет существовать, так как право владения было передано.
    Еще одна распространенная причина проблем - попытка хранить ссылки на другие объекты в структуре. Ссылки накладывают кучу ограничений на время жизни и мутабельность связанных объектов. Прежде чем это делать, стоит дважды подумать о возможности использования других типов указателей.

    Синхронизация выполнения функций

    Синхронизация в javascript. Например, есть три функции:
    func1(function(){}); // асинхронная с callback func2(function(){}); // асинхронная с callback func3(); // синхронная возвращает true-false
    Нужно, чтобы после того, как func1 и func2 вызвали свои callback, а func3 вернул true, вызвать функцию func4
    Как правильно и лучше всего это сделать, если ли стандартная техника для такого?


    Ответ

    Вариант 1 - наиболее разумный - использовать Promise и Deferred
    http://api.jquery.com/promise/
    http://api.jquery.com/jQuery.when/
    http://api.jquery.com/deferred.promise/
    Код:
    var d1 = $.Deferred(); var d2 = $.Deferred(); var d3 = $.Deferred();
    func1(function() { d1.notify(); }); func2(function() { d2.notify(); }); func3(); d3.notify();
    $.when( d1, d2, d3 ).done(function () { // Выполнить результирующее действие. });
    Вариант 2 - завести счетчик количества выполняемых функций (не требует библиотек) и отслеживать выполнение в общем callback-е. Возможно также вместо счетчика использовать массив с именами функций.
    var currentCallbacks = 0; var expectedCallbacks = 3;
    var commonCallback = function() { currentCallbacks++; if (currentCallbacks == expectedCallbacks) { // Выполнить результирующее действие. } };
    func1(function(){commonCallback();}); func2(function(){commonCallback();}); func3(); commonCallback();
    Вариант 3 - _underscore.js имеет функцию after. Если библиотека уже подключена, можно использовать её функционал.
    Вернёт копию функции function, модифицированную таким образом, что она будет запущена только после того, как будет вызвана count раз. Удобно использовать при работе с асинхронными запросами, например, чтобы убедиться, что все обращения к серверу завершились.
    var commonCallback = _.after(3, function() { // Выполнить результирующее действие... });
    func1(function() { commonCallback(); }); func2(function() { commonCallback(); }); func3(); // Внутри должен перед выходом из функции вызываться commonCallback();
    var functions = [func1, func2, func3]; var runProcess = function() { _.each(functions, function(func) { func(); }); };
    runProcess();
    Вариант 4 - построить цепочку вызовов, но убивает все плюсы параллелизма.
    func1(callback1);
    function callback1() { ... func2(callback2); }
    function callback2() { ... func3(); // Выполнить результирующее действие. }

    Генерация сочетаний без повторений

    Требуется перебрать все комбинации группы символов от A до X где X может быть любой другой буквой.
    Пример: дана последовательность ABCD, функция должна выдать AB, AC, AD, BC, BD, CD, ABC, BCD, CDA, ABD (вроде ничего не забыл), т.е. позиция символа в группе не важна - важна лишь уникальность самой группы.
    Гуглил в сторону размещений и сочетаний. Но так и не понял что именно из этого мне требуется. Грешен - не учил математику. Умные люди, объясните на пальцах или кодом, буду признателен.
    Update: Обычно говорят, - и года не прошло. А вот у меня как раз прошел. Снова понадобилось, в этот раз подошел обстоятельно - вот код на PHP:
    function gen_comb ($rest, $current = "", $container = []) { // Если пустой текущий и есть остаток if(!$current and $rest) { // Текущему даем первый символ остатка $current = substr($rest, 0, 1); // Потом для каждого в остатке for($i=strlen($rest); $i > 0; $i--) // формируем пару с текущим и записываем в вывод $container[] = $current . substr($rest, $i, strlen($rest)); // при этом проверяем - если в остатке один if(strlen($rest) == 1 and $current) // возвращаем результат return $container; // если в остатке больше одного и при вычете еще останется if(strlen($rest) - 1) // возвращаем рекурсивный результат с уменьшенным на 1 остатком return gen_comb(substr($rest, 1, strlen($rest)), "", $container); } }


    Ответ

    Предисловие
    Я очень люблю следующий алгоритм из-за его просто детской простоты. Он не претендует на звание самого быстрого алгоритма, но является самым простым для понимания из всех, что я встречал.
    Алгоритм
    Если учитывать и одиночные комбинации (A, B, C, D), то таких комбинаций всего 2n - 1, где n - количество символов в исходной строке.
    Допустим, что у нас строка из n символов. То есть, у нас n позиций в строке.
    A B C D E F G H ... n-1 n // ^ ^ ^ ^ ^ ^ ^ ^ ... ^ ^ 1 2 3 4 5 6 7 8 ... n-1 n // порядковый номер каждой позиции
    Рассмотрим каждую позицию нулём (0) либо единицей (1). Договоримся ставить 1 на той позиции, на которой мы хотим видеть символ, а 0 на той, на которой не хотим.
    Получится примерно следующая строка из n нулей и единиц
    0 1 0 0 1 0 0 0 ... 0 0 // полученная закодированная строка ^ ^ ^ ^ ^ ^ ^ ^ ... ^ ^ 1 2 3 4 5 6 7 8 ... n-1 n // порядковый номер каждой позиции
    Эта строка кодирует комбинацию
    _ B _ _ E _ _ _ ... _ _ // комбинация строка ^ ^ ^ ^ ^ ^ ^ ^ ... ^ ^ 1 2 3 4 5 6 7 8 ... n-1 n // порядковый номер каждой позиции
    А теперь выпишем двоичный набор длиной в n элементов
    0 0 0 0 0 0 0 0 ... 0 0|_ _ _ _ _ _ _ _ ... _ _ 0 0 0 0 0 0 0 0 ... 0 1|_ _ _ _ _ _ _ _ ... _ n 0 0 0 0 0 0 0 0 ... 1 0|_ _ _ _ _ _ _ _ ... n-1 _ 0 0 0 0 0 0 0 0 ... 1 1|_ _ _ _ _ _ _ _ ... n-1 n .......................|......................... 1 1 1 1 1 1 1 1 ... 1 0|A B C D E F G H ... n-1 _ 1 1 1 1 1 1 1 1 ... 1 1|A B C D E F G H ... n-1 n
    Этот набор выписывается достаточно просто. Если просто, то на каждой новой строке к последнему элементу прибавляется единица. И если в результате получается число больше единицы, то позиция обнуляется и единица добавляется на соседнюю слева позицию и т.д.
    Этот набор (без первого) будет описывать всевозможные комбинации исходной строки.
    Пример
    Возьмём строку ABCD. В ней 4 символа, а значит, у нас будет 24 - 1 = 15 комбинаций.
    Выпишем двоичный набор из 4 элементов
    0 0 0 0|_ _ _ _ 0 0 0 1|_ _ _ D 0 0 1 0|_ _ C _ 0 0 1 1|_ _ C D 0 1 0 0|_ B _ _ 0 1 0 1|_ B _ D 0 1 1 0|_ B C _ 0 1 1 1|_ B C D 1 0 0 0|A _ _ _ 1 0 0 1|A _ _ D 1 0 1 0|A _ C _ 1 0 1 1|A _ C D 1 1 0 0|A B _ _ 1 1 0 1|A B _ D 1 1 1 0|A B C _ 1 1 1 1|A B C D
    И получаем следующие варианты
    1) D 2) C 3) CD 4) B 5) BD 6) BC 7) BCD 8) A 9) AD 10) AC 11) ACD 12) AB 13) ABD 14) ABC 15) ABCD
    Если вам не нужны одиночные комбинации, то можете их выбросить :)