Android Studio 2.0 で「set ANDROID_DAILY_OVERRIDE environment variable to "*****"」

ビルド時に謎のエラーメッセージ.

Plugin is too old, please update to a more recent version, or set ANDROID_DAILY_OVERRIDE environment variable to "*****"

環境変数「ANDROID_DAILY_OVERRIDE」とか初めて見た.

トップレベルの build.gradle をとりあえず(非推奨だが)書き換えるといける.

dependencies {
    classpath 'com.android.tools.build:gradle:+'
    ....
}

固定で書く場合, 今の最新バージョンはいくつか.

Maven_Repository__com_android_tools_build_»_gradle

Maven Repository: com.android.tools.build » gradle

いや, alpha だし, これか.

com_android_tools_build_gradle

com.android.tools.build.gradle

New_Build_System_-_Android_Tools_Project_Site

New Build System - Android Tools Project Site

エラーメッセージどおりに, OSX なら以下の後, プロジェクトをクリーンして, Android Studio再起動.

launchctl setenv ANDROID_DAILY_OVERRIDE *****

しかし, 引き続き新たなエラーメッセージが...

8.4.0 なのに「updating the version of com.google.android.gms to 8.3.0」


Android で よくある正規表現を使えるやつ

そもそもは Linkify のWEBリンクがなんだかな, と思い.

device-2011-08-23-153643

使えそうなよくある正規表現がいくつか用意されていたのですな.

public static final Pattern WEB_URL = Pattern.compile(
    "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
  + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
  + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
  + "(?:" + DOMAIN_NAME + ")"
  + "(?:\\:\\d{1,5})?)"
  + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~"
  + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
  + "(?:\\b|$)");
public static final Pattern PHONE
  = Pattern.compile(                
      "(\\+[0-9]+[\\- \\.]*)?"      
    + "(\\([0-9]+\\)[\\- \\.]*)?"   
    + "([0-9][0-9\\- \\.]+[0-9])"); 
public static final Pattern EMAIL_ADDRESS
  = Pattern.compile(
    "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
    "\\@" +
    "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
    "(" +
        "\\." +
        "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
     ")+"
  );

platform_frameworks_base/Patterns.java

すぐにそのまま使おう.


if (Patterns.WEB_URL.matcher(text).find()) {
  // do something
}

「厳格なのか?」でフィルターをつける場合.

// A match filter that only accepts odd numbers.
MatchFilter oddFilter = new MatchFilter() {
    public final boolean acceptMatch(CharSequence s, int start, int end) {
        int n = Character.digit(s.charAt(end-1), 10);
        return (n & 1) == 1;
    }
};

// Match all digits in the pattern but restrict links to only odd
// numbers using the filter.
Pattern pattern = Pattern.compile("[0-9]+");
Linkify.addLinks(text, pattern, "http://...", oddFilter, null);

Android Text Links Using Linkify


Android Code Style で インデントはスペース何個?

Android Studioデフォルトのスペース4個ではなんとなく不自由に思えてきた,インデント.

今どきは何個なのか.

Google の Code Style としては「2個」.

Android のコーディング時にAndroidStudioにセットしておくといい2つのXMLファイル

その他どんな雰囲気なのか.

square も「2個」.

java-code-styles_Square_xml_at_master_·_square_java-code-styles

java-code-styles/Square.xml at master · square/java-code-styles

XMLもスペース2個ででいいように思えるのだが.

CodeStyle__Java_·_ogaclejapan_android-code-styles_Wiki

CodeStyle: Java · ogaclejapan/android-code-styles Wiki

CodeStyle__XML_·_ogaclejapan_android-code-styles_Wiki

CodeStyle: XML · ogaclejapan/android-code-styles Wiki

いまや, コードもXMLも2個か.

square のスタイルにしとこうかな.

Installation

- Run the install.sh script.
- Restart IntelliJ if it's running.
- Open IntelliJ Project Settings -> Code Styles, change the code style for the project to the one you want.

Preferences

sh 1個叩くだけで設定に追加してくれます.

square/java-code-styles


Android Data Binding は いつ実力を発揮できるのだ?!

Data_Binding_Guide___Android_Developers

Data Binding Guide | Android Developers

たくさん記事を見かけるようになったのでかんたんに比較してみようかと思い.

20160104-195007

これまで

public class MainActivity extends AppCompatActivity {

  private TextView name;
  private TextView age;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);

    name = (TextView) findViewById(R.id.name);
    age = (TextView) findViewById(R.id.age);

    User user = new User("ジョーンズ", 30);

    name.setText(user.name);
    age.setText(String.valueOf(user.age));
  }

  public void onClickName(View v) {
    Toast.makeText(this, " 名前をクリックしました。", Toast.LENGTH_SHORT).show();
  }

}
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">
    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClickName"
        />
    <TextView
        android:id="@+id/age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
 </LinearLayout>

ButterKnife

dependencies {
 	...
    compile 'com.jakewharton:butterknife:7.0.1'
}
public class MainActivity extends AppCompatActivity {

  @Bind(R.id.name) TextView name;
  @Bind(R.id.age) TextView age;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);

    ButterKnife.bind(this);

    User user = new User("ジョーンズ", 30);

    name.setText(user.name);
    age.setText(String.valueOf(user.age));
  }

  @OnClick(R.id.name)
  public void onClickName(View v) {
    Toast.makeText(this, " 名前をクリックしました。", Toast.LENGTH_SHORT).show();
  }

}
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">
    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <TextView
        android:id="@+id/age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
 </LinearLayout>

Data Binding

android {
	...
    dataBinding {
        enabled = true
    }
}
public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    MainActivityBinding binding = 
         DataBindingUtil.setContentView(this, R.layout.main_activity);

    User user = new User("ジョーンズ", 30);

    binding.setUser(user);
    binding.setActivity(this);
  }

  public void onClickName(View v) {
    Toast.makeText(this, " 名前をクリックしました。", Toast.LENGTH_SHORT).show();
  }

}
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.example.User"/>
        <variable
            name="activity"
            type="com.example.MainActivity" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}"
            android:onClick="@{activity.onClickName}"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(user.age)}"
            />
    </LinearLayout>
</layout>

むむむ...

レイアウトを繰り返し使うような ListView/RecyclerView で実力を発揮するのかな?

This is more than binding simple data to your views and avoiding the boilerplate code. To me, this is actually mixing business logic in your UI layouts. Your views should be as dumb as possible, adhering to the Single Responsibility Principle with the only responsibility to show data. This could lead to a complicated, cluttered and unclean codebase.

We've seen some of the examples of the Data Binding API. I'm sure that this API was created in order to ease the developers' work and avoid boilerplate, but one can overuse it and accidentally create chaos in his code. Mixing Java in your view code has never been a good idea. Does JSP ring a bell?

How you can go wrong with the new Data Binding API

強力な分だけ「用法・用量」に注意, ということなのか.

ちなみに AndroidStudio最新環境では build.gradle 内 dataBinding { enabled = true } のみで使えるようになっておる.

Data Binding Guide | Android Developers


Android 次期バージョン N は Oracle Java を使わないのか?

Diff_-_51b1b6997fd3f980076b8081f7f1165ccc2a4008^__-_platform_libcore_git_-_Git_at_Google

技術ネタ満載の YCombinator の運営する「Hacker News」で昨日から話題になっています.

Google confirms next Android version won’t use Oracle’s proprietary Java APIs | Hacker News

このへん素人目にも想像できるのは「著作権料を払いたくない」という理由.

So in order for Google to avoid paying that royalty going forward they need to move to OpenJDK quickly with their next release, with the belief that using Oracle's GPL JDK implementation also gives them a license to the API (which is somehow separately copyrightable? The Federal Circuit is a mess).

ここらの適用範囲などの法律の話は金額のわりに明快でなく庶民には分かりづらい.

実際, 開発中のソースコードではどのようになってきているのか.

Mysterious Android codebase commit | Hacker News

This diff is more explicit about what's going on:
https://android.googlesource.com/platform/libcore.git/+/aab9...
Change dependency from libart -> libopenjdkjvm.
There are also diffs adding lambda support, tweaking various classes for compatibility with applications that use reflection to access internal capabilities, and fixing lots OpenJDK compatibility bugs.

確かに, OpenJDK に移行してるようにも見えるが.

In the context of the recent juniper attack where some unauthorized code was committed without anybody noticing for years, it seems like it would be easy to hide a backdoor in such a big commit.
How do you go about checking the integrity of the code when you have so many files?
8902 files were changed, most added, and the commit says it's just importing openJDK files. Is there anybody checking that the source file imported haven't been modified to include some kind of backdoor?

はっきり「OpenJDKに移行を進めている」とは言い切れないのか.

WEBでは見づらいのでアプリで.

Hacker News Reader (翻訳) - Google Play の Android アプリ