Страницы

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

Показаны сообщения с ярлыком kotlin. Показать все сообщения
Показаны сообщения с ярлыком kotlin. Показать все сообщения

вторник, 31 марта 2020 г.

BackUp БД postgresql через pg_dump не работает при вызове команды из Spring

#java #база_данных #postgresql #spring #kotlin


Дано:

БД postgresql на Mac. В ней есть данные и я могу сделать BackUp из консоли вызвав
/Library/PostgreSQL/10/bin/pg_dump -U db_user_name -w -c -f my_db_name.sql my_db_name,
что создаст файл my_db_name.sql в папке где я вызываю команду.

Задача:

Настроить периодический BackUp БД через Spring.

Проблема:

При вызове вышеуказанного скрипта программно получаю ошибку Файл не найден

Вопрос:

Как же это реализовать? Кажется, проблема в правах доступа к файлам/папкам, но непонятно
какая именно и как узнать конкретно.

Пробовал:

Пробовал указывать абсолютный путь типа {ПУТЬ_К_ПРОЕКТУ_СПРИНГА}/my_db_name.sql или
/Users/myusername/my_db_name.sql - не помогает.

Код:

@Scheduled(cron = "0 * * * * *")
fun backUpDb() {
    val executeCmd = "/Library/PostgreSQL/10/bin/pg_dump -U $dbUserName -w -c -f
$database.sql $database"

    val runtimeProcess: Process
    try {
        val pb = ProcessBuilder(executeCmd)
        pb.redirectOutput(Redirect.INHERIT)
        pb.redirectError(Redirect.INHERIT)
        runtimeProcess = pb.start()
        val processComplete = runtimeProcess.waitFor()

        if (processComplete == 0) {
            println("Backup created successfully")
        } else {
            println("Could not create the backup")
        }
    } catch (ex: Exception) {
        ex.printStackTrace()
    }
}


Лог:

java.io.IOException: Cannot run program "/Library/PostgreSQL/10/bin/pg_dump -U db_user_name
-w -c -f my_db_name.sql my_db_name": error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at ru.scp.quiz.service.quiz.QuizServiceImpl.backUpDb(QuizServiceImpl.kt:75)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
    at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.(UNIXProcess.java:247)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)

    


Ответы

Ответ 1



Проблема оказалась в том, что команда в одной строке не распознаётся и надо составлять массив из каждой её части и тогда оно работает. Т.е. надо команду в массив превратить при передаче ProcessBuilder-у: val pb = ProcessBuilder(executeCmd.split(" "))

среда, 4 марта 2020 г.

Модификация метода

#android #kotlin


Изначально у меня метод выглядит следующим образом:

override fun onListItemClick(itemIndex: Int, itemCode: String) {
    val data = adapter.getItem(itemIndex)
    if (data is TitleValueItem) {
        when (data.titleId) {
            R.string.v2_mobile_settings_language -> onLanguageClick()
        }
    }
}


теперь я его решил преобразовать таким образом:

override fun onListItemClick(itemIndex: Int, itemCode: String) {
    when(adapter.getItem(itemIndex) as? TitleValueItem? ?: return) {
        R.string.some -> onLanguageClick()
    }
}


И он мне ругается на строковый ресурс, что мол Int вместо TitleValueItem, не могу
понять, что я забыл дописать то .
    


Ответы

Ответ 1



Попробуйте следующим образом: override fun onListItemClick(itemIndex: Int, itemCode: String) { when ((adapter.getItem(itemIndex) as? TitleValueItem)?.titleId ?: return) { R.string.v2_mobile_settings_language -> onLanguageClick() } }

Ответ 2



Вот так попробуйте override fun onListItemClick(itemIndex: Int, itemCode: String) { when((adapter.getItem(itemIndex) as? TitleValueItem? ?: return).titleId) { R.string.some -> onLanguageClick() } }

среда, 26 февраля 2020 г.

Как исправить утечку памяти Android Studio Kotlin

#android #kotlin


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

Код обработки:

   // получаем ответ от php запроса в формате json
        try {
            val reader = BufferedReader(InputStreamReader(`is`, "UTF-8"), 8)
            val sb = StringBuilder()
            line = reader.readLine()
            while (line != null) {
                sb.append(line + "\n")
            }
            `is`?.close()
            result = sb.toString()
            Log.e("pass 2", "connection success$result")
        } catch (e: Exception) {
            Log.e("Fail 2", e.toString())
        }


Ошибка:

 E/AndroidRuntime: FATAL EXCEPTION: Thread-42
        Process: ru.ifr0z.fabuserlocation.example, PID: 20957
        java.lang.OutOfMemoryError: Failed to allocate a 486539272 byte allocation
with 25165824 free bytes and 149MB until OOM, max allowed footprint 271163448, growth
limit 402653184
            at java.util.Arrays.copyOf(Arrays.java:3260)
            at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:125)
            at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:451)
            at java.lang.StringBuilder.append(StringBuilder.java:137)
            at ru.ifr0z.fabuserlocation.example.TestZaps.run(TestZaps.kt:59)
    I/Process: Sending signal. PID: 20957 SIG: 9
    Application terminated.


Ещё я был бы очень признателен если бы мне кто подсказал что это значит пытался загуглить
это, но информации никакой толком не нашёл, данные логи идут аккурат перед ошибкой
о утечки памяти:

E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/LocationManager: thread is not runable, msg ignore, state:WAITING, pkg:ru.ifr0z.fabuserlocation.example
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]

    


Ответы

Ответ 1



Вы прочитали из потока одну строку и в цикле пихаете её (одну и ту же) в билдер до потери памяти:). Я Котлин знаю очень из далека, но на en-SO советуют читать поток таким кодом: val allText = inputStream.bufferedReader().use(BufferedReader::readText) Источник

Что выполняют CallAdapterFactory в Retrofit?

#android #kotlin #retrofit #rxjava2


.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    


Ответы

Ответ 1



С помощью метода addCallAdapterFactory вы расширяете ваш retrofit сторонними библиотеками. В данном случае вы добавляете поддержку RxJava 2. Список доступных адаптеров тут.

Библиотека для работы с датами Kotlin

#kotlin


Необходимо работа с датами, например такие операции как:


определить количество недель охватывающих 2 даты 
(например 03.11.2019 и 04.11.2019 - 2 недели)
Дату среды на 15 неделе от даты и т.д.


Не подскажите, а то самому не охота реализовывать. На python использовал relativedelta,
может есть что-то подобное на Kotlin. Будет применяться на Android

Попробовал Joda Time, как советовали.

fun differentDatesInWeek(startDate: DateTime, endDate: DateTime) : Int{

        return Weeks.weeksBetween(startDate, endDate).weeks
    }


Собственно вопрос, почему при выборе дат 03.11.2019 и 04.11.2019 он показывает 0,
а не 2 (или хотя бы 1)?

Или вот так. Решение 2:

var start = DateTime.parse("2019-11-08")
        var end = DateTime.parse("2019-11-09")
        Log.d("Разница 1", Weeks.weeksBetween(start, end).weeks.toString())

        start = DateTime.parse("2019-11-08")
        end = DateTime.parse("2019-11-10")
        Log.d("Разница 2", Weeks.weeksBetween(start, end).weeks.toString())


Ответ:

2019-11-01 16:36:25.325 22728-22728/ru.ddstudio.schedule D/Разница 1: 0
2019-11-01 16:36:25.327 22728-22728/ru.ddstudio.schedule D/Разница 2: 0


Собственно ответ должен быть разный, так как они лежат в разных неделях. Взял именно
эти данные, чтобы показать что неделя "Американская"

Посмотрел решение с Calendar

Вот код

        var calendar = Calendar.getInstance()
    calendar.set(2019, 11, 2)
    val c1 = calendar.get(Calendar.WEEK_OF_YEAR)
    calendar.set(2019, 11, 3)
    val c2 = calendar.get(Calendar.WEEK_OF_YEAR)
    Log.d("Количество недель с1", (c1).toString())
    Log.d("Количество недель с2", (c2).toString())
    Log.d("Количество недель", (c2 - c1).toString())

    ////////////
    calendar = Calendar.getInstance()
    calendar.set(2019, 11, 3)
    val c3 = calendar.get(Calendar.WEEK_OF_YEAR)
    calendar.set(2019, 11, 4)
    val c4 = calendar.get(Calendar.WEEK_OF_YEAR)
    Log.d("Количество недель с3", (c3).toString())
    Log.d("Количество недель с4", (c4).toString())
    Log.d("Количество недель", (c4 - c3).toString())


Результат:

    2019-11-01 16:18:51.726 21282-21282/ru.ddstudio.schedule D/Количество недель с1: 49
2019-11-01 16:18:51.726 21282-21282/ru.ddstudio.schedule D/Количество недель с2: 49
2019-11-01 16:18:51.726 21282-21282/ru.ddstudio.schedule D/Количество недель: 0
2019-11-01 16:18:51.726 21282-21282/ru.ddstudio.schedule D/Количество недель с3: 49
2019-11-01 16:18:51.726 21282-21282/ru.ddstudio.schedule D/Количество недель с4: 49
2019-11-01 16:18:51.726 21282-21282/ru.ddstudio.schedule D/Количество недель: 0


Почему ответ для этих дат одинаков? хотя они находятся в разных неделях
    


Ответы

Ответ 1



Берете календарь, устанавливаете дату 1, определяете номер недели 1-ой даты и также для 2-ой даты, если они попадают в 1 год, то разница недель+1. Берете дату, добавляете 15 недель - получится искомая дата. Calendar calendar = Calendar.getInstance(); calendar.set( Calendar.MONTH, month1 ); calendar.set( Calendar.DATE, date1 ); calendar.set( Calendar.YEAR, year1 ); calendar.get( Calendar.WEEK_OF_YEAR ); calendar.add( Calendar.WEEK, 15 );

Ответ 2



Сейчас стандартом де-факто для работы с датами является либа Joda Time В вашем случае, количество недель между двумя датами в термина Joda будет такая: var weeks = Weeks.weeksBetween(dateTime1, dateTime2).getWeeks()

пятница, 14 февраля 2020 г.

Возможна ли веб-разработка на котлине?

#веб_программирование #kotlin


Очень нравится этот язык своим синтаксисом, но он же в основном на андроид ориентирован
насколько я понимаю. Возможно ли его как-то приспособить для сервера? Spring/Play...
или что-то еще. И насколько это уже распространено (веб на котлине)? 

P.S. Я в курсе что он в жс компилироваться может, но я в основном бэкэндщик и мне
интересен он именно со стороны серверной разработки.
    


Ответы

Ответ 1



Kotlin не ориентирован в основном на Android, тут вы глубоко заблуждаетесь. Android просто оказался благоприятной нишей, в которой разработчики заждались чего-то нового, сидя на Java 6. Есть официальная страница на сайте Kotlin-a о web-девелопменте: https://kotlinlang.org/docs/reference/server-overview.html На конференции, что была недавно в Сан Франциско, ребята из JetBrains очень активно продвигали свой собственный фреймворк Ktor, с него и советую начать. https://github.com/ktorio/ktor Kotlin язык широкого применения, и областей его применения будет все больше и больше, над этим сейчас в JetBrains активно работают. Все видео с KotlinConf 2017 https://www.youtube.com/watch?v=spFtUgL32yA&list=PLQ176FUIyIUY6UK1cgVsbdPYA3X5WLam5

четверг, 13 февраля 2020 г.

Сделать EditText который позволяет написать только один любой emoji icon или один любой символ

#java #android #kotlin #emoji


Условия: Есть приложение, содержащее EditText.

Задача: Сделать EditText, который позволяет вписать в себя только один любой Emoji
icon или какой-нибудь один символ.

Идеи: Я пробовал прописать в параметрах EditText android:maxLength="1", но в таком
случае некоторые emoji просто не пишутся. Предполагаю, это происходит потому, что некоторые
emoji состоят из нескольких других emoji, которые в последствии объединяются, то есть
они имеют длину больше одного символа.

Вопрос: Как осуществить задуманное?
    


Ответы

Ответ 1



Используйте Emoji Compatibility support library.

Ответ 2



Удалось реализовать без дополнительных библиотек: Создаём Boolean переменную editTextFlag, которая используется для того, чтобы пресекать бесконечные изменения текста в EditText, вызванные в результате команд MyEditText.setText(...). (Дальше станет понятнее зачем нужна эта переменная.) Ставим на EditText улавливатель изменений текста (ввода или удаления) командой .addTextChangedListener(...). В нём по дефолту находится три функции: afterTextChanged, beforeTextChanged и onTextChanged. Нам понадобится только одна: "beforeTextChanged", которая вызывается за момент до того, как введётся текст. s - в данной функции это текст, который был в EditText до изменения after - количество символов в EditText после изменения В "beforeTextChanged" я создал три условия: (editTextFlag && after == 0) - вызывается когда пользователь удаляет символ или emoji, то есть количество символов в EditText после изменения равно 0 (editTextFlag && HabitIconEditText.text.isNotEmpty()) - вызывается, когда в EditText уже есть какой-то символ или emoji icon и пользователь пытается добавить ещё один. Мы ему это не позволяем и пишем в EditText текст, который был до изменения, то есть текст s, командой MyEditText.setText(s). Ну и для красоты перемещаем курсор EditText в конец строки командой MyEditText.setSelection(s.length). Ну else вызывается когда не подходит ни одно из вышеперечисленных условий. В данном случае оно просто переключает переменную editTextFlag обратно на true. Дело в том, что при вызове команды .setText( ... ) addTextChangedListener вызывается второй раз. Так как при первом вызове editTextFlag переключилось на false, то нужно вернуть эту переменную обратно на на true, делается это как раз при втором вызове, в этом условии else. Вот собсна сам код: var editTextFlag = true MyEditText.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { when { (editTextFlag && after == 0) -> { editTextFlag = false MyEditText.setText("") } (editTextFlag && HabitIconEditText.text.isNotEmpty()) -> { editTextFlag = false MyEditText.setText(s) MyEditText.setSelection(s.length) } else -> { editTextFlag = true } } } override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable) {} })

воскресенье, 9 февраля 2020 г.

Можно ли писать на Kotlin, без особых знаний Java?

#android #kotlin


У меня есть опыт со скриптовыми языками (Ruby, Python), a Kotlin много чего у них
позаимствовал. Язык мне понравился в плане простоты как Ruby.
    


Ответы

Ответ 1



Писать можно, но на данный момент без полной изоляции от Java нереально. Ведь сами подумайте все базовые классы на Java и уйти от этого требуется время, да и зачем? Многие либы, многие решения не сопровождаются до сих пор котлином, большинство решений разных проблем в сети будут скорей всего на java. Но если мыслить с точки зрения могу ли я писать приложения не используя Java? - то тогда, да без сомнения.

среда, 5 февраля 2020 г.

Назначение символа * при создании объекта в котлине

#java #kotlin


Здравствуйте. Перевел код с  java на kotlin  со помощью автоматического конвертера.
Появилась конструкция, которую я не могу понять. Что означает звездочка при создании
объекта (return Sort(*orders)) ? Мне нужно хотя бы название этой конструкции для дальнейшего
гугления.

class Sort (vararg orders: SortOrder) {

var orders: List = ArrayList()

companion object {
    fun sort(vararg orders: SortOrder): Sort {
        return Sort(*orders)
    }
}

init {
    this.orders = Arrays.asList(*orders)
}

override fun equals(other: Any?): Boolean {
    if (this === other) return true
    if (other == null || javaClass != other.javaClass) return false
    val sort = other as Sort?

    return orders == sort!!.orders
}

    


Ответы

Ответ 1



Согласно документации +, -, *, /, % - mathematical operators * is also used to pass an array to a vararg parameter (также используется для передачи массива параметру vararg) Также When we call a vararg-function, we can pass arguments one-by-one, e.g. asList(1, 2, 3), or, if we already have an array and want to pass its contents to the function, we use the spread operator (prefix the array with *): val a = arrayOf(1, 2, 3) val list = asList(-1, 0, *a, 4) Перевод Когда мы вызываем vararg-функцию, мы можем передавать аргументы один за другим, например, asList (1, 2, 3), или, если у нас уже есть массив и мы хотим передать его содержимое функции, мы используем оператор распространения (spread) (префикс массива с *):

понедельник, 3 февраля 2020 г.

Как конвертировать файлы .java в файлы .kt?

#java #android #intellij_idea #конвертация #kotlin


Прочитал тут habrahabr.ru/company/JetBrains/blog/231525 статью. Там написано, что
просто конвертируется. Но в IDEA не нашёл меню, отвечающего за конвертацию. Как осуществить это?
    


Ответы

Ответ 1



Необходимо выполнить действие "Convert Java File to Kotlin File". Это можно сделать несколькими способами: Выполняем действие "Find Action" Ctrl+Shift+A и набираем имя действия. Также эта опция доступна в меню "Code | Convert Java File to Kotlin File". Естественно у вас должен быть установлен плагин Kotlin, либо используйте Intellij IDEA 15, в которой этот плагин предоставляется "из коробки"

Ответ 2



Здесь есть подробный урок о переходе на Kotlin: http://java-help.ru/kotlin-introduction/

воскресенье, 2 февраля 2020 г.

Static метод в kotline

#java #android #kotlin


Есть метод в java:

public static Locale parseStringLocale(String locale) {
    return locale.length() > 2
            ? new Locale(locale.substring(0, 2), locale.substring(3))
            : new Locale(locale);
}


При попытке сконвертировать его в kotlin получается нечто подобное:

fun parseStringLocale(locale: String): Locale {
    return if (locale.length > 2)
        Locale(locale.substring(0, 2), locale.substring(3))
    else
        Locale(locale)
}


Но он уже не static, ему стоит как то приклеить companion object или как можно решить
вопрос, для будущего вызова данного метода.
    


Ответы

Ответ 1



Статические методы в Kotlin задаются через companion object т.е. в вашем случае companion object{ fun parseStringLocale(locale: String): Locale { return if (locale.length > 2) Locale(locale.substring(0, 2), locale.substring(3)) else Locale(locale) } }

Ответ 2



Я бы рекомендовал в Kotlin заменять служебные методы (util) на extensions. Модификатор static убрали не для того, чтобы все методы перемещать в компаньон. Я бы сделал так: fun String.toLocale(): Locale { //здесь ваша логика, обращайтесь к данному String с помощью this } Если вы же хотите сделать util класс, можно сделать просто object: object LocaleUtils { //fun parseStringLocale... }

пятница, 31 января 2020 г.

Выполнить метод при закрытии активити

#java #android #kotlin


Есть две активити "MainActivity" и "SecondActivity". Можно каким-нибудь образом выполнить
метод в "MainActivity" при возврате с "SecondActivity" на "MainActivity", но чтобы
он не выполнялся при создании "MainActivity", срабатывал лишь после закрытия "SecondActivity"?
    


Ответы

Ответ 1



Да, можно. Для этого запускайте вторую активити через startActivityForResult, после её закрытия у первой активити будет вызван метод onActivityResult

пятница, 24 января 2020 г.

Kotlin. Перегрузка методов под тип Null

#kotlin #интерфейс #null


Добрый день.
Пытаюсь реализовать интерфейс примерно такого вида:

interface IDataConversions {
    fun setData(value: Boolean?)
    fun setData(value: Byte?)
    fun setData(value: Short?)
    fun setData(value: Int?)
    fun setData(value: Float?)
    fun setData(value: ByteArray?)
    fun setData(value: String?)
}


Однако заметил, что в таком случае придется в каждом методе проверять на Null

Есть возможность в Kotlin реализовать что-то типа такого? : 

interface IDataConversions {
    fun setData(value: "какой то Null тип")
    fun setData(value: Boolean)
    fun setData(value: Byte)
    fun setData(value: Short)
    fun setData(value: Int)
    fun setData(value: Float)
    fun setData(value: ByteArray)
    fun setData(value: String)
}

    


Ответы

Ответ 1



Также, как и в джаве, при перегрузке будет браться сначала более конкретный тип. Выглядит так, что вам просто нужно перегрузить метод с параметром Any?: interface IDataConversions { fun setData(value: Any?) fun setData(value: Boolean) fun setData(value: Byte) ... }

среда, 22 января 2020 г.

Интересное поведение kotlinx

#android #kotlin


Столкнулся со следующей проблемой, подключил библиотеку, в которой есть некие вьюшки
с определенными id'шками. И в main проекте при обращении к этому определенному view
не взначай прописал тот же id и для свой view.
После этого kotlinx вместо того чтобы обращаться в классе к моей id моего проекта,
обратился вплоть до id подключенной библиотеки.

Как можно избежать подобных ситуаций?
Пока как вариант это переименование id в main или библиотеки, но так как это  порой
не явно всплывает, то хотелось бы как то по другому обойти. Возможно кто то сталкивался
уже с чем-то подобным. 

UPD:

Хочу заметить что импорт не меняется, к примеру:

import kotlinx.android.synthetic.main.dialog_immediate_categorization.*

Где в самой разметке:




Где как видно что: com.mandarine.android.common это в моём случае элемент подключенной
библиотеки в которой для класса TitleSwitchView выделена разметка состоящая из TextView
и SwitchView в котором так раз таки и указан id switchView.
И уже в моём классе он обращается не к switchView типа TitleSwitchView а к id switchView
типа SwitchView.
    


Ответы

Ответ 1



Скройте ресурсы библиотеки. Хороший ответ в офф документации https://developer.android.com/studio/projects/android-library#PrivateResources

Ответ 2



Уу, вот это вопрос! Затрагивает давно известную тему доступности ресурса по всему коду приложения, и как следстве опасность коллизии имен. Механизм поиска обекта в КотлинИкс подразумевает скоуп всего дерева элементов. Обойти данную проблему можно отказом от КотлинИкс. Главное не прибегать к решению в котором используются более сложные имена для обьектов. Автор вопроса молодец!

Изменение цвета подписи Spinner

#android #kotlin


Делаю приложение для изменения цвета приложения



Как изменить цвет подписи у Spinner программно, т.к. в зависимости от цвета должен
меняться и цвет текста. Хотел через setTextColor как у кнопок, но у Spinner нет такого
метода
    


Ответы

Ответ 1



Подключите к вашему Spinner вот такой адаптер: public class MySpinnerAdapter extends ArrayAdapter { Context ctx; List objects; MySpinnerAdapter(Context context, String[] objects) { super(context, R.layout.item_spinner, objects); ctx = context; this.objects = Arrays.asList(objects); } //для показа в меню @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { return getCustomView(position, convertView, parent); } //для показа в закрытом виде @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { return getCustomView(position, convertView, parent); } View getCustomView(int position, View convertView, ViewGroup parent) { if (convertView == null) convertView = View.inflate(ctx, R.layout.item_spinner, null); ... ваша логика изменения цвета: if () { convertView.setBackground(нужный цвет); } return convertView; } @Override public int getCount() { return objects.size(); } } И в нем пропишите логику смены цвета. В качестве R.layout.item_spinner используйте или свой лэйаут или возьмите у андроида (который обычно используется в обычном адаптере).

суббота, 11 января 2020 г.

Как выполнить более 3 параллельных http запросов с помощью RxJava (+retrofit2) в Android

#android #kotlin #rxjava #retrofit2


Пытаюсь освоить работу с RxJava + retrofit2 + kotlin.

Как в этом участвует Observable в общем разобрался, даже научился объединять результаты
2-3 параллельных запросов по итогу выполнения всех с помощью Observable.zip, НО как
похожим образом выполнить более 3 параллельных запросов не могу понять.

В исходном коде класса Observable есть метод 

static  Observable zip(), 


но он не работает как 

static  Observable zip() 


в случае с тремя Observable на вход и Function3<*,*,*,*>. 

Старался уже сделать первые три запроса с помощью zip, потом flatMap и тд, но всё
не выходит. Чтение документации и примеров не помогают повернуть к нужному направлению.
Смотрел в сторону Observable.combineLatest, но пришел к выводу (может ошибочному),
что метод вернет результат первого выполнившегося Observable.

Если в целом, что я хочу: 

У меня есть 4 метода, которые возвращают Observable:


this.orderRepository.getStatuses():Observable
this.orderRepository.getOrders():Observable
this.userRepository.getUsers():Observable
this.orderRepository.getTypes():Observable


Подскажите, пожалуйста, как я должен скомпоновать эти методы, чтобы они выполнились
параллельно, и в конце получить результат выполнения всех 4 методов в одном месте? 

Мои стыдливые попытки ниже. Это уже что-то испорченное, но я вообще не понимаю, что
я должен сделать с 4 Observables, чтобы их всех в одном месте и вернуть в UI. + уже
запутался с flatMap, map и так далее...

override fun buildUseCaseObservable(params: Params): Observable {

return Observable.zip(
                this.userRepository.getUsers(100, 1, ApiUserFilter(isManager = true)),
                this.orderRepository.getOrderStatuses(),
                this.orderRepository.getOrderTypes(),
                Function3
{ t1, t2, t3 ->
                    Zip(t1,t2,t3)
                }).map {
                    this.orderRepository.getOrders(params.limit, params.page, params.filter).flatMap {
                        it
                    }
                }

 }



    


Ответы

Ответ 1



Zip для четырех observable можно написать так: Observable.zip( getStatuses(), getOrders(), getUsers(), getTypes(), Function4 { status, order, user, type -> ... } )

воскресенье, 5 января 2020 г.

val или fun в Kotlin

#kotlin #lambda


Недавно начал писать на языке Kotlin и у меня возникло много вопросов о fun and val,
например, чем отличаются эти два случая:   


val handleMessage (Message) -> Unit = { message -> 
    /* do something here */ 
}  

fun handleMessage(message : Message){
    /* do something here*/
}



Я хотел бы узнать есть ли между ними какая-нибудь серьезная разница и почему я должен
в похожих случаях пользоваться одним, а не другим.

P.S. Я знаю что val immutable и обычно его используют для того, чтобы хранить данные
    


Ответы

Ответ 1



Большое спасибо @Grundy за помощь в поисках ответа. val handleMessage : (Message) -> Unit{ message -> /* do something */ } данный код создает новый класс: class A : (Message) -> Unit { override fun invoke(message : Message) { /* do something*/ } } Т.е. при обращении к лямбда выражению у нас создается новый класс и вызывается метод invoke с заданным параметром. В случае fun: fun handleMessage(message: Message){ /* do something*/ } данный код компилируется в следующий java-код: public class ExampleClass{ void handleMessage(Message message){ /* do something */ } } Итог: 1. fun - обыкновенная функция, которая превращается в обычный метод, в то время как val создает новый класс и вызывает его метод invoke с переданными параметрами. 2. Если вы пишите на Android, стоит избегать использования val лямбда выражений

среда, 1 января 2020 г.

Возможность авторизации запросов в spring и access_token-ом и через форму входа в браузере

#java #spring #kotlin #spring_boot #spring_security


Дано:

Проект на spring+kotlin. Реализовано получение access_token через БД и доступ к ресурсам
с его помощью.

Задача:

Реализовать возможность доступа к ресурсам для юзеров, залогинившихся через форму
логина в браузере.

Проблема:

Работает только один из способов авторизации. Если добавить аннотацию @EnableResourceServer
- работает способ доступа с токеном. При запросе любой страницы в браузере просто выводит
ошибку "неавторизован", в т.ч. по адресу /login. Если на /login зайти с прикреплением
токена - выведет 404. Если аннотацию @EnableResourceServer убрать - работает доступ
через форму логина в браузере и получение токена, но все запросы с прикреплением токена
перенаправляют на /login, т.е. токен не воспринимается.

Вопрос:

Как же сделать так, чтобы работало?

По идее надо написать что-то тут, но часы гугленья не дали понимания что именно:

@Configuration
@EnableWebSecurity
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
class WebSecurityConfiguration : WebSecurityConfigurerAdapter() {

    @Bean
    fun passwordEncoder() = BCryptPasswordEncoder()

    @Bean
    fun authenticationProvider(): DaoAuthenticationProvider {
        val authenticationProvider = DaoAuthenticationProvider()
        authenticationProvider.setUserDetailsService(userDetailsService)
        authenticationProvider.setPasswordEncoder(passwordEncoder())
        return authenticationProvider
    }

    @Bean
    override fun authenticationManagerBean(): AuthenticationManager {
        return super.authenticationManagerBean()
    }

    @Autowired
    lateinit var userDetailsService: UserServiceImpl

    @Autowired
    fun configureGlobal(auth: AuthenticationManagerBuilder) {
        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder())
                .and()
                .authenticationProvider(authenticationProvider())
    }

    override fun configure(http: HttpSecurity) {
        http
                .csrf().disable()
        http
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin().permitAll()
    }
}


Дополнительная информация:

Ссылка на весь проект на GitHub: https://github.com/mohaxspb/springSecurityExample/tree/v0.0.1 

Для запуска и работы надо поставить postgresql и создать там под юзером postgres
с паролем testtest БД с именем springbootdb - далее при запуске в БД создана будет
таблица с юзерами и туда будет добавлен юзер, под коим можно логиниться с логином test@test.ru
и паролем password. Для получения токена надо указать client_id: client_id и client_secret:
client_secret (эти данные также пишутся в БД при старте сервера)
    


Ответы

Ответ 1



Проблема решена. Заключалась она в том, что при добавлении аннотации @EnableResourceServer в цепочку фильтров для каждого запроса добавлялся OAuth2AuthenticationProcessingFilter, в настройках которого по умолчанию включён явный запрет на аутентификацию с помощью Cookie, которые используются при входе через форму логина. С другой стороны, если убрать аннотацию @EnableResourceServer, то фильтр OAuth2AuthenticationProcessingFilter не будет добавлен и спринг не будет знать, что на запросы с токеном надо реагировать попыткой аутентификации по токену. В итоге я сделал так: Убрал аннотацию @EnableResourceServer. Вручную добавил OAuth2AuthenticationProcessingFilter в цепочку фильтров для каждого запроса указав ему, что можно пропускать запросы с аутентификацией с помощью Cookie Этому фильтру установил AuthenticationManager типа OAuth2AuthenticationManager OAuth2AuthenticationManager - это дополнительный AuthenticationManager, которому передана реализация ClientDetailsService (отвечает за предоставление данных о клиентском приложении для авторизации) и реализация ResourceServerTokenServices, которая превращает access_token в объект Authentication с типом OAuth2Authentication Т.к. спрингу надо знать какой AuthenticationManager главный, надо дефолтный пометить аннотацией @Primary Таким образом, когда спринг не находит в запросе куки или токен он перенаправляет на страницу логина. После ввода данных устанавливает в браузере куку и аутентифицирует запросы ею. Если же в запросе есть токен, то срабатывает добавленный фильтр и пытается по токену аутентифицировать запрос. В случае удачи устанавливает аутентификацию в SecurityContext. В итоге реализация WebSecurityConfigurerAdapter выглядит так: @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) class WebSecurityConfiguration : WebSecurityConfigurerAdapter() { @Autowired lateinit var clientDetailsService: ClientServiceImpl @Bean fun tokenServices() = AccessTokenServices() @Bean fun passwordEncoder() = BCryptPasswordEncoder() @Bean fun authenticationProvider(): DaoAuthenticationProvider { val authenticationProvider = DaoAuthenticationProvider() authenticationProvider.setUserDetailsService(userDetailsService) authenticationProvider.setPasswordEncoder(passwordEncoder()) return authenticationProvider } @Primary @Bean override fun authenticationManagerBean(): AuthenticationManager { return super.authenticationManagerBean() } @Autowired lateinit var userDetailsService: UserServiceImpl @Autowired fun configureGlobal(auth: AuthenticationManagerBuilder) { auth .authenticationProvider(authenticationProvider()) .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()) } @Bean fun oauth2authenticationManager(): OAuth2AuthenticationManager { val authManager = OAuth2AuthenticationManager() authManager.setClientDetailsService(clientDetailsService) authManager.setTokenServices(tokenServices()) return authManager } @Bean fun myOAuth2Filter(): Filter { val filter = OAuth2AuthenticationProcessingFilter() filter.setAuthenticationManager(oauth2authenticationManager()) //allow auth with cookies (not only with token) filter.setStateless(false) return filter } override fun configure(http: HttpSecurity) { http .csrf() .disable() http .authorizeRequests() .anyRequest() .authenticated() http .formLogin() .permitAll() http .addFilterBefore( myOAuth2Filter(), BasicAuthenticationFilter::class.java ) } } Весь код в репозитории под тегом v0.03 Наверное, можно сократить код, корректно реализовав ResourceServerConfigurerAdapter и вернув @EnableResourceServer. Если получится - дополню ответ.

вторник, 31 декабря 2019 г.

Опасность использования не Java в Android [закрыт]

#java #android #kotlin


        
             
                
                    
                        
                            Закрыт. Этот вопрос не по теме. Ответы на него в данный
момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Update the question so it's
on-topic for Stack Overflow на русском.
                        
                        Закрыт 4 года назад.
                                                                                
           
                
        
Я пишу для Android около 1.5 лет, все это время я учусь в университете и проекты
для фриланса пишу на языке kotlin. Проекты работают хорошо и язык мне очень нравится.
Стоит так же отметить что использование этого языка не исключает наличия кода на java
в проекте. Но скоро выпуск и меня не покидает ощущение, что решающим с точки зрения
работодателя будет именно опыт использования java. 

Как вы считаете стоит отказаться от использования kotlin и вернуться на java или
же я напрасно беспокоюсь? Спасибо.
    


Ответы

Ответ 1



ОБНОВЛЕНИЕ 29 мая 2017: Котлин признан ещё одним языком разработки на Android, популярность его заметно выросла. В силу того, что и Kotlin, и Java собираются на одну общую платформу, бинарная и прочая совместимость не помеха, а важен язык как язык проекта. По-моему, с точки зрения работодателя важно, сможете ли Вы работать в команде, и тогда знание Java вам поможет куда больше, чем знание Kotlin: при всех его плюсах, он гораздо менее популярен, и, соответственно, гораздо меньше вероятность, что Вы найдёте себе место, где будут использовать Kotlin. Это критично только в том случае, если над вашей частью проекта работать будет только вы и никто после или до вас, но это редко. Ну а если вы точно знаете, что работать будете только там, где будут использовать Kotlin, то конечно вопрос стоять не будет.

Ответ 2



Не важно на каком ты пишете языке, если есть опыт разработки, то его можно применить в любом проекте на любом языке. Знаю человека которого позвали на вакансию Java разработчика без знания Java, но он к тому моменту уже был хорошим С# разработчиком.

суббота, 28 декабря 2019 г.

Android - в связи с прекращением существования системы, стоит ли изучать Kotlin?

#java #android #kotlin #fuchsia


Как уже пишут, система Android в 2023-м году будет заменена на новую операционную
систему, и все устройства уже будут выпускаться без Android.

Так как сегодня язык программирования Kotlin только начинает свое развитие, и многие
библиотеки пока еще на Java, стоит ли браться за изучение Kotlin, если есть какой-то
опыт в Java? Даже если в ближайшие 2-3 года Kotlin станет основным языком в Android
программировании, каков будет смысл изучать его, если он вскоре не будет нужен?
    


Ответы

Ответ 1



Даже если Android и будет заменен на Fuchsia или что-там еще, то надо четко понимать, что 70-80% успеха новой оси это наличие девелоперов, разработчиков под данную ось. Нет разработчиков - нет приложений, нет приложений нет оси. Уже многие пытались: HP выпускал WebOS, Samsung выпускал Tizen и что? Где они теперь? Если Google не сделает ставку на Java девелоперов - ось не взлетит. Другой вопрос, что лет через 5 возможно появится другой язык программирования, который начнет доминировать. Сейчас многие активно пересаживаются на Kotlin, но надо понимать, что Kotlin это та же самая Java только в профиль, я вот лично Kotlin от Java почти не отделяю. Следите за рэнкингом языков На мой пристрастный взгляд сейчас есть 2 перспективных языка: Python и Rust, первый потому что все вдруг резко увлеклись AI, ML и проч. модностями, а второй - ну не знаю, свежо как то :)

Ответ 2



Не факт, что Android будет заменен. Fucsia - пока только пробный проект. Второе - обещали поддержку приложений из Google Play. Скорее всего, будет и поддержка Java-Kotlin приложений. А Kotlin в любом случае надо учить, даже если случится такое, что Fucsia выстрелит и программировать под нее будет нельзя на Kotlin`e, то в мире останется миллионы Android устройств. Да и пока ждешь до 2033-35 надо что-то делать...

Ответ 3



Как уже известно, готовящаяся на замену Android ОС Fuchsia будет базироваться на Flutter SDK. Недавно вышла статья на тему использования Kotlin c Flutter SDK. Пока не все гладко и есть существенные ограничения, но впереди еще пять лет и ответ на ваш вопрос по поводу нужности данного языка, думаю, очевиден.