android kotlin gradle.build

Here skeleton of gradle.build script for madness people who try to code Android apps using kotlin language.

This gradle script uses another structure of subdirectories, more simple I would say. There is no useless “deep” folders like src/main/java, src/main/assets, etc..

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.1.0'
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:0.10.770'
    }
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'idea'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.jetbrains.kotlin:kotlin-stdlib:0.10.770'
}

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 21
    }

    dependencies {
        compile fileTree(dir: 'libs', include: '*.jar')
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['java', 'kotlin']
            aidl.srcDirs = ['java']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }
    }
}

Read more

Android: отправка письма дефолтным клиентом

gmail-app-with-predefined-text-via-mailto-intent

Задача: отрыть дефолтный email клиент у пользователя на устройстве с предустановленным заголовком письма, текстом и адресатом.

При этом не должно всплывать окно IntentChooser, предоставляющее варианты каким приложением воспользоваться для написания письма. Пользователь должен сразу увидеть его дефолтный email клиент (и это не всегда gmail). Тысячи ответов на StackOverflow показывают диалог, схожий с “share”. Некоторые товарищи в лучшем случае предлагают фильтровать по ContentType и другим косвенным признакам того, что это почтовый клиент, хотя достаточно часто все равно просачиваются приложения вроде Evernote или даже пресловутый bluetooth. Иногда предлагают не переносимые решения, типа использование курсора для получения доступных email клиентов.

Read more

Android: сниппет для тостов

Toast прекрасный способ оповестить пользователя о чем то, не блокируя интерфейс. У них можно завадать отзывы, показывать в разных местах и даже делать кастомные view и все это с помощью fluent interface. Уверен, что читатели если и слышали о таких расширенных возможностях, то никогда не пользовались этим. Самый стандартный юзкейс – показать текст.

По моему опыту часто нужно показать toast как результат не успешной процедуры, которая обычно выполняется в фоне в отдельном треде или воркере, т.е. не в UI. А для этого приходится писать лапшу только для того, Toast.makeText(…).show() выполнился в UI треде.

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

Было

Toast.makeText(this,
    getText(R.string.messages_storage_invalid),
    Toast.LENGTH_SHORT).show();

Стало

    toastShort(R.string.messages_storage_invalid);

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

Read more

Kotlin: джависты, завидуйте

Около года назад, в подкасте радио-т я впервые услышал о инициативе JetBrains, новом языке программирования kotlin. С тех пор внимательно слежу за его развитием.
Они позиционируют котлин как “better java” и, надо сказать, у это получается. Это статический типизированный, язык со вшитой nullable-проверкой Так же он поддерживает функции высшего порядка(замыкания), extension functions и trait. Может немного напоминать scala – но, достаточно далеко от неё.

Read more

Play Framework: локализация Date.since()

Play framework позволяет в шаблонах groovy использовать extension functions – т.е прицеплять методы на ходу к объектам.

В частности в play имеет расширение экземпляров класса Date – since(), который возвращает сколько времени прошло от указанной даты. Например “13 minutes ago”

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

Read more

Android: не используйте String.isEmpty

Ни eclipse ни intellj Idea ни android lint не предупреждают, что String.isEmpty() появился в Java 6, и после Android 2.3.

java.lang.NoSuchMethodError: java.lang.String.isEmpty
at pro.ezway.carmonitor.entity.TroubleCode.hasTitle(TroubleCode.java:142)
at pro.ezway.carmonitor.ui.fragments.TroubleCodesFragment$TroubleCodesAdapter.getView(TroubleCodesFragment.java:242)
at android.widget.AbsListView.obtainView(AbsListView.java:1315)
at android.widget.ListView.makeAndAddView(ListView.java:1727)

Read more

Android: запуск дефолтного ланчера

Есть неочевидная ситуация: вы пишете лаунчер лончер или что-то его заменяющее, отдебажили, всё работало. Конечно же, вы поставили его как програму по умолчанию и теперь он стартует вместо дефолтого. И вдруг, вылезает некая бага, которая начинает крушить, бомбить ронять телефон, перезапуская приложение. Перезапустится, конечно же, то, что упало, а упал лончер. И он снова падает. Development mode в продакшене отключён. Ну вы поняли.

На самом деле бывают ситуации ещё хуже, например, для vendor lock-in приложений, которые вообще скрывают, что они работают под андроид.

Предвкушая первую мысль как вернуть дефолтный лончер: вызвать в приложении finish(). Чёрт, это же домашний экран %)

Read more

Groovy: java слишком проста

Возьмём довольно частую задачку: есть несколько значений первой переменной, нужно сделать присвоить второй переменной какое-то значение, в зависимости от первой переменной, т.е. value mapping.

В джаве это делается примерно так:

String alertClass = "";
switch(code.toUpperCase().charAt(0)) {
case 'U':
    alertClass = "alert";
    break;
case 'P':
    alertClass = "alert-error";
    break;
case 'B':
    alertClass = "alert-warning";
    break;
case 'C':
    alertClass = "alert-info";
    break;
}
// now alertClass has value

Read more

Android: отложенное действие

Бывает необходиость выполнить что-то не сразу, а чуть позже в главном(main) потоке для GUI

Этот код поможет(на время разработки)

public class AwesomeActivity extends WorkspaceActivity {
   @Override
   public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        . . .
        new Handler() {{
            postDelayed(new Runnable() {
                @Override
                public void run() {
                    // do something here
                    hideShutter();
                }
            }, 1500);
        }};
   }
}

Read more

Play framework: SELECT .. IN

Наткнулся на очередную невозможность сделать казалось бы простые вещи: выполнить запрос

SELECT .. WHERE something IN list

т.е. выбрать все записи, в которых поле something равно чему то из списка list.

Обойти можно через JPA:

@Entity
@Table(name="ezTroubleCode")
public class TroubleCode extends Model {
   @Index(name = "IDXcode")
   @Column(nullable=false, length=5)
   public String code;

   . . .

   /**
    * Search for codes by codeId
    */

    public static List<troublecode> findByCode(List<string> codes) {
        Query q = JPA.em().createQuery("SELECT tc FROM TroubleCode tc WHERE code IN (:codes)");
        q.setParameter("codes", codes);
        return q.getResultList();
    }
}
</string></troublecode>

Read more