Chrome CustomTabs 使い方 バックグランド処理で高速に

nexus2cee_stuff_thumb

[I/O 2015] Chrome Custom Tabs Will Add Easy And Rich Web Content To Any App With Chrome Capabilities

サービス経由で「ウォームアップ」,「URL先読み」を行って
高速に開く.

公開されている Googleサンプルのうち利用するヘルパークラスなどは
前回エントリを参照.

 

1. バインド

ウォームアップも同時に行う.
アクテビティのライフサイクルに合わせて.

public class SampleActivity extends AppCompatActivity
        implements CustomTabActivityHelper.ConnectionCallback {

    private CustomTabActivityHelper mCustomTabActivityHelper;

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

        mCustomTabActivityHelper = new CustomTabActivityHelper();
        mCustomTabActivityHelper.setConnectionCallback(this);

    }

    @Override
    protected void onStart() {
        super.onStart();
        mCustomTabActivityHelper.bindCustomTabsService(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        mCustomTabActivityHelper.unbindCustomTabsService(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mCustomTabActivityHelper.setConnectionCallback(null);
    }

    @Override
    public void onCustomTabsConnected() {
    }

    @Override
    public void onCustomTabsDisconnected() {
    }

}

 

2. プリフェッチ

開くであろうURLが確定した時点でバックグランドで先読み.

mCustomTabActivityHelper.mayLaunchUrl(uri, null, null);

 

3. 起動

前回とほぼ同じ.
タイトル, アニメーションを付けてなめらかな体感に.
R.anim.slide_* はサンプルのものを利用.

CustomTabsIntent customTabsIntent =
    new CustomTabsIntent.Builder(mCustomTabActivityHelper.getSession())
        .setShowTitle(true)
        .setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left)
        .setExitAnimations(this, android.R.anim.slide_in_left, android.R.anim.slide_out_right)
        .build();
CustomTabActivityHelper.openCustomTab(this, customTabsIntent, uri, new WebViewFallback());

 

以上をまとめてテンプレート的に

public class SampleActivity extends AppCompatActivity
        implements CustomTabActivityHelper.ConnectionCallback {

    private CustomTabActivityHelper mCustomTabActivityHelper;

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

        mCustomTabActivityHelper = new CustomTabActivityHelper();
        mCustomTabActivityHelper.setConnectionCallback(this);

    }

    private void preFetchUrl(Uri uri) {
        mCustomTabActivityHelper.mayLaunchUrl(uri, null, null);
    }

    private void open(Uri uri) {
         CustomTabsIntent customTabsIntent = 
            new CustomTabsIntent.Builder(mCustomTabActivityHelper.getSession())
            .setShowTitle(true)
            .setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left)
            .setExitAnimations(this, android.R.anim.slide_in_left, android.R.anim.slide_out_right)
            .build();
         CustomTabActivityHelper.openCustomTab(this, customTabsIntent, uri, new WebViewFallback());
    }

    @Override
    protected void onStart() {
        super.onStart();
        mCustomTabActivityHelper.bindCustomTabsService(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        mCustomTabActivityHelper.unbindCustomTabsService(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mCustomTabActivityHelper.setConnectionCallback(null);
    }

    @Override
    public void onCustomTabsConnected() {
    }

    @Override
    public void onCustomTabsDisconnected() {
    }

}

イベントからプリフェッチしてからのオープンすればよい.

しかし「先読みのタイミング」て…

(つづく)

Chrome Custom Tabs を とりあえず数行で使う


Chrome Custom Tabs を とりあえず数行で使う

スマホでブラウザを起動する, っての最近では面倒.

LINEとかメッセージでリンクを送ってくる人とか.

20150910-215123

さりげなく開かずにテキトーな会話を続けたりします.

考えてみると「なんかブラウザって重いしトロい」から.

そこで, 最近登場したのが「Chrome Custom Tabs」というしくみ.

Chrome Custom Tabs - Google Chrome

performance

表示までが非常に高速化されてるようにに見える.

実装しようとサンプルをダウンロードしてみる.

GoogleChrome/custom-tabs-client

アプリ内モジュールやヘルパーやプロセス間の通信など
依存関係があるのでわかりづらい.

とりあえずシンプルにURLを渡すだけでで起動してみたいだけなので以下で.

build.gradle

compile 'com.android.support:customtabs:23.0.1'

サンプル内モジュール customtabs 以下は不要.

コピペするクラス

CustomTabsHelper
KeepAliveService
CustomTabActivityHelper
WebViewFallback

shared というモジュールは作らずベタクラスとしてコピペ.
アプリ内モジュール依存はなしで.

起動

...
Uri uri = Uri.parse("http://google.com/");
CustomTabsIntent customTabsIntent =
    new CustomTabsIntent.Builder().build();
CustomTabActivityHelper
    .openCustomTab(this, customTabsIntent, uri, new WebViewFallback());
...

UIカスタマイズはしない. するならここで.

WebViewFallback#openUri()

    ...
    //Intent intent = new Intent(activity, WebViewActivity.class);
    //intent.putExtra(WebActivity.EXTRA_URL, uri.toString());
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(uri);
    activity.startActivity(intent);
    ...

Chromeアプリ (stable/beta/dev) をインストールしてない場合は,
デフォルトブラウザなどに暗黙的に投げる.

で ?

起動はできる.
が, これだけでは恩恵にありつけない.

20150910-224352

サイト内検索などはできるようにはなるが
「なんかブラウザって重いしトロい」が解消せず.

以下の機能があるという.

Pre-warming of the Browser in the background, while avoiding stealing resources from the application.

Providing a likely URL in advance to the browser, which may perform speculative work, speeding up page load time.

これを使わないと意味ないな...

(つづく)


Google (Now?) からの wikipedia の「URLを開くアプリが見つかりません」

ここ2-3日きっとみんなも遭遇してるはず.

Google Now から, 何か検索したときの Wikipedia ページへのリンクタップでのこれ.

20150825-040622

たくさん困ってる人がいる模様.

検索機能に問題は無いが特定サイトへ飛ぼうとすると「URLを開くアプリが見つかりません」のメッセージが出てリンク先が開けない Wikipediaとnaverまとめが開けないのは検索エンジンとして致命的です

昨日から突然Wikipediaが閲覧不可になりました。タイトルにあるように、「URLを開くアプリが見つかりません」と出てくるのでどうすれば良いのか困っています。

昨日から突然Wikipediaが閲覧不可… │ au Q&Aプラス

タップしたときのログ.

...
I/ContextIntentStarter(19425): No activity found for Intent { act=android.intent.action.VIEW cat=[android.intent.category.BROWSABLE] dat=http://ja.m.wikipedia.org/wiki/メインページ flg=0x8080000 pkg=org.wikipedia (has extras) }
E/ContextIntentStarter(19425): No activity found for any of the 1 intents
...

「pkg=org.wikipedia」とあるのでアプリ指定. このアプリをインストールしておけばアプリがタップ時に起動する.

ウィキペディアモバイル - Google Play の Android アプリ

インストールしてなければ「URLを開くアプリがみつかりません」となる.

すこし待てば直るのかな. wikipedia 入れるしかないのかな.

Google - Google Play の Android アプリ

Google Nowランチャー - Google Play の Android アプリ


onActivityResult() を透過的に Fragment に渡す

Activity内のFragmentに, 別Activityからの結果を渡す.

...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Fragment fragment = getFragmentManager().findFragmentById(R.id.your_fragment_id);
    if (fragment != null) {
        fragment.onActivityResult(requestCode, resultCode, data);
    }
}
...

fragment いなかったら正しく fragment.setArguments(bundle); で.


Android で 定数 (int)で enum を使うことは 

こんな記事を見かけた.

Why don't you use enum ? // Speaker Deck

...
public class Status {
  public static final int OK = 0;
  public static final int ERROR = 1;
}

public void onSomethingAction(int status) {
  switch (status) {
    case Status.OK:
      Log.d(TAG, “Status : OK”);
      break;
    case Status.ERROR:
      Log.d(TAG, “Status : NG”);
      break;
  }
}
...

より,

...
public enum Status {
  OK,
  ERROR
}

public void onSomethingAction(Status status) {
  Log.d(TAG, “Status : “ + status.name());
}
...

のほうがいいよね, と.

なんとなくここら「enum」についての議論を
よく見かけたような気がしたのですこし調べてみる.

even in the most recent documents android suggests that it's not such a good idea to use enums in an android application. The reason why is because they use up more memory than a static constants variable.

Working with Enums in android - Stack Overflow

Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.

java - Why Android uses Ints instead of Enums - Stack Overflow

Android_Memories____Speaker_Deck

Android Memories // Speaker Deck

公式ドキュメントには,

Be aware of memory overhead

Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.

Managing Your App's Memory | Android Developers

と書いてる.

他に,

Java enums are tremendously more expensive in code size than simple static final ints; classes and objects have not-insignificant overhead, so if you take a very class-heavy approach to your implementation you can end up with a significantly larger code size and RAM footprint for your app.

I really like this article on the importance of thinking about performance…

これに対して Jake Wharton さんも言及.

他には,

Should I strictly avoid using enums on Android?
No. Strictly means they are so bad, they should not be used at all. Possibly a performance issues might arise in an extreme situation like many many many (thousands or millions of) operations with enums (consecutive on the ui thread). Far more common are the network I/O operations that should strictly happen in a background thread. The most common usage of enums is probably some kind of type check - whether an object is this or that which is so fast you won't be able to notice a difference between a single comparison of enums and a comparison of integers.

java - Should I strictly avoid using enums on Android? - Stack Overflow

the original version of that document was just a bunch of prejudices. it's been rewritten to only contain facts backed up by actual benchmarks, and it's updated as the VM is updated. you can find the various benchmarks

Why was "Avoid Enums Where You Only Need Ints" removed from Android's performance tips? - Stack Overflow

結局,

オーバーヘッドは上がるが, まず最初はいうほど気にしなくてもよくね? 最近は. 見通しも良いし. 便利だし.

てな雰囲気でいいのかな. しらんけど.