Android Studio「Instant Run」の適用範囲や条件

実際使ってみると, 編集したコードが反映されたりされなかったり.

でも確かに高速なときもある.

効果的に高速で動作してくれるためのコードの編集範囲・条件は何なのか.

Instant_Run_-_Android_Tools_Project_Site

Instant Run - Android Tools Project Site

分かりづらいので表に.

instantrun

なんだか...

it seems that this feature is not perfectly stable yet : sometimes the modified code is marked as “pushed” whereas the modification is not really applied on the emulator. It is currently stable when it comes to hot resources or xml file swapping. It is really a great improvement, as we generally have to perform numerous incremental builds when we are tuning our xml files.

Reduce your Android build duration | OCTO talks !

みんなも上手に「Instant Run」を使って高速にアプリを開発しよう!!


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 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


Mac OS X ファイル名の濁点を変換 (PHP)

OSによってファイル名の正規化が行われる.

UAX15-NormFig3

Unicode正規化 - Wikipedia

Linux / Windows
NFC: Normalization Form Canonical Compression

OS X
NFD: Normalization Form Canonical Decompression

異なる「正規化」間で問題となる.

PHPで認識して変換できるのか.

ファイルを OSX上でつくる.

$ ls
KONBU.txt        こんふ.txt       こんぶ.txt

これに対してPHPコード.

<?php
$files = glob('*.txt');
foreach ($files as $key => $file) {
    $raw = pathinfo($file, PATHINFO_FILENAME);
    $nfc_iconv = iconv('UTF-8-MAC', 'UTF-8', $raw);
  //$nfc_normalizer = Normalizer::normalize($raw, Normalizer::FORM_C);
    echo $raw                                  . "\t" .
         mb_strlen($raw, 'UTF-8')              . "\t" . 
       //mb_strlen($raw, 'UTF-8-MAC')          . "\t" . 
         iconv_strlen($raw, 'UTF-8-MAC')       . "\t" .
         urlencode($raw)                       . "\n";
    echo $nfc_iconv                            . "\t" .
         mb_strlen($nfc_iconv, 'UTF-8')        . "\t" . 
         iconv_strlen($nfc_iconv, 'UTF-8-MAC') . "\t" .
         urlencode($nfc_iconv)                 . "\n";
  //echo $nfc_normalizer                       . "\n";
}

実行.

$ php test.php 
KONBU	5	5	KONBU
KONBU	5	5	KONBU
こんふ	3	3	%E3%81%93%E3%82%93%E3%81%B5
こんふ	3	3	%E3%81%93%E3%82%93%E3%81%B5
こんぶ	4	3	%E3%81%93%E3%82%93%E3%81%B5%E3%82%99
こんぶ	3	3	%E3%81%93%E3%82%93%E3%81%B6

よって, NFDからNFCに変換する場合.

iconv('UTF-8-MAC', 'UTF-8', $raw)

PHP関数 iconv*( ) は「UTF-8-MAC」を知っている.


今ではToolbar記述は不要となっていました とさ

昔々, こんな記述がありました.

...
dependencies {
    compile "com.android.support:appcompat-v7:21.0.+"
}
...
...
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.blah);

    Toolbar toolbar = (Toolbar) findViewById(R.id.myawesometoolbar);
    setSupportActionBar(toolbar);
}
...
...
<android.support.v7.widget.Toolbar
    android:id=”@+id/my_awesome_toolbar”
    android:layout_height=”wrap_content”
    android:layout_width=”match_parent”
    android:minHeight=”?attr/actionBarSize”
    android:background=”?attr/colorPrimary” />
...

AppCompat v21 — Lollipop 搭載前のデバイスにマテリアル デザインを! - Google Developer Japan Blog

旧ActionBarを隠したりとか, そんなテーマのとか, メニューのとか, 面倒でしたが今ではもうこの記述不要なのですね.

以下, Android Studio で BlankActivity をGUIから作成. API23.

...
dependencies {
    ...
    compile 'com.android.support:appcompat-v7:23.0.1'
}
...
...
public class MainActivity extends AppCompatActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }
}
...
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
...
>
    <TextView
        android:text="Hello World!"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</RelativeLayout>

KITKATでもLOLLIPOPでもきちんと表示されます.
Android_Device_Monitor 2

Android_Device_Monitor

テーマは, 非NoActionBarを親にして色を設定.

...
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>
...

前の記述のままでも動いてしまうのですが, 消したほうが気持ちがよいです.

元々,「appcompat-v7」の「v7」というのは,「API7まで対応できる」という後方互換の意味でしたよね.