Координаты

Байку расскажу. Прислали нам как-то файлик экселевский. Табличка с десятком строк — телекоммуникационные столбы новые с координатами. Сказали, что координаты сняли GPSами… Мы полдня промучались. Никак они вдоль дороги не укладываются. После мозгового штурма родилось предположение, что прекрасный «инженер» записал «что видел». На экране 54°24’15” (54 градуса, 24 минуты, 15 секунд) записывал как 54,2415…

Изолента

Денис рассказал: «Обидно, когда час ищешь по даче какую-нибудь изоленту. Всё перерыл — нет. Едешь, покупаешь, возвращаешься. Надо положить так, чтоб потом найти — придумываешь самый заметный шкафчик, выдвигаешь, а там… предыдущие три мотка изоленты.»

onActivityResult для фрагмента

Предположим, вас занесло в чудный мир программистов для Андроид. Вы прониклись туториалами и описаниями об Активностях и Фрагментах. Начали красиво писать первые скромные поделки… Хорошо? Благодать? Уже расслабились и получаете удовольствие? А вот тут раз и из-за угла вам лопатой!

Дело было так. Вы написали Активность, а в неё чудесно вписали красивый Фрагментик. Но вы же захотели большего — вызвать из этого Фрагментика на экран другую Активность! Эка наглость… Не просто вызвать, а вызвать для результата. То есть, она для вас должна вернуть полезные данные.

Кусок текста Фрагмента:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class LittleFragment: Fragment() {
  …
    // На нажатие волшебной кнопки
    fun onClick() {
        // Формируем запрос и отправляем его, ожидая в ответ полезные данные
        val intent =
        startActivityForResult(intent, REQUEST_DATA)
    }
  …
    // Ловушка для полезных данных
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        Log.d(TAG, "onActivityResult(requestCode = $requestCode, resultCode = $resultCode)")
        if (resultCode == Activity.RESULT_OK) {
            when (requestCode) {
                REQUEST_DATA ->
                    updateSomething()
                else ->
                    Log.e(TAG, "onActivityResult: wrong request code!")
            }
        }
    }
  …
}

Начинаете эксперименты… Продолжаете эксперименты… Продолжаете… Но ловушка просто так работать отказывается. После недолгих скитаний от кофемашины до компуктера, от балкона до кота, становится ясно, что ответ получает ловушка, расположенная у родительской Активности! Вот ведь… Чего ж нас раньше в детском садике не предупредили? Тупо копируем нашу ловушку в Активность — в ответ граблями по наглой морде:

Родительская активность получает ответ немного другой формы. Хуже того, у родительской Активности могут быть свои котлеты и перемешивать их с кодами запросов нашего фрагмента — как-то не по-джентельменски. Возвращаем ловушку обратно, а у родительской Активности пишем закленания:

Код родительской Активности:

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
class MainActivity : AppCompatActivity() {
  …
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        Log.d(TAG, "onActivityResult(requestCode = $requestCode, resultCode = $resultCode)")
        if (resultCode == Activity.RESULT_OK) {
            when (requestCode) {
                REQUEST_DATA1_FOR_MAIN_ACTIVITY -> {
                    // …
                }
                REQUEST_DATA2_FOR_MAIN_ACTIVITY -> {
                    // …
                }
                else -> {
                    // Если ожидаемые коды не подходят — пытаемся определить дочерний Фрагмент,
                    // инициировавший происходящие события. requestCode в старших разрядах содержит индекс:
                    val fragmentIndex = requestCode.shr(16)
                    if (fragmentIndex>0) {
                        // Надо передать дочернему фрагменту
                        val fragments = supportFragmentManager.fragments
                        if (fragmentIndex>fragments.size)
                            Log.e(TAG, "onActivityResult: wrong request code!")
                        else {
                            Log.i(TAG, "onActivityResult: transfer result to fragment.")
                            fragments[fragmentIndex-1].onActivityResult(
                                    requestCode.and(0xFFFF),
                                    resultCode, data)
                        }
                    }
                }
            }
        }
        super.onActivityResult(requestCode, resultCode, data)
    }

Такому в Хогвардсе не учат. Это жизнь, детка!

Ошибка в миллиард долларов

sir_tony_hoare_img_5125

Сэр Чарльз Энтони Ричард Хоар изобрёл null указатели в программировании. В своей речи на конференции в 2008 году он попросил прощения за это:

— Я назвал это моей ошибкой, ценой в миллиард долларов. Изобретение ссылки null в 1965 году. В то время я разрабатывал первую всеобъемлющую систему типов для ссылок в объектно ориентированном программировании (ALGOL W). Моей целью было — гарантировать, что все ссылки абсолютно безопасны, благодаря проверкам, проводимым компилятором автоматически. Но я не устоял перед соблазном добавить null, просто потому, что это легко реализовать. Это повлекло за собой неисчислимое море ошибок, уязвимостей, системных сбоев, которые наверняка принесли ущерба в миллиарды долларов в последующие сорок лет.

via

Следует отметить, что новейшие языки программирования пытаются лучше защищаться от такого рода проблем:

Objective C: синоним null в нём является nil. Одним из самых замечательных свойств nil в Objective-C является возможность посылать ему совершенно любые сообщения (или «вызывать методы»), ответом на которые неизменно будет всё тот же nil. Можно не писать некоторые проверки:

1
2
3
4
5
/* Далеко, далеко за пределами нашей галактики… */
if (foo != nil && [foo testValue: 0x90]) { … }
   
/* Программисты же из Млечного Пути могут писать просто */
if ([foo testValue: 0x90]) { … }

Swift и Kotlin добавляют к описаниям типов данных «опциональные типы». Применяются в тех случаях, когда значение может отсутствовать. Опциональный тип подразумевает, что возможны два варианта: или значение есть, и его можно извлечь из опционала, либо его вообще нет.

Опубликовано в рубрике Android

Почему не будет мобильного приложения с картой общественного транспорта Томска

Мобильное приложение с картой общественного транспорта Томска
Вчера разговорились с моим замечательным другом предпринимателем. Относительно недавно он стал совладельцем одного из автобусных маршрутов Томска. Для меня стало большим откровением, что оказывается, мобильное приложение для пассажиров с картой маршрутов и с движущимися по ним значками реальных автобусов — ОПАСНО!

Казалось бы, реальная польза для пользователя общественного транспорта: карта, маршруты, через сколько подъедет автобус… Лепота. Но, реальность круче. Подобное приложение, как оказалось было. Но водители маршруток стали его использовать для гонок с конкурентами. И мобильное приложение сочли опасным — убрали из общего доступа.

Наконец-то снег!

До этого что-то белое выпало и долго-долго лежало тонюсеньким слоем на асфальте улиц. Так долго, что уже покрылось примерно таким же слоем пыли. А вот вчера как началось сыпаться — всем на-зависть.

IMG_20151125_085238

IMG_20151125_090227

Картина «Мир глазами ребёнка»

900-6528

Вышивка:

  • Дмитриенко Мирослава Севировна
  • Дмитриенко Анна Викторовна

Багет:

  • Дмитриенко Виктор Евгеньевич

Картина собрана для благотворительной детской выставки-ярмарки. Вырученные средства пойдут в фонд развития школы. Начальная цена — 300 ₽.

UPD: Продано.

900-6529