Quantcast
Channel: Yukiの枝折
Viewing all 146 articles
Browse latest View live

Android:SyncAdapter

$
0
0

Intro

SyncAdapterについて.

  • SyncAdapterはスケジュールされた同期タスクに向いている
  • 同期のポリシーを指定するだけで後はAndroidがよしなにスケジュールする
  • 採用できる同期のポリシーは次の通り
    • サーバデータ変更時のメッセージ通知受信時(use GCM)
    • デバイスデータ変更時
    • TCP/IPコネクション接続時
    • 一定時間or指定時間 (厳密ではない(効率優先))
    • オンデマンド (not require)
  • バッテリーやネットワークリソースに易しい設計である
  • Authenticator機能を使用してログインが必要なサーバとも同期可能
  • Authenticator機能が不要であればスタブでよい(アカウントは必須ではない)
  • ContentProviderと連携したデータ管理, 操作をサポートする
  • ContentProviderの使用は必須ではないが強く推奨されている

Transferring Data Using Sync Adapters

Synchronizing data between an Android device and web servers can make your application significantly more useful and compelling for your users. For example, transferring data to a web server makes a useful backup, and transferring data from a server makes it available to the user even when the device is offline. In some cases, users may find it easier to enter and edit their data in a web interface and then have that data available on their device, or they may want to collect data over time and then upload it to a central storage area.

AndroidデバイスとWebサーバー間のデータ同期を行うアプリケーションは魅力的に映る. 例えばデータをサーバに移してバックアップをとったり, サーバからデータを取得してオフライン操作を可能にする. Webインタフェースを使ってデータを簡単に見つけたり編集したりでき, それらのデータをAndroidデバイス上でも使うことができる. 時間をかけて集めたデータをサーバにアップロードして管理することも可能だ.

Although you can design your own system for doing data transfers in your app, you should consider using Android’s sync adapter framework. This framework helps manage and automate data transfers, and coordinates synchronization operations across different apps. When you use this framework, you can take advantage of several features that aren’t available to data transfer schemes you design yourself:

アプリでデータ転送を行う場合, Android標準のsync adapter frameworkの使用を検討すべきである. このframeworkはデータの管理と自動転送の手段を提供する. そして, 端末にあるアプリ全体のデータ同期タイミングを調整してくれる. このframeworkを使用するといくつかのアドバンテージを得られる.

Plug-in architecture
Allows you to add data transfer code to the system in the form of callable components.
Plug-in architecture
データ転送のロジックを呼出し可能なコンポーネントにしてシステムへ追加できる
Automated execution
Allows you to automate data transfer based on a variety of criteria, including data changes, elapsed time, or time of day. In addition, the system adds transfers that are unable to run to a queue, and runs them when possible.
Automated execution
データが更新された時や一定間隔置き, 指定時間といった様々な契機でデータ転送を自動実行できる. また, 実行できなかったものはキューイングされ良しなに再開される.
Automated network checking
The system only runs your data transfer when the device has network connectivity.
Automated network checking
システムはネットワーク接続が有効な時にデータ転送を実行する.
Improved battery performance
Allows you to centralize all of your app’s data transfer tasks in one place, so that they all run at the same time. Your data transfer is also scheduled in conjunction with data transfers from other apps. These factors reduce the number of times the system has to switch on the network, which reduces battery usage.
improved battery performance
システムはデータ転送タスクを一元管理して, 同時実行されてもシステムはうまくタスクスケジューリングしてくれる. これによりネットワーク接続の回数を減らしてバッテリー消費を抑える.
Account management and authentication
If your app requires user credentials or server login, you can optionally integrate account management and authentication into your data transfer.
Account management and authentication
もし, ユーザのサーバログインが必要であればオプションでAccount ManagementとAuthenticatorとも統合されることができる.

This class shows you how to create a sync adapter and the bound Service that wraps it, how to provide the other components that help you plug the sync adapter into the framework, and how to run the sync adapter to run in various ways.

ここでは, どうやってsync adapterとバインドされたServiceを作成するのか, frameworkにsync adapterを差し込むために必要なコンポーネントをどうやって提供するのか, そして, sync adapterを実行する方法をいくつか紹介する.

Note: Sync adapters run asynchronously, so you should use them with the expectation that they transfer data regularly and efficiently, but not instantaneously. If you need to do real-time data transfer, you should do it in an AsyncTask or an IntentService.

Note: Sync adapterは非同期実行され, 定期的かつ効率的なデータ転送を用途としており, 即時同期を期待すべきではない. もし即時性を求めるならばAsyncTaskIntentServiceの使用を検討すべき.

since: 2014.09.19
source: http://developer.android.com/training/sync-adapters/index.html

Creating a Stub Authenticator

The sync adapter framework assumes that your sync adapter transfers data between device storage associated with an account and server storage that requires login access. For this reason, the framework expects you to provide a component called an authenticator as part of your sync adapter. This component plugs into the Android accounts and authentication framework and provides a standard interface for handling user credentials such as login information.

sync adapter frameworkはログインとアカウント情報が必要なWebサービス/サーバとのデータ転送も想定している. frameworkはあなたから提供されるsync adapterがauthenticatorを持っていることを期待する. このコンポーネントはaccountとauthentication frameworkとログイン画面で使われる.

Even if your app doesn’t use accounts, you still need to provide an authenticator component. If you don’t use accounts or server login, the information handled by the authenticator is ignored, so you can provide an authenticator component that contains stub method implementations. You also need to provide a bound Service that allows the sync adapter framework to call the authenticator’s methods.

もしアプリがアカウントを使用しない場合でもauthenticatorコンポーネントを提供する必要がある. もしアカウントやサーバログインを必要としないのであればauthenticatorをスタブ化すればよい. いずれにせよframeworkがauthenticatorへアクセスするために必要なメソッドはバインドサービスに実装する必要がある.

This lesson shows you how to define all the parts of a stub authenticator that you need to satisfy the requirements of the sync adapter framework. If you need to provide a real authenticator that handles user accounts, read the reference documentation for AbstractAccountAuthenticator.

ここではスタブなauthenticatorの実装方法について紹介する. もし認証機構を提供したいのであればAbstractAccountAuthenticatorのドキュメントを参照すること.

Add a Stub Authenticator Component

To add a stub authenticator component to your app, create a class that extends AbstractAccountAuthenticator, and then stub out the required methods, either by returning null or by throwing an exception.

スタブ用コンポーネントにAbstractAccountAuthenticatorクラスを継承させ, スタブメソッドを実装し, メソッドでnullや例外を返すようにする.

The following snippet shows an example of a stub authenticator class:

authenticatorクラスのスニペット:

/*
* Implement AbstractAccountAuthenticator and stub out all
* of its methods
*/

publicclassAuthenticatorextendsAbstractAccountAuthenticator {
// Simple constructor
publicAuthenticator(Context context) {
super(context);
}
// Editing properties is not supported
@Override
public Bundle editProperties(
AccountAuthenticatorResponse r, String s) {
thrownew UnsupportedOperationException();
}
// Don't add additional accounts
@Override
public Bundle addAccount(
AccountAuthenticatorResponse r,
String s,
String s2,
String[] strings,
Bundle bundle) throws NetworkErrorException {
returnnull;
}
// Ignore attempts to confirm credentials
@Override
public Bundle confirmCredentials(
AccountAuthenticatorResponse r,
Account account,
Bundle bundle) throws NetworkErrorException {
returnnull;
}
// Getting an authentication token is not supported
@Override
public Bundle getAuthToken(
AccountAuthenticatorResponse r,
Account account,
String s,
Bundle bundle) throws NetworkErrorException {
thrownew UnsupportedOperationException();
}
// Getting a label for the auth token is not supported
@Override
public String getAuthTokenLabel(String s) {
thrownew UnsupportedOperationException();
}
// Updating user credentials is not supported
@Override
public Bundle updateCredentials(
AccountAuthenticatorResponse r,
Account account,
String s, Bundle bundle) throws NetworkErrorException {
thrownew UnsupportedOperationException();
}
// Checking features for the account is not supported
@Override
public Bundle hasFeatures(
AccountAuthenticatorResponse r,
Account account, String[] strings) throws NetworkErrorException {
thrownew UnsupportedOperationException();
}
}

Bind the Authenticator to the Framework

In order for the sync adapter framework to access your authenticator, you must create a bound Service for it. This service provides an Android binder object that allows the framework to call your authenticator and pass data between the authenticator and the framework.

sync adapter frameworkがあなたのauthenticatorにアクセスできるようにバインドサービスを作成する必要がある. このサービスはframeworkがあなたのauthenticatorを呼び出し, frameworkとauthenticator間でデータ通知できるようにするbinder objectを提供する.

Since the framework starts this Service the first time it needs to access the authenticator, you can also use the service to instantiate the authenticator, by calling the authenticator constructor in the Service.onCreate() method of the service.

frameworkがこのサービスを開始した時, まず初めにauthenticatorへのアクセスを必要とする. authenticatorをインスタンス化するためにService.onCreate()でauthenticatorのコンストラクタを呼ぶ方法がある.

The following snippet shows you how to define the bound Service:

サービスの定義は下記.

/**
* A bound Service that instantiates the authenticator
* when started.
*/

publicclassAuthenticatorServiceextendsService {
...
// Instance field that stores the authenticator object
private Authenticator mAuthenticator;
@Override
publicvoidonCreate() {
// Create a new authenticator object
mAuthenticator = new Authenticator(this);
}
/*
* When the system binds to this Service to make the RPC call
* return the authenticator's IBinder.
*/

@Override
public IBinder onBind(Intent intent) {
return mAuthenticator.getIBinder();
}
}

Add the Authenticator Metadata File

To plug your authenticator component into the sync adapter and account frameworks, you need to provide these framework with metadata that describes the component. This metadata declares the account type you’ve created for your sync adapter and declares user interface elements that the system displays if you want to make your account type visible to the user. Declare this metadata in a XML file stored in the /res/xml/ directory in your app project. You can give any name to the file, although it’s usually called authenticator.xml.

authenticatorをsync adapterとaccount frameworkに結合するには, コンポーネントを定義したmetadataをframeworkに提供する必要がある. metadataはあなたがsync adapterで使用するアカウント種別を宣言し, ユーザに表示するアカウント情報にも使用される. metadataはプロジェクトの/res/xmlにXMLファイルとして格納する. ファイル名は任意だが, 一般的にはauthenticator.xmlが使われる.

This XML file contains a single element <account-authenticator> that has the following attributes:

このXMLファイルには<account-authenticator>タグが1つだけ含まれる. 属性については下記.

android:accountType

The sync adapter framework requires each sync adapter to have an account type, in the form of a domain name. The framework uses the account type as part of the sync adapter’s internal identification. For servers that require login, the account type along with a user account is sent to the server as part of the login credentials.

If your server doesn’t require login, you still have to provide an account type. For the value, use a domain name that you control. While the framework uses it to manage your sync adapter, the value is not sent to your server.

android:accountType

sync adapter frameworkに登録するsync adapterにはaccount typeが必須. account typeはドメイン名の形式となる. frameworkはsync adapterの識別子としてaccount typeを使用する. サーバに対してはログインアカウントとしてログイン検証で使用される.

もしサーバがログインを必要としない場合でもaccount typeをframeworkに提供する必要がある. その時は制御できるドメイン名を指定する. frameworkはsync adapterの管理にaccount typeを使用するに留め, サーバにこれを送信することはしない.

android:icon
Pointer to a Drawable resource containing an icon. If you make the sync adapter visible by specifying the attribute android:userVisible="true" in res/xml/syncadapter.xml, then you must provide this icon resource. It appears in the Accounts section of the system’s Settings app.
android:icon
Drawableリソースを指定する. もしsync adapterの属性としてandroid:userVisible="true"/res/xml/syncadapter.xmlで定義したならば, このリソースの提供は必須である. このアイコンはシステムの設定アプリにあるAccountセクションで表示される.
android:smallIcon
Pointer to a Drawable resource containing a small version of the icon. This resource may be used instead of android:icon in the Accounts section of the system’s Settings app, depending on the screen size.
android:smallIcon
Drawableリソースアイコン(小さい版)を指定する.このアイコンはシステムの設定アプリにあるAccountセクションで画面サイズに依存して表示される.
android:label
Localizable string that identifies the account type to users. If you make the sync adapter visible by specifying the attribute android:userVisible="true" in res/xml/syncadapter.xml, then you should provide this string. It appears in the Accounts section of the system’s Settings app, next to the icon you define for the authenticator.
android:label
ローカライズされたaccount typeの識別子でユーザに表示される. もしsync adapterの属性としてandroid:userVisible="true"/res/xml/syncadapter.xmlで定義したならば, この文字列リソースの提供は必須である. このアイコンはシステムの設定アプリにあるAccountセクションでアカウントのラベルで使用される.

The following snippet shows the XML file for the authenticator you created previously:

authenticatorのXMLファイル定義は下記.

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator
xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="example.com"
android:icon="@drawable/ic_launcher"
android:smallIcon="@drawable/ic_launcher"
android:label="@string/app_name"/>

Declare the Authenticator in the Manifest

In a previous step, you created a bound Service that links the authenticator to the sync adapter framework. To identify this service to the system, declare it in your app manifest by adding the following <service> element as a child element of <application>:

次にsync adapter frameworkへ登録する, ahtuenticatorと紐づいたバインドサービスを作成する. システムがこのサービスを識別できるようにアプリのマニフェストファイルに<service>タグで登録する.

<service
android:name="com.example.android.syncadapter.AuthenticatorService">

<intent-filter>
<actionandroid:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />

</service>

The <intent-filter> element sets up a filter that’s triggered by the intent action android.accounts.AccountAuthenticator, which sent by the system to run the authenticator. When the filter is triggered, the system starts AuthenticatorService, the bound Service you have provided to wrap the authenticator.

<intent-filter>タグはandroid.accounts.AccountAuthenticatorのIntentアクションをトリガできるように宣言する. このIntentアクションはsystemがauthenticatorを実行するときに送信される. このフィルタがトリガされたとき, システムはAuthenticatorServiceを開始する. このAuthenticatorServiceはあなたが定義したauthenticatorをラップしたサービスである.

The <meta-data> element declares the metadata for the authenticator. The android:name attribute links the meta-data to the authentication framework. The android:resource element specifies the name of the authenticator metadata file you created previously.

<meta-data>タグはauthenticatorのmetadataを定義する. android:name属性はauthentication frameworkのmeta-dataとリンクする. android:resource属性にはauthenticator metadataファイルを指定する.

Besides an authenticator, a sync adapter also requires a content provider. If your app doesn’t use a content provider already, go to the next lesson to learn how to create a stub content provider; otherwise, go to the lesson Creating a Sync Adapter.

authenticatorの補足として, sync adapterはContent Providerを必要とする. もしアプリで Content Providerを使用していない場合, Content Providerのスタブを作成する次のレッスンに進めばよい. そうでなければCreating a Sync Adapterに進む.

since: 2014.09.19
source: http://developer.android.com/training/sync-adapters/creating-authenticator.html

Creating a Stub Content Provider

The sync adapter framework is designed to work with device data managed by the flexible and highly secure content provider framework. For this reason, the sync adapter framework expects that an app that uses the framework has already defined a content provider for its local data. If the sync adapter framework tries to run your sync adapter, and your app doesn’t have a content provider, your sync adapter crashes.

sync adapter frameworkはデバイスデータを柔軟かつセキュアに管理するためにContent Providerを使うようデザインされている. そのためsync adapter frameworkはアプリがローカルデータをContent Providerを使って管理していることを期待する. もしsync adapter frameworkがあなたのsync adapterを実行したときにContent Providerを持っていないとクラッシュする.

If you’re developing a new app that transfers data from a server to the device, you should strongly consider storing the local data in a content provider. Besides their importance for sync adapters, content providers offer a variety of security benefits and are specifically designed to handle data storage on Android systems. To learn more about creating a content provider, see Creating a Content Provider.

もしサーバからデバイスへデータ転送するアプリを開発しているならContent Providerを使ってデータを保存することを強く検討すべきである. もう1つ, sync adapterの重要なポイントは, Content Providerはセキュリティ面で様々なメリットがあり, Androidシステムのデータストレージに特化した設計であることだ.

However, if you’re already storing local data in another form, you can still use a sync adapter to handle data transfer. To satisfy the sync adapter framework requirement for a content provider, add a stub content provider to your app. A stub provider implements the content provider class, but all of its required methods return null or 0. If you add a stub provider, you can then use a sync adapter to transfer data from any storage mechanism you choose.

ローカルデータをContent Providerで管理していなくても, sync adapterを使う方法はまだある. sync adapter frameworkのContent Providerに対する要件を満たすために, stub content providerの追加を検討する. stub content providerはContentProviderクラスを継承し, すべてのメソッドでnull0を返却する. stub content providerを追加した場合でも任意のストレージ機構を使用してsync adapterを使用できる.

If you already have a content provider in your app, you don’t need a stub content provider. In that case, you can skip this lesson and proceed to the lesson Creating a Sync Adapter. If you don’t yet have a content provider, this lesson shows you how to add a stub content provider that allows you to plug your sync adapter into the framework.

すでにContent Providerを持っているならstub content providerは必要ない. その場合, このレッスンはスキップしてCreating a Sync Adapterに進むといい. もしcontent providerを持っていないならここでstub content providerの作成方法を紹介する.

Add a Stub Content Provider

To create a stub content provider for your app, extend the class ContentProvider and stub out its required methods. The following snippet shows you how to create the stub provider:

stub content providerを作成するためにContentProviderクラスを継承し, 実装必須のメソッドをスタブ定義する.

/*
* Define an implementation of ContentProvider that stubs out
* all methods
*/

publicclassStubProviderextendsContentProvider {
/*
* Always return true, indicating that the
* provider loaded correctly.
*/

@Override
publicbooleanonCreate() {
returntrue;
}
/*
* Return an empty String for MIME type
*/

@Override
public String getType() {
returnnew String();
}
/*
* query() always returns no results
*
*/

@Override
public Cursor query(
Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder) {
returnnull;
}
/*
* insert() always returns null (no URI)
*/

@Override
public Uri insert(Uri uri, ContentValues values) {
returnnull;
}
/*
* delete() always returns "no rows affected" (0)
*/

@Override
publicintdelete(Uri uri, String selection, String[] selectionArgs) {
return0;
}
/*
* update() always returns "no rows affected" (0)
*/

publicintupdate(
Uri uri,
ContentValues values,
String selection,
String[] selectionArgs) {
return0;
}
}

Declare the Provider in the Manifest

The sync adapter framework verifies that your app has a content provider by checking that your app has declared a provider in its app manifest. To declare the stub provider in the manifest, add a <provider> element with the following attributes:

sync adapter frameworkはあなたのアプリがContent Providerを持っているかどうかをマニフェストファイルを参照して検証する. マニフェストでstub content providerを定義するには<provider>タグに次の属性を指定する.

android:name="com.example.android.datasync.provider.StubProvider"
Specifies the fully-qualified name of the class that implements the stub content provider.
android:name="com.example.android.datasync.provider.StubProvider"
絶対参照名でstub content providerのクラス名を指定
android:authorities="com.example.android.datasync.provider"
A URI authority that identifies the stub content provider. Make this value your app’s package name with the string “.provider” appended to it. Even though you’re declaring your stub provider to the system, nothing tries to access the provider itself.
android:authorities="com.example.android.datasync.provider"
stub content providerを識別するURIのAuthorityを指定. Authorityはパッケージ名に”.provider”を追加する形で作成する. stub content providerを定義してシステムに提供しても自身でこれにアクセスすることはしないだろう.
android:exported="false"
Determines whether other apps can access the content provider. For your stub content provider, set the value to false, since there’s no need to allow other apps to see the provider. This value doesn’t affect the interaction between the sync adapter framework and the content provider.
android:exported="false"
他のアプリがこのcontent providerにアクセスできるかどうかを指定する. stub content providerであれば他アプリからアクセスさせる必要がないのでfalseを設定する. この値はsync adapter frameworkとcontent providerとのインタラクションに影響しない.
android:syncable="true"
Sets a flag that indicates that the provider is syncable. If you set this flag to true, you don’t have to call setIsSyncable() in your code. The flag allows the sync adapter framework to make data transfers with the content provider, but transfers only occur if you do them explicitly.
android:syncable="true"
このflagはproviderが同期可能であることを示唆する. もしtrueを設定したならば, コード上でsetIsSyncable()を呼ぶ必要がなくなる. このflagはsync adapter frameworkがcontent providerを使って転送データを作るのを許可する. ただし, あなたが望む場合にだけ転送が発生する.

The following snippet shows you how to add the <provider> element to the app manifest:

<provider>タグの書き方は下記.

<manifestxmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.network.sync.BasicSyncAdapter"
android:versionCode="1"
android:versionName="1.0">

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">

...
<provider
android:name="com.example.android.datasync.provider.StubProvider"
android:authorities="com.example.android.datasync.provider"
android:exported="false"
android:syncable="true"/>

...
</application>
</manifest>

Now that you have created the dependencies required by the sync adapter framework, you can create the component that encapsulates your data transfer code. This component is called a sync adapter. The next lesson shows you how to add this component to your app.

sync adapter frameworkに必要なものを作成したら, 次はデータ転送をカプセル化したコンポーネントを作成する. このコンポーネントはsync adapterと呼ばれており, 次のレッスンでコンポーネントの追加方法を紹介する.

since: 2014.09.19
source: http://developer.android.com/training/sync-adapters/creating-stub-provider.html

Creating a Sync Adapter

The sync adapter component in your app encapsulates the code for the tasks that transfer data between the device and a server. Based on the scheduling and triggers you provide in your app, the sync adapter framework runs the code in the sync adapter component. To add a sync adapter component to your app, you need to add the following pieces:

sync adapter componentはサーバとデバイス間のデータ転送を行うタスクのコードをカプセル化する. スケジューリングとアプリが提供するトリガを契機に, sync adapter frameworkがsync adapter componenetのデータ転送コードを実行する. sync adapter componentをアプリに追加するには次のコンポーネントが必要になる:

Sync adapter class.
A class that wraps your data transfer code in an interface compatible with the sync adapter framework.
Sync adapter class
sync adapter frameworkと互換性のあるインタフェースで実装されたデータ転送コードをもつクラス.
Bound Service.
A component that allows the sync adapter framework to run the code in your sync adapter class.
Bound Service
sync adapter frameworkがsync adapterクラスを実行できるようにするコンポーネント
Sync adapter XML metadata file.
A file containing information about your sync adapter. The framework reads this file to find out how to load and schedule your data transfer.
Sync adapter XML metadata file.
sync adapterの情報が含まれたファイル. frameworkはこのファイルからデータトランスファの読み込み方とスケジュールを参照する.
Declarations in the app manifest.
XML that declares the bound service and points to sync adapter-specific metadata.
Declarations in the app manifest.
XMLにはサービスとsync adapterのmetadataファイルを定義する.

This lesson shows you how to define these elements.

このレッスンでは上記の要素をどう定義するかを紹介する.

Create a Sync Adapter Class

In this part of the lesson you learn how to create the sync adapter class that encapsulates the data transfer code. Creating the class includes extending the sync adapter base class, defining constructors for the class, and implementing the method where you define the data transfer tasks.

この章では, データ転送コードをカプセル化したsync adapterクラスの作成方法を紹介する. クラスを作成するにはsync adapterを拡張し, コンストラクタを作成し, データ転送タスクのメソッドを実装する.

Extend the base sync adapter class AbstractThreadedSyncAdapter

To create the sync adapter component, start by extending AbstractThreadedSyncAdapterand writing its constructors. Use the constructors to run setup tasks each time your sync adapter component is created from scratch, just as you use Activity.onCreate() to set up an activity. For example, if your app uses a content provider to store data, use the constructors to get a ContentResolver instance. Since a second form of the constructor was added in Android platform version 3.0 to support the parallelSyncs argument, you need to create two forms of the constructor to maintain compatibility.

sync adapter componentを作成するために, AbstractThreadedSyncAdapterクラスを継承し, コンストラクタを定義する. コンストラクタではActivity.onCreate()のように, sync adapter componentを初期化・構築する. 例えば, アプリがContent Providerを使用してデータを保存する場合, コンストラクタでContentResolverインスタンスを取得する. 2つめのコンストラクタはAndroid3.0からサポートされた引数parallelSyncsが追加されている. あなたは互換性のためにこの2つのコンストラクタをメンテする必要がある.

Note: The sync adapter framework is designed to work with sync adapter components that are singleton instances. Instantiating the sync adapter component is covered in more detail in the section Bind the Sync Adapter to the Framework.

Note: sync adapter frameworkはsync adapter componentsがsingletonインスタンスとして動作するようにデザインされている. sync adapter componentについてはBind the Sync Adapter to the Frameworkでより詳細に扱っている.

The following example shows you how to implement AbstractThreadedSyncAdapterer and its constructors:

AbstractTreadedSyncAdapterのコンストラクタを実装したサンプル:

/**
* Handle the transfer of data between a server and an
* app, using the Android sync adapter framework.
*/

publicclassSyncAdapterextendsAbstractThreadedSyncAdapter {
...
// Global variables
// Define a variable to contain a content resolver instance
ContentResolver mContentResolver;
/**
* Set up the sync adapter
*/

publicSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
/*
* If your app uses a content resolver, get an instance of it
* from the incoming Context
*/

mContentResolver = context.getContentResolver();
}
...
/**
* Set up the sync adapter. This form of the
* constructor maintains compatibility with Android 3.0
* and later platform versions
*/

publicSyncAdapter(
Context context,
boolean autoInitialize,
boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
/*
* If your app uses a content resolver, get an instance of it
* from the incoming Context
*/

mContentResolver = context.getContentResolver();
...
}

Add the data transfer code to onPerformSync()

The sync adapter component does not automatically do data transfer. Instead, it encapsulates your data transfer code, so that the sync adapter framework can run the data transfer in the background, without involvement from your app. When the framework is ready to sync your application’s data, it invokes your implementation of the method onPerformSync().

sync adapter componentが勝手にデータ転送することはしない. 代わりに, あなたのアプリの関与なしにカプセル化されたデータ転送コードをsync adapter frameworkがバックグラウンドで実行する. frameworkがデータ転送の準備が整ったら, onPerformSync()メソッドを呼び出す.

To facilitate the transfer of data from your main app code to the sync adapter component, the sync adapter framework calls onPerformSync() with the following arguments:

sync adapter componentにデータ転送させるため, sync adapter frameworkはonPerformSync()に次の引数を渡す.

Account
An Account object associated with the event that triggered the sync adapter. If your server doesn’t use accounts, you don’t need to use the information in this object.
Account
Accountオブジェクトはsync adapterがトリガされたイベントに関連したオブジェクト. もしあなたのサーバがアカウントを必要としないのであれば, このオブジェクトの情報も必要ない.
Extras
A Bundle containing flags sent by the event that triggered the sync adapter.
Extras
sync adapterをトリガしたイベントから送信されたflagを持つBundle.
Authority
The authority of a content provider in the system. Your app has to have access to this provider. Usually, the authority corresponds to a content provider in your own app.
Authority
システムにあるContent ProviderのAuthority. あなたのアプリはこのContent Providerにアクセスできる必要がある. 通常自アプリのContent Providerのものを指定する.
Content provider client
A ContentProviderClient for the content provider pointed to by the authority argument. A ContentProviderClient is a lightweight public interface to a content provider. It has the same basic functionality as a ContentResolver. If you’re using a content provider to store data for your app, you can connect to the provider with this object. Otherwise, you can ignore it.
Content provider client
ContentProviderClientは引数authorityに対応するContente Providerのクライアントである. ContentProviderClientは軽量なContentProviderの公開インタフェースである. ContentResolverが持つ基本的な機能を備える. もしContent providerを使ってデータを保存したいならContentProviderClientを使って接続できる. 不要ならこれを無視できる.
Sync result
A SyncResult object that you use to send information to the sync adapter framework.
Sync result
SyncResultオブジェクトはsync adapter frameworkへ情報を送信するのに使用する.

The following snippet shows the overall structure of onPerformSync():

onPerformSync()について記す.

/*
* Specify the code you want to run in the sync adapter. The entire
* sync adapter runs in a background thread, so you don't have to set
* up your own background processing.
*/

@Override
publicvoidonPerformSync(
Account account,
Bundle extras,
String authority,
ContentProviderClient provider,
SyncResult syncResult) {
/*
* Put the data transfer code here.
*/

...
}

While the actual implementation of onPerformSync() is specific to your app’s data synchronization requirements and server connection protocols, there are a few general tasks your implementation should perform:

onPerformSync()の実装はアプリデータ同期要件とサーバ接続プロトコルによって固有のものとなるが, いくつか一般的なタスクもある.

Connecting to a server
Although you can assume that the network is available when your data transfer starts, the sync adapter framework doesn’t automatically connect to a server.
Connecting to a server
あなたはネットワーク接続が有効の前提でデータ転送を開始することができるが, sync adapter frameworkはサーバへ自動接続するようなことはしない.
Downloading and uploading data
A sync adapter doesn’t automate any data transfer tasks. If you want to download data from a server and store it in a content provider, you have to provide the code that requests the data, downloads it, and inserts it in the provider. Similarly, if you want to send data to a server, you have to read it from a file, database, or provider, and send the necessary upload request. You also have to handle network errors that occur while your data transfer is running.
Downloading andr uploading data
sync adapterはいかなるデータ転送タスクも自動化しない. もしサーバからデータをダウンロードしてcontent providerを使って保存したい場合, データをリクエストして, ダウンロードして, providerでinsertするコードを提供する必要がある. 同じように, サーバへデータを送信したい場合はファイル,データベース, content providerを使って読み込み, 必要なアップロードリクエストを送信する. あなたはデータ転送の実行時に発生するネットワークエラーもハンドルする必要がある.
Handling data conflicts or determining how current the data is
A sync adapter doesn’t automatically handle conflicts between data on the server and data on the device. Also, it doesn’t automatically detect if the data on the server is newer than the data on the device, or vice versa. Instead, you have to provide your own algorithms for handling this situation.
Handling data conflicts or determining how current the data is
sync adapter はデバイスとサーバ間データのコンフリクトを自動でハンドルしない. またサーバとデバイスどちらのデータが新しいかについても検出しない. 代わりに独自のアルゴリズムを作ってこれを解決する必要がある.
Clean up.
Always close connections to a server and clean up temp files and caches at the end of your data transfer.
Clean up.
データ転送が終了したらサーバとのコネクションや添付ファイル, キャッシュの後始末をすること.

Note: The sync adapter framework runs onPerformSync() on a background thread, so you don’t have to set up your own background processing.

Note sync adapter framework はonPerformSync()をバックグラウンドスレッドで実行する. あなたはバックグラウンドプロセスをわざわざ作成する必要がない.

In addition to your sync-related tasks, you should try to combine your regular network-related tasks and add them to onPerformSync(). By concentrating all of your network tasks in this method, you conserve the battery power that’s needed to start and stop the network interfaces. To learn more about making network access more efficient, see the training class Transferring Data Without Draining the Battery, which describes several network access tasks you can include in your data transfer code.

onPerformSync()には同期関連タスクに加えて, 通常のネットワーク関連タスクも実装する. ネットワーク関連のタスクはこのメソッドに集約される. ネットワーク接続のstart/stopはバッテリーを消耗する. 効率的なネットワークアクセスについてはTransferring Data Without Draining the Batteryを参照. ネットワークアクセスについて有用なコードが紹介されている.

Bind the Sync Adapter to the Framework

You now have your data transfer code encapsulated in a sync adapter component, but you have to provide the framework with access to your code. To do this, you need to create a bound Service that passes a special Android binder object from the sync adapter component to the framework. With this binder object, the framework can invoke the onPerformSync() method and pass data to it.

ここまでで, データ転送コードはsync adapter componentにカプセル化されたわけだが, frameworkにアクセス手段を提供するコードを提供しなければならない. これをするにはsync adapter componentのBinder Objectをframeworkに渡すバインドサービスを作成する. このBinderはframeworkがonPerformSync()メソッドを実行してデータを渡せるものであること.

Instantiate your sync adapter component as a singleton in the onCreate() method of the service. By instantiating the component in onCreate(), you defer creating it until the service starts, which happens when the framework first tries to run your data transfer. You need to instantiate the component in a thread-safe manner, in case the sync adapter framework queues up multiple executions of your sync adapter in response to triggers or scheduling.

サービスのonCreate()メソッドでsync adapter componentをsingletonインスタンスとしてインスタンス化する. onCreate()でコンポーネントがインスタンス化されるため, frameworkが最初にデータ転送をしようとサービスを開始するまでsync adapter componentの作成は延期される. コンポーネントのインスタンス化はスレッドセーフにすること. sync adapter frameworkは応答へのトリガやスケジューリングによるsync adapterの複数の実行をキューイングする.

For example, the following snippet shows you how to create a class that implements the bound Service, instantiates your sync adapter component, and gets the Android binder object:

サービスを実装してsync adapter componentをインスタンス化し, Binder objectを取得するコードを例示する.

package com.example.android.syncadapter;
/**
* Define a Service that returns an IBinder for the
* sync adapter class, allowing the sync adapter framework to call
* onPerformSync().
*/

publicclassSyncServiceextendsService {
// Storage for an instance of the sync adapter
privatestatic SyncAdapter sSyncAdapter = null;
// Object to use as a thread-safe lock
privatestaticfinal Object sSyncAdapterLock = new Object();
/*
* Instantiate the sync adapter object.
*/

@Override
publicvoidonCreate() {
/*
* Create the sync adapter as a singleton.
* Set the sync adapter as syncable
* Disallow parallel syncs
*/

synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
}
}
}
/**
* Return an object that allows the system to invoke
* the sync adapter.
*
*/

@Override
public IBinder onBind(Intent intent) {
/*
* Get the object that allows external processes
* to call onPerformSync(). The object is created
* in the base class code when the SyncAdapter
* constructors call super()
*/

return sSyncAdapter.getSyncAdapterBinder();
}
}

Note: To see a more detailed example of a bound service for a sync adapter, see the sample app.

Note: sync adapterのためのバインドサービスについての詳細な例はサンプルアプリを参照.

Add the Account Required by the Framework

The sync adapter framework requires each sync adapter to have an account type. You declared the account type value in the section Add the Authenticator Metadata File. Now you have to set up this account type in the Android system. To set up the account type, add a dummy account that uses the account type by calling addAccountExplicitly().

sync adapter frameworkはsync adapterがaccount typeを持っていることを期待する. account typeの定義についてはAdd the Authenticator Metadata Fileのセクションを参照. account typeをセットアップするためにダミーのアカウントを追加するにはaddAccountExplicitly()を使えきる.

The best place to call the method is in the onCreate() method of your app’s opening activity. The following code snippet shows you how to do this:

ActivityのonCreate()メソッドはこのメソッドを呼ぶのに都合のいい場所になる.

publicclassMainActivityextendsFragmentActivity {
...
...
// Constants
// The authority for the sync adapter's content provider
publicstaticfinal String AUTHORITY = "com.example.android.datasync.provider"
// An account type, in the form of a domain name
publicstaticfinal String ACCOUNT_TYPE = "example.com";
// The account name
publicstaticfinal String ACCOUNT = "dummyaccount";
// Instance fields
Account mAccount;
...
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
// Create the dummy account
mAccount = CreateSyncAccount(this);
...
}
...
/**
* Create a new dummy account for the sync adapter
*
* @param context The application context
*/

publicstatic Account CreateSyncAccount(Context context) {
// Create the account type and default account
Account newAccount = new Account(
ACCOUNT, ACCOUNT_TYPE);
// Get an instance of the Android account manager
AccountManager accountManager =
(AccountManager) context.getSystemService(
ACCOUNT_SERVICE);
/*
* Add the account and account type, no password or user data
* If successful, return the Account object, otherwise report an error.
*/

if (accountManager.addAccountExplicitly(newAccount, null, null))) {
/*
* If you don't set android:syncable="true" in
* in your <provider> element in the manifest,
* then call context.setIsSyncable(account, AUTHORITY, 1)
* here.
*/

} else {
/*
* The account exists or some other error occurred. Log this, report it,
* or handle it internally.
*/

}
}
...
}

Add the Sync Adapter Metadata File

To plug your sync adapter component into the framework, you need to provide the framework with metadata that describes the component and provides additional flags. The metadata specifies the account type you’ve created for your sync adapter, declares a content provider authority associated with your app, controls a part of the system user interface related to sync adapters, and declares other sync-related flags. Declare this metadata in a special XML file stored in the /res/xml/ directory in your app project. You can give any name to the file, although it’s usually called syncadapter.xml.

frameworkにsync adapterを組み込むのに, コンポーネントを指定するmetadataと追加のflagグを提供する必要がある. metadataはaccount typeを指定し, sync adapterを生成し, アプリに関連するcontent providerのauthorityを解決し, systemUIでsync adapterに関連する一部を制御し, 他の同期に関連するflagを宣言する. metadataの宣言は/res/xmlディレクトリにあるXMLファイルで行う. ファイル名は任意だが, 一般的にsyncadapter.xmlが使用される.

This XML file contains a single XML element <sync-adapter> that has the following attributes:

XMLファイルには<sync-adapter>要素だけが含まれる. 次はそれぞれの属性:

android:contentAuthority
The URI authority for your content provider. If you created a stub content provider for your app in the previous lesson Creating a Stub Content Provider, use the value you specified for the attribute android:authorities in the <provider> element you added to your app manifest. This attribute is described in more detail in the section Declare the Provider in the Manifest.
If you’re transferring data from a content provider to a server with your sync adapter, this value should be the same as the content URI authority you’re using for that data. This value is also one of the authorities you specify in the android:authorities attribute of the <provider> element that declares your provider in your app manifest.
android:contentAuthority
Content ProviderのURI Authorityを指定する. もしstub content providerを作成しているのであればCreating a Stub Content Providerのレッスンを参照. ここで使用する値はマニフェストで宣言される<provider>タグのandroid:authoritiesの値を指定する. この属性についての詳細はDeclare the Provider in the Manifestのセクションを参照.
もし, sync adapterでContent Providerを使ってデータ転送するのであれば, この値はコンテンツURIのauthorityと揃えるべきである. この値はandroid:authoritiesで指定されたcontent providerを解決する.
android:accountType
The account type required by the sync adapter framework. The value must be the same as the account type value you provided when you created the authenticator metadata file, as described in the section Add the Authenticator Metadata File. It’s also the value you specified for the constant ACCOUNT_TYPE in the code snippet in the section Add the Account Required by the Framework.
android:accountType
account typeはsync adapter frameworkが必要とする. この値はあなたが作成したauthenticator metadataで提供されるaccount typeの値となる. この説明はAdd the Authenticator Metadata Fileを参照. またはAdd the Account required by the Frameworkセクションのコードスニペットで定義したACCOUNT_TYPE定数.

Settings attributes

android:userVisible
Sets the visibility of the sync adapter’s account type. By default, the account icon and label associated with the account type are visible in the Accounts section of the system’s Settings app, so you should make your sync adapter invisible unless you have an account type or domain that’s easily associated with your app. If you make your account type invisible, you can still allow users to control your sync adapter with a user interface in one of your app’s activities.
android:userVisible
sync adapterのaccount typeの可視性を設定する. デフォルトではSystem設定アプリのAccountsセクションでアカウントアイコンとラベルが表示される. あなたのsync adapterに紐づくアカウントやドメインがないのであれば不可視に設定すべき. アカウントを不可視に設定しても自前のActivityでアカウントを制御できるように作ることは可能.
android:supportsUploading
Allows you to upload data to the cloud. Set this to false if your app only downloads data.
android:supportsUploading
クラウドへのデータアップロードを許可するかどうか. falseにするとダウンロードのみ可能となる.
android:allowParallelSyncs
Allows multiple instances of your sync adapter component to run at the same time. Use this if your app supports multiple user accounts and you want to allow multiple users to transfer data in parallel. This flag has no effect if you never run multiple data transfers.
android:allowParallelSyncs
sync adapter componentの複数インスタンス化と同時実行を許可するかどうか. マルチユーザをサポートして並列にデータ転送をサポートしたいのであればこのフラグが使える. 複数のデータ転送をしない限りこのフラグには効果がない.
android:isAlwaysSyncable
Indicates to the sync adapter framework that it can run your sync adapter at any time you’ve specified. If you want to programmatically control when your sync adapter can run, set this flag to false, and then call requestSync() to run the sync adapter. To learn more about running a sync adapter, see the lesson Running a Sync Adapter
android:isAlwaysSyncable
sync adapter frameworkがsync adapterをいつでも実行できることを示す. もしsync adapterの実行スケジュールをプログラム制御したい場合は, フラグにfalseをセットしてrequestSync()を呼べばsync adapterが実行される. sync adapterの実行についてはRunning a Sync Adapterを参照.

The following example shows the XML for a sync adapter that uses a single dummy account and only does downloads.

sync adapterがダミーアカウントを使用してダウンロードのみサポートする場合のXMLを例示する.

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter
xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.example.android.datasync.provider"
android:accountType="com.android.example.datasync"
android:userVisible="false"
android:supportsUploading="false"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true"/>

Declare the Sync Adapter in the Manifest

Once you’ve added the sync adapter component to your app, you have to request permissions related to using the component, and you have to declare the bound Service you’ve added.

sync adapter componentをアプリに追加するには, これに関連するpermissionを要求し, バインドサービスの宣言を追加する必要がある.

Since the sync adapter component runs code that transfers data between the network and the device, you need to request permission to access the Internet. In addition, your app needs to request permission to read and write sync adapter settings, so you can control the sync adapter programmatically from other components in your app. You also need to request a special permission that allows your app to use the authenticator component you created in the lesson Creating a Stub Authenticator.

sync adapter componentが実行するコードでネットワークとデバイス間のデータ転送を行うため, Internetへアクセスするpermissionが必要になる. 追加でsync adapter設定のread/write permissionも必要になる. これでsync adapterをプログラムから制御できる. Creating a Stub Authenticatorのレッスンで作成したようなauthenticator componentを作成するには特別なpermissionが必要になる.

To request these permissions, add the following to your app manifest as child elements of <manifest>:

これらのpermissionを要求するための<manifest>の子要素:

android.permission.INTERNET
Allows the sync adapter code to access the Internet so that it can download or upload data from the device to a server. You don’t need to add this permission again if you were requesting it previously.
android.permission.INTERNET
sync adapterがInternetにアクセスするのを許可する. これによりダウンロード/アップロードが可能になる. 既に定義済みなら不要.
android.permission.READ_SYNC_SETTINGS
Allows your app to read the current sync adapter settings. For example, you need this permission in order to call getIsSyncable().
android.permission.READ_SYNC_SETTINGS
現在のsync adapter設定を読み取るのに必要. 例えばgetIsSyncable()メソッドの実行に必要となる.
android.permission.WRITE_SYNC_SETTINGS
Allows your app to control sync adapter settings. You need this permission in order to set periodic sync adapter runs using addPeriodicSync(). This permission is not required to call requestSync(). To learn more about running the sync adapter, see Running A Sync Adapter.
android.permission.WRITE_SYNC_SETTINGS
sync adapter設定の書き込みに必要. このpermissionは定期的にsync adapterを実行するためのaddPeriodicSync()の実行に必要. requestSync()メソッドの実行にこのパーミッションは必要ない. より詳細を学びたいならRunning A Sync Adapterを参考.
android.permission.AUTHENTICATE_ACCOUNTS
Allows you to use the authenticator component you created in the lesson Creating a Stub Authenticator.
android.permission.AUTHENTICATE_ACCOUNTS
Creating a Stub Authenticatorで作成したauthenticator componentの生成に必要.

The following snippet shows how to add the permissions:

permission追加の方法は下記:

<manifest>
...
<uses-permission
android:name="android.permission.INTERNET"/>

<uses-permission
android:name="android.permission.READ_SYNC_SETTINGS"/>

<uses-permission
android:name="android.permission.WRITE_SYNC_SETTINGS"/>

<uses-permission
android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>

...
</manifest>

Finally, to declare the bound Service that the framework uses to interact with your sync adapter, add the following XML to your app manifest as a child element of <application>:

最後に, frameworkと相互通信するsync adapterを持つバインドサービスを定義.

<service
android:name="com.example.android.datasync.SyncService"
android:exported="true"
android:process=":sync">

<intent-filter>
<actionandroid:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-dataandroid:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />

</service>

The <intent-filter> element sets up a filter that’s triggered by the intent action android.content.SyncAdapter, sent by the system to run the sync adapter. When the filter is triggered, the system starts the bound service you’ve created, which in this example is SyncService. The attribute android:exported="true" allows processes other than your app (including the system) to access the Service. The attribute android:process=":sync" tells the system to run the Service in a global shared process named sync. If you have multiple sync adapters in your app they can share this process, which reduces overhead.

システムがsync adapterを実行できるようにするため<intent-filter>android.content.SyncAdapterを定義. システムがバインドサービスを開始するときにトリガされる. 上記例ではSyncServiceにあたる. android:exported="true"属性はシステムを含めた他のプロセスがServiceにアクセスできることを許可するものである. android:process=":sync"属性はサービスをグローバル共有プロセスであるsyncで動作させることを指定している. もし複数のsync adapterをもっているなら, このプロセスリソースを共有することで, オーバヘッドを軽減させる.

The <meta-data> element provides provides the name of the sync adapter metadata XML file you created previously. The android:name attribute indicates that this metadata is for the sync adapter framework. The android:resource element specifies the name of the metadata file.

<meta-data>要素にはsync adapterのmetadata XMLファイルを指定する. android:nameの値はこれがsync adapter frameworkのものであることを示す. android:resouce要素はmetadataファイルの名前を指定する.

You now have all of the components for your sync adapter. The next lesson shows you how to tell the sync adapter framework to run your sync adapter, either in response to an event or on a regular schedule.

これですべてのsync adapterのためのコンポーネントを学習した. 次はsync adapter frameworkにsync adapterを実行させる契機(イベントに反応させるor定期的に実行させる)を登録する方法を見ていく.

since: 2014.09.19
source: http://developer.android.com/training/sync-adapters/creating-sync-adapter.html

Running a Sync Adapter

In the previous lessons in this class, you learned how to create a sync adapter component that encapsulates data transfer code, and how to add the additional components that allow you to plug the sync adapter into the system. You now have everything you need to install an app that includes a sync adapter, but none of the code you’ve seen actually runs the sync adapter.

前のレッスンでsync adapter componentのイロハを学んだ. これでsync adapterをアプリに追加できるがこれを実行する術を身につけていない.

You should try to run your sync adapter based on a schedule or as the indirect result of some event. For example, you may want your sync adapter to run on a regular schedule, either after a certain period of time or at a particular time of the day. You may also want to run your sync adapter when there are changes to data stored on the device. You should avoid running your sync adapter as the direct result of a user action, because by doing this you don’t get the full benefit of the sync adapter framework’s scheduling ability. For example, you should avoid providing a refresh button in your user interface.

sync adapterをスケジュールベースまたは何かのイベントを契機に実行させてみる. 例えば, 一定間隔置きあるいは指定時間に実行させるといった具合に. デバイスデータの変更に合わせてsync adapterを実行したい場合に, ユーザの更新アクションを契機に直接sync adapterを実行するような設計は避けるべきである. これではsync adapter frameworkのスケジューリング能力を引き出すことができない. sync adapterを使用するためにリフレッシュボタンを置くようなことは避けるべき.

You have the following options for running your sync adapter:

sync adapterを使用する上でのオプション:

When server data changes
Run the sync adapter in response to a message from a server, indicating that server-based data has changed. This option allows you to refresh data from the server to the device without degrading performance or wasting battery life by polling the server.
When server data changes
サーバ上のデータが変更され, その変更通知を受けてsync adapterを実行する. この方法は, ポーリングによるサーバパフォーマンスの低下や無駄なバッテリー消費を避けることができる.
When device data changes
Run a sync adapter when data changes on the device. This option allows you to send modified data from the device to a server, and is especially useful if you need to ensure that the server always has the latest device data. This option is straightforward to implement if you actually store data in your content provider. If you’re using a stub content provider, detecting data changes may be more difficult.
When device data changes
デバイス上のデータが変更された時にsync adapterを実行する. この方法ではデバイスからサーバへ更新データを送信して、サーバが最新の情報を持つようにできる. これをContent Providerで実装すれば簡単に実現できる. もしStud content providerを使っているならデータ変更の検知から実装する必要があり複雑である.
When the system sends out a network message
Run a sync adapter when the Android system sends out a network message that keeps the TCP/IP connection open; this message is a basic part of the networking framework. Using this option is one way to run the sync adapter automatically. Consider using it in conjunction with interval-based sync adapter runs.
When the system sends out a network message
Androidシステムがネットワーク通信のためにTCP/IP 接続したのを契機にsync adapterを実行する. このオプションは自動的にsync adapterを実行するための方法でもある. 間隔をおいて同期実行するsync adapterの方法とあわせて検討できる.
At regular intervals
Run a sync adapter after the expiration of an interval you choose, or run it at a certain time every day.
At regular intervals
一定時間後であったり, 毎日特定時刻になるとsync adapterを実行する.
On demand
Run the sync adapter in response to a user action. However, to provide the best user experience you should rely primarily on one of the more automated options. By using automated options, you conserve battery and network resources.
On demand
ユーザアクションに応じてsync adapterを実行する. ただし, よりよいUXを提供するには他のいずれかのオプションを指定すべきである. 自動化オプションはバッテリーとネットワークリソースを節約する.

The rest of this lesson describes each of the options in more detail.

残りのレッスンは各オプションの詳細についてみていく.

Run the Sync Adapter When Server Data Changes

If your app transfers data from a server and the server data changes frequently, you can use a sync adapter to do downloads in response to data changes. To run the sync adapter, have the server send a special message to a BroadcastReceiver in your app. In response to this message, call ContentResolver.requestSync() to signal the sync adapter framework to run your sync adapter.

もしアプリがサーバからデータを受け取り, かつサーバデータが頻繁に更新されるのであればsync adapterをデータ変更時のダウンローダとして使える. サーバは特別なメッセージをBroadcastReceiverに対して送信しsync adapterを実行する. メッセージを受けたらContentResolver.requestSync()を実行する. この命令でsync adapter frameworkがsync adapterを実行する.

Google Cloud Messaging (GCM) provides both the server and device components you need to make this messaging system work. Using GCM to trigger transfers is more reliable and more efficient than polling servers for status. While polling requires a Service that is always active, GCM uses a BroadcastReceiver that’s activated when a message arrives. While polling at regular intervals uses battery power even if no updates are available, GCM only sends messages when needed.

サーバでメッセージを作りデバイスにこれを送信する. GCMはポーリングより効率的かつ信頼できる. ポーリングでは常にサービスが稼働しているが, GCMではBroadcastReceiverを使用して必要なメッセージがある時にしかサービスを稼働させない. ポーリングはメッセージや更新がないときもバッテリーを消費し続けるがGCMではメッセージが送られた時にしか消費しない.

Note: If you use GCM to trigger your sync adapter via a broadcast to all devices where your app is installed, remember that they receive your message at roughly the same time. This situation can cause multiple instance of your sync adapter to run at the same time, causing server and network overload. To avoid this situation for a broadcast to all devices, you should consider deferring the start of the sync adapter for a period that’s unique for each device.

Note: GCMでbroadcastを経由してsync adapterのトリガとする時, GCMが世界中のアプリインストールされたデバイスに一斉配信されてサーバへ同時アクセスしてくるシチュエーションを想定すること. サーバとネットワークリソースの過負荷を回避するため, GCMをトリガとする場合はアクセスが集中しないように分散させること.

The following code snippet shows you how to run requestSync() in response to an incoming GCM message:

GCM受信を契機にrequestSync()するコード:

publicclassGcmBroadcastReceiverextendsBroadcastReceiver {
...
// Constants
// Content provider authority
publicstaticfinal String AUTHORITY = "com.example.android.datasync.provider"
// Account type
publicstaticfinal String ACCOUNT_TYPE = "com.example.android.datasync";
// Account
publicstaticfinal String ACCOUNT = "default_account";
// Incoming Intent key for extended data
publicstaticfinal String KEY_SYNC_REQUEST =
"com.example.android.datasync.KEY_SYNC_REQUEST";
...
@Override
publicvoidonReceive(Context context, Intent intent) {
// Get a GCM object instance
GoogleCloudMessaging gcm =
GoogleCloudMessaging.getInstance(context);
// Get the type of GCM message
String messageType = gcm.getMessageType(intent);
/*
* Test the message type and examine the message contents.
* Since GCM is a general-purpose messaging system, you
* may receive normal messages that don't require a sync
* adapter run.
* The following code tests for a a boolean flag indicating
* that the message is requesting a transfer from the device.
*/

if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)
&&
intent.getBooleanExtra(KEY_SYNC_REQUEST)) {
/*
* Signal the framework to run your sync adapter. Assume that
* app initialization has already created the account.
*/

ContentResolver.requestSync(ACCOUNT, AUTHORITY, null);
...
}
...
}
...
}

Run the Sync Adapter When Content Provider Data Changes

If your app collects data in a content provider, and you want to update the server whenever you update the provider, you can set up your app to run your sync adapter automatically. To do this, you register an observer for the content provider. When data in your content provider changes, the content provider framework calls the observer. In the observer, call requestSync() to tell the framework to run your sync adapter.

Content Providerでデータを管理している場合に, Content Providerが更新されるたびにサーバもアップデートしたい時, sync adapterを自動化して同期させることができる. これをするには, Content ProviderのObserverを登録する. Content Providerのデータが更新されたとき, Content Provider frameworkはobserverを呼び出す. observerはreqyestSync()を呼び出してframeworkにsync adapterを実行させる.

Note: If you’re using a stub content provider, you don’t have any data in the content provider and onChange() is never called. In this case, you have to provide your own mechanism for detecting changes to device data. This mechanism is also responsible for calling requestSync() when the data changes.

Note: stub content providerを使っている場合はcontent providerでデータを扱うことができないし, observerのonChange()は決して呼ばれない. この場合, 独自の機構を作ってデバイスデータの変更を検出するしかない. この機構でのデータ変更時はrequestSync()を呼び出す必要がある.

To create an observer for your content provider, extend the class ContentObserver and implement both forms of its onChange() method. In onChange(), call requestSync() to start the sync adapter.

content providerのobserverを作成するにはContentObserverクラスを継承し, onChange()メソッドを実装する. onChange()ではrequestSync()を呼びsync adapterを実行する.

To register the observer, pass it as an argument in a call to registerContentObserver(). In this call, you also have to pass in a content URI for the data you want to watch. The content provider framework compares this watch URI to content URIs passed in as arguments to ContentResolver methods that modify your provider, such as ContentResolver.insert(). If there’s a match, your implementation of ContentObserver.onChange() is called.

observerの登録にはregisterContentObserver()の引数にそれを渡す. もう一つの引数に監視対象のURIも必要になる. Content Provider Frameworkは ContentResolver.insert()のようなコンテンツを変更するメソッドが呼ばれた時に, メソッドに渡されるURIを比較してcontent providerの変更を監視する. マッチした場合は実装したContentObserver.onchange()が呼び出される.

The following code snippet shows you how to define a ContentObserver that calls requestSync() when a table

requestSync()を呼ぶContentObserverの実装:

publicclassMainActivityextendsFragmentActivity {
...
// Constants
// Content provider scheme
publicstaticfinal String SCHEME = "content://";
// Content provider authority
publicstaticfinal String AUTHORITY = "com.example.android.datasync.provider";
// Path for the content provider table
publicstaticfinal String TABLE_PATH = "data_table";
// Account
publicstaticfinal String ACCOUNT = "default_account";
// Global variables
// A content URI for the content provider's data table
Uri mUri;
// A content resolver for accessing the provider
ContentResolver mResolver;
...
publicclassTableObserverextendsContentObserver {
/*
* Define a method that's called when data in the
* observed content provider changes.
* This method signature is provided for compatibility with
* older platforms.
*/

@Override
publicvoidonChange(boolean selfChange) {
/*
* Invoke the method signature available as of
* Android platform version 4.1, with a null URI.
*/

onChange(selfChange, null);
}
/*
* Define a method that's called when data in the
* observed content provider changes.
*/

@Override
publicvoidonChange(boolean selfChange, Uri changeUri) {
/*
* Ask the framework to run your sync adapter.
* To maintain backward compatibility, assume that
* changeUri is null.
ContentResolver.requestSync(ACCOUNT, AUTHORITY, null);
}
...
}
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
// Get the content resolver object for your app
mResolver = getContentResolver();
// Construct a URI that points to the content provider data table
mUri = new Uri.Builder()
.scheme(SCHEME)
.authority(AUTHORITY)
.path(TABLE_PATH)
.build();
/*
* Create a content observer object.
* Its code does not mutate the provider, so set
* selfChange to "false"
*/

TableObserver observer = new TableObserver(false);
/*
* Register the observer for the data table. The table's path
* and any of its subpaths trigger the observer.
*/

mResolver.registerContentObserver(mUri, true, observer);
...
}
...
}

Run the Sync Adapter After a Network Message

When a network connection is available, the Android system sends out a message every few seconds to keep the device’s TCP/IP connection open. This message also goes to the ContentResolver of each app. By calling setSyncAutomatically(), you can run the sync adapter whenever the ContentResolver receives the message.

ネットワーク接続が有効な時, AndroidはTCP/IP接続を維持するために数秒ごとにメッセージを送信する. このメッセージはContentResolverに届き, setSyncAutomatically()を呼ぶことでContentResolverがメッセージを受信する度にsync adapterを実行させることもできる.

By scheduling your sync adapter to run when the network message is sent, you ensure that your sync adapter is always scheduled to run while the network is available. Use this option if you don’t have to force a data transfer in response to data changes, but you do want to ensure your data is regularly updated. Similarly, you can use this option if you don’t want a fixed schedule for your sync adapter, but you do want it to run frequently.

ネットワークメッセージが送信された際にsync adapterを実行するようにスケジュールすると, sync adapterはネットワーク接続が有効になる都度実行される. このオプションはデータ変更時の強制同期を必要とはしないものの, それなりの頻度でデータをアップデートしたい時に使用できる. 定期的なスケジューリングは望まないが頻繁なアップデートを望む場合に向いている.

Since the method setSyncAutomatically() doesn’t disable addPeriodicSync(), your sync adapter may be triggered repeatedly in a short period of time. If you do want to run your sync adapter periodically on a regular schedule, you should disable setSyncAutomatically().

setSyncAutomatically()メソッドはaddPeriodicSync()を無効化しない. sync adapterは短いスパンで繰り返しトリガされることになる. 一定期間置きに同期実行されたい場合はsetSyncAutomatically()を無効化すべき.

The following code snippet shows you how to configure your ContentResolver to run your sync adapter in response to a network message:

下記はネットワークメッセージに応じてContentResolverからsync adapterを実行させるコード:

publicclassMainActivityextendsFragmentActivity {
...
// Constants
// Content provider authority
publicstaticfinal String AUTHORITY = "com.example.android.datasync.provider";
// Account
publicstaticfinal String ACCOUNT = "default_account";
// Global variables
// A content resolver for accessing the provider
ContentResolver mResolver;
...
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
// Get the content resolver for your app
mResolver = getContentResolver();
// Turn on automatic syncing for the default account and authority
mResolver.setSyncAutomatically(ACCOUNT, AUTHORITY, true);
...
}
...
}

Run the Sync Adapter Periodically

You can run your sync adapter periodically by setting a period of time to wait between runs, or by running it at certain times of the day, or both. Running your sync adapter periodically allows you to roughly match the update interval of your server.

一定の間隔でsync adapterを実行させることができる. これによりサーバとの更新間隔を一定にできる.

Similarly, you can upload data from the device when your server is relatively idle, by scheduling your sync adapter to run at night. Most users leave their powered on and plugged in at night, so this time is usually available. Moreover, the device is not running other tasks at the same time as your sync adapter. If you take this approach, however, you need to ensure that each device triggers a data transfer at a slightly different time. If all devices run your sync adapter at the same time, you are likely to overload your server and cell provider data networks.

夜間にアップロードするようにスケジュールすれば比較的アイドル状態の時に同期させることができる. ほとんどのユーザが夜に充電するため, デバイスが有効である可能性も高い. このアプローチをとるとき, 各端末からアクセスが集中してネットワークやサーバが過負荷とならないよう配慮すること.

In general, periodic runs make sense if your users don’t need instant updates, but expect to have regular updates. Periodic runs also make sense if you want to balance the availability of up-to-date data with the efficiency of smaller sync adapter runs that don’t over-use device resources.

一般的に, ユーザがインスタントアップデートを望まないが, 定期的なアップデートを望むような場合に使える. データ可用性のバランスを保つために効率的かつ小さくsync adapterを定期実行してデータをアップデートすることは, デバイスのリソースを占有しすぎることをせず有効である.

To run your sync adapter at regular intervals, call addPeriodicSync(). This schedules your sync adapter to run after a certain amount of time has elapsed. Since the sync adapter framework has to account for other sync adapter executions and tries to maximize battery efficiency, the elapsed time may vary by a few seconds. Also, the framework won’t run your sync adapter if the network is not available.

sync adapterを定期実行するためにaddPeriodicSync()を呼ぶ. このスケジュールはsync adapterを一定時間経過後に実行させる. ただし, sync adapter frameworkはバッテリ効率化のために間近にスケジュールされているsync adapterをまとめて実行する. そのため, 予定時刻からずれて実行させるケースがある. また指定時間にネットワークが有効でない場合は同期実行されない.

Notice that addPeriodicSync() doesn’t run the sync adapter at a particular time of day. To run your sync adapter at roughly the same time every day, use a repeating alarm as a trigger. Repeating alarms are described in more detail in the reference documentation for AlarmManager. If you use the method setInexactRepeating() to set time-of-day triggers that have some variation, you should still randomize the start time to ensure that sync adapter runs from different devices are staggered.

覚書として, addPeriodicSync()は一日の特定の時間にsync adapterを実行しない. 毎日決まった時間に同期実行したいのであればAlarmManagerを参照. setInexactrepeating()メソッドを使って同期時間を集中させることを避けるために実行時間をランダマイズして分散させることを検討すべき.

The method addPeriodicSync() doesn’t disable setSyncAutomatically(), so you may get multiple sync runs in a relatively short period of time. Also, only a few sync adapter control flags are allowed in a call to addPeriodicSync(); the flags that are not allowed are described in the referenced documentation for addPeriodicSync().

addPeriodicSync()メソッドは setSyncAutomatically()を無効化しない. そのため短期間で複数回同期実行される可能性がある. いくつかのsync adapter制御フラグがaddPeriodicSync()で許可される. 許可されないフラグについてはaddPeriodicSync()のドキュメントで説明されている.

The following code snippet shows you how to schedule periodic sync adapter runs:

sync adapterを定期実行させるコード:

publicclassMainActivityextendsFragmentActivity {
...
// Constants
// Content provider authority
publicstaticfinal String AUTHORITY = "com.example.android.datasync.provider";
// Account
publicstaticfinal String ACCOUNT = "default_account";
// Sync interval constants
publicstaticfinallong MILLISECONDS_PER_SECOND = 1000L;
publicstaticfinallong SECONDS_PER_MINUTE = 60L;
publicstaticfinallong SYNC_INTERVAL_IN_MINUTES = 60L;
publicstaticfinallong SYNC_INTERVAL =
SYNC_INTERVAL_IN_MINUTES *
SECONDS_PER_MINUTE *
MILLISECONDS_PER_SECOND;
// Global variables
// A content resolver for accessing the provider
ContentResolver mResolver;
...
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
// Get the content resolver for your app
mResolver = getContentResolver();
/*
* Turn on periodic syncing
*/

ContentResolver.addPeriodicSync(
ACCOUNT,
AUTHORITY,
null,
SYNC_INTERVAL);
...
}
...
}

Run the Sync Adapter On Demand

Running your sync adapter in response to a user request is the least preferable strategy for running a sync adapter. The framework is specifically designed to conserve battery power when it runs sync adapters according to a schedule. Options that run a sync in response to data changes use battery power effectively, since the power is used to provide new data.

ユーザリクエストを契機にsync adapterを実行させるのが最後の戦略になる. sync adapter frameworkはsync adapterをスケジュール実行させてバッテリー節約するようデザインされている. 基本的にデータの変更を契機に同期実行するのがバッテリーにやさしい設計である.

In comparison, allowing users to run a sync on demand means that the sync runs by itself, which is inefficient use of network and power resources. Also, providing sync on demand leads users to request a sync even if there’s no evidence that the data has changed, and running a sync that doesn’t refresh data is an ineffective use of battery power. In general, your app should either use other signals to trigger a sync or schedule them at regular intervals, without user input.

他のオプションと比較して, ユーザに同期タイミングを委ねるネットワークやバッテリーリソースの面でも非効率的である. また, 同期を実行したからといってデータが変更されている保証もなく空振りに終わる可能性もあり, リソースが無駄に使われる. 一般的にユーザの入力に頼らず, 定期的あるいは他のシグナルをトリガに同期を実行するべきである.

However, if you still want to run the sync adapter on demand, set the sync adapter flags for a manual sync adapter run, then call ContentResolver.requestSync().

しかし, それでもまだ都度sync adapterを実行したいという場合は都度実行用のフラグを設定した上で, ContentResolver.requestSync()を使って手動で同期実行させることができる.

Run on demand transfers with the following flags:

都度実行させるためのフラグ設定:

SYNC_EXTRAS_MANUAL
Forces a manual sync. The sync adapter framework ignores the existing settings, such as the flag set by setSyncAutomatically().
SYNC_EXTRAS_MANUAL
強制同期実行する. sync adapter frameworkはこの時, setSyncAutomatically()で設定されている値を無視する.
SYNC_EXTRAS_EXPEDITED
Forces the sync to start immediately. If you don’t set this, the system may wait several seconds before running the sync request, because it tries to optimize battery use by scheduling many requests in a short period of time.
SYNC_EXTRAS_EXPEDITED
即時同期実行を強制する. これを設定しない場合, sync adapter frameworkはバッテリ効率化のために同期リクエストをスケジューリングしようとするため即時同期実行されない場合がある.

The following code snippet shows you how to call requestSync() in response to a button click:

ボタン押下でrequestSync()メソッドを呼ぶコード:

publicclassMainActivityextendsFragmentActivity {
...
// Constants
// Content provider authority
publicstaticfinal String AUTHORITY =
"com.example.android.datasync.provider"
// Account type
publicstaticfinal String ACCOUNT_TYPE = "com.example.android.datasync";
// Account
publicstaticfinal String ACCOUNT = "default_account";
// Instance fields
Account mAccount;
...
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
/*
* Create the dummy account. The code for CreateSyncAccount
* is listed in the lesson Creating a Sync Adapter
*/


mAccount = CreateSyncAccount(this);
...
}
/**
* Respond to a button click by calling requestSync(). This is an
* asynchronous operation.
*
* This method is attached to the refresh button in the layout
* XML file
*
* @param v The View associated with the method call,
* in this case a Button
*/

publicvoidonRefreshButtonClick(View v) {
...
// Pass the settings flags by inserting them in a bundle
Bundle settingsBundle = new Bundle();
settingsBundle.putBoolean(
ContentResolver.SYNC_EXTRAS_MANUAL, true);
settingsBundle.putBoolean(
ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
/*
* Request the sync for the default account, authority, and
* manual sync settings
*/

ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle);
}

since: 2014.09.19
source: http://developer.android.com/training/sync-adapters/running-sync-adapter.html


License
Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.


Android:ImageryHeaderFragment

$
0
0

Intro

Android Developers Blogで紹介されているioschedアプリの機能を一部実装する.
Blog: http://android-developers.blogspot.jp/2014/08/material-design-in-2014-google-io-app.html

実現したい機能のイメージは次の通り. スクロールに追従し, 一定のY座標に到達すると画面上部との隙間を埋める(GapFill)ヘッダバーを実装する.
Imagery Header

First Releaseのデザインではスクロール量によってバナーエリアのα値が変化する. Android Developers Blogの著者はこれについて次のコメントを残している.

Our concern was that this design bent the physics of material design too far. It’s as if the text was sliding along a piece of paper whose transparency changed throughout the animation.

Material Designの重要なファクタである paper と ink の観点から, バナーエリアに描画されたテキストを残す形で透過アニメーションされる点が, Material Designの物理学から外れていると感じたようだ.
これを改善したのがUpdate version. Material Designのpaper と inkの物理学をより推進した形だ. 画像ではわかり辛いが, ヘッダバーエリアの下にコンテンツ詳細が潜り込むため, Z軸の存在を考慮してshadow効果も適用されている.

レイアウト構造は次のようになっている.
Layout structore

実装を始める前に, 今回参考とさせて頂いたサイト, およびリポジトリを紹介する.

また, 今回作成したコードは次のリポジトリで公開している.

ImageryHeaderFragment

Material Designではページのヘッダや背景等にイメージを配置し, コンテキストを表現することを推奨している. 今回作成するImageryHeaderFragmentはこれに倣って画像を配置できる機能を継承する(画像を必ず表示する必要はない). FABについては本コンポーネントの責務から外れるため実装されない. また, “L Preview”のAPIは本Fragmentでは使用しない.

Step by step

実装の手順を紹介する.

  1. Theme, Colorリソースを準備
  2. ImageryHeaderFragmentに必要なView拡張クラスを実装
  3. Layoutリソースを準備
  4. ImageryHeaderFragmentを実装

Step 1: Theme

ImageryHeaderFragment, ActionBarとActivityのためのThemeリソースを定義する.

  • /res/values/colors.xml
<resources>
<colorname="window_background">#eeeeee</color>

<!-- API v21移行はandroid:colorPrimaryの値に使用 -->
<colorname="colorPrimary">#a00</color>
</resources>
  • /res/values/styles.xml
<!-- ImageryHeader Theme -->
<stylename="Theme.ImageryHeader"parent="android:Theme.Holo.Light.DarkActionBar">
<itemname="android:actionBarStyle">@style/Theme.ImageryHeader.ActionBar</item>
<item name="android:windowBackground">@color/window_background</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowActionBarOverlay">true</item>
</style>

<!-- ImageryHeader Theme Action Bar -->
<stylename="Theme.ImageryHeader.ActionBar"parent="android:Widget.Holo.ActionBar">
<itemname="android:displayOptions">showHome</item>
<itemname="android:background">@null</item>
</style>
  • /AndroidManifest.xml
<activity
android:name=".MainActivity"
android:theme="@style/Theme.ImageryHeader">

ActionBarはApp iconとAction itemのために使用するため消すことはしない. かわりに背景を透過し, 不要な要素(shadowやApp title)を非表示にしておく.

Step 2: Custom View

ObservableScrollView

ImageryHeaderFragmentでは, 各Viewのポジションをスクロール量によって動的に変化させる. 実現するにはScrollViewのスクロールイベントのリスナーが必要であるが, Android純正のScrollViewにはコールバックリスナを受け付ける仕組みがない. これを実現するためにScrollViewを拡張したObservableScrollViewを実装する.

publicclassObservableScrollViewextendsScrollView {
private ArrayList<Callbacks> mCallbacks = new ArrayList<Callbacks>();

publicObservableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
protectedvoidonScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
for (Callbacks c : mCallbacks) {
c.onScrollChanged(l - oldl, t - oldt);
}
}

@Override
publicintcomputeVerticalScrollRange() {
returnsuper.computeVerticalScrollRange();
}

publicvoidaddCallbacks(Callbacks listener) {
if (!mCallbacks.contains(listener)) {
mCallbacks.add(listener);
}
}

publicstaticinterfaceCallbacks {
publicvoidonScrollChanged(int deltaX, int deltaY);
}
}

Original source code:
GitHub - ObservableScrollView

Step 3: Layout

リソースとカスタムViewの準備ができたらlayoutリソースを作成する. 画面構成は大きく3つの要素から成る.

  • Header Image
  • Body
  • Header Bar

3つの要素はレイアウト上, (FragmentLayoutによって)重なるように定義される. 実際には画面のスクロールポジションに従って各ViewのY座標を動的に変えていく.
Header Barの定義位置を最後にしてあるのはz-indexを手前にするためである.

  • /res/layout/fragment_imageryheader.xml
<yuki312.android.imageryheaderfragment.ObservableScrollView
android:id="@+id/scroll_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:overScrollMode="never">


<FrameLayout
android:id="@+id/scroll_view_child"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false">


<!-- Header Imagery -->
<FrameLayout
android:id="@+id/header_image_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">


<ImageView
android:id="@+id/header_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>

</FrameLayout>

<!-- Body -->
<LinearLayout
android:id="@+id/body_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/window_background"
android:clipToPadding="false"
android:orientation="vertical">


<!-- TODO: Dummy View for scroll. remove this view.-->
<TextView
android:layout_width="match_parent"
android:layout_height="777dp"
android:text="I`m Dummy"
/>

</LinearLayout>

<!-- Header bar -->
<FrameLayout
android:id="@+id/header_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false">


<!-- background -->
<!-- height assigned dynamically, and fill the ActionBar gaps. -->
<View
android:id="@+id/header_bar_background"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/colorPrimary"/>


<!-- contents -->
<LinearLayout
android:id="@+id/header_bar_contents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingTop="16dp">


<TextView
android:id="@+id/header_bar_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Placeholder"/>


</LinearLayout>

<!-- shadow -->
<View
android:id="@+id/header_bar_shadow"
android:layout_width="match_parent"
android:layout_height="6dp"
android:layout_gravity="bottom"
android:layout_marginBottom="-6dp"
android:background="@drawable/bottom_shadow"/>


</FrameLayout>
</FrameLayout>
</yuki312.android.imageryheaderfragment.ObservableScrollView>

@id/header_image_container

ヘッダイメージ画像のコンテナ. ioschedアプリではここにscrim効果を付与するアトリビュートも指定している. scrim効果を実装したい場合は次を追加し, scrim画像を用意する.

<FrameLayout
android:id="@+id/header_image_container"
...
android:foreground="@drawable/photo_banner_scrim">
  • /res/drawable/photo_banner_scrim
<shapexmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="270"
android:centerColor="#0000"
android:centerY="0.3"
android:endColor="#0000"
android:startColor="#3000"/>

</shape>

Original source code:
GitHub - photo_banner_scrim.xml

@id/header_bar_background

今回のメインViewとなるHeaderBar. 一定量スクロールされるとGapFillアニメーションする. このViewはActionBarが担っていたブランディングカラーのためにcolorPrimaryを指定する.

@id/header_bar_shadow

一定量スクロールされるとHeaderBarに影を落とす効果を付与する. これはMaterial Designの物理学に従いBodyよりもHeaderBarのpaper要素が手前(Z depth)にあることを表現している.

android:clipChildren

このアトリビュートは, 子Viewの描画領域が自領域外であっても実行するものである. これはヘッダ
バーの画面上部へのGapFillアニメーションやshadow効果の描画に必要になる. このアトリビュートを使えば親Viewのサイズに影響することなくshadow等の効果が実現できる.
これはGoogleI/O 2014でも紹介(15:00~)されている(http://youtu.be/lSH9aKXjgt8). ただしhorrible hackの類いである点に留意する.
Android Lから導入されるlight sourceとshadowのサポートはこれらの問題を解決(構築されたView階層に対してZ軸を考慮した物理的にも正しいshadow効果を描画)する.

Fragment

準備は整った. 各ViewはFramelayoutの効果で全て0座標に位置している. 今の状態でアプリ実行すると次のレイアウトになる.

Layout define only

ここからはImageryHeaderFragmentのソースコードで各Viewの配置を調整していく.

publicclassImageryHeaderFragmentextendsFragment
implementsObservableScrollView.Callbacks {

...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
... findViewByID ...
setupCustomScrolling(rootView);
return rootView;
}

privatevoidsetupCustomScrolling(View rootView) {
scrollView = (ObservableScrollView) rootView.findViewById(R.id.scroll_view);
scrollView.addCallbacks(this);
...
}

まずはスクロールイベントを検知するために, ObservableScrollView.Callbacksをimplementsする. Fragment.onCreateView()でObservableScrollViewへコールバック登録.

private ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener
= new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
publicvoidonGlobalLayout() {
recomputeHeaderImageAndScrollingMetrics();
}
};

privatevoidsetupCustomScrolling(View rootView) {
...
ViewTreeObserver vto = scrollView.getViewTreeObserver();
if (vto.isAlive()) {
vto.addOnGlobalLayoutListener(globalLayoutListener);
}
}

privatevoidrecomputeHeaderImageAndScrollingMetrics() {
finalint actionBarSize = calculateActionBarSize();
headerBarTopClearance = actionBarSize - headerBarContents.getPaddingTop();
headerBarContentsHeightPixels = headerBarContents.getHeight();

headerImageHeightPixels = headerBarTopClearance;
if (showHeaderImage) {
headerImageHeightPixels =
(int) (headerImage.getWidth() / HEADER_IMAGE_ASPECT_RATIO);
headerImageHeightPixels = Math.min(headerImageHeightPixels,
rootView.getHeight() * 2 / 3);
}

ViewGroup.LayoutParams lp;
lp = headerImageContainer.getLayoutParams();
if (lp.height != headerImageHeightPixels) {
lp.height = headerImageHeightPixels;
headerImageContainer.setLayoutParams(lp);
}

lp = headerBarBackground.getLayoutParams();
if (lp.height != headerBarContentsHeightPixels) {
lp.height = headerBarContentsHeightPixels;
headerBarBackground.setLayoutParams(lp);
}

ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)
bodyContainer.getLayoutParams();
if (mlp.topMargin
!= headerBarContentsHeightPixels + headerImageHeightPixels) {
mlp.topMargin = headerBarContentsHeightPixels + headerImageHeightPixels;
bodyContainer.setLayoutParams(mlp);
}

onScrollChanged(0, 0); // trigger scroll handling
}

ObservableScrollViewからViewTreeObserverを取得してGlobalLayoutListenerを登録. ObservableScrollViewのレイアウト構築完了を待つ. レイアウト構築が完了したらheaderImageContainer, bodyContainer, headerBarBackgroundのレイアウトを調整する.

headerBarTopClearance
recomputeHeaderImageAndScrollingMetrics()では, headerBarTopClearance値を設定する. この値はHeaderBarと画面上部まで(あるいはActionBar部の)隙間間隔を表す.
コード上ではActionBarの高さからheaderBarContents.getPaddingTop()つまりHeaderBar領域の上部余白を除いた値を設定することで, HeaderBarのコンテンツ(“Placeholder”)部とActionBarの隙間を小さくしている.

次にImageryHeaderFragmentのコアとなる処理を見る.

// GapFillアニメ開始位置の調整. 開始位置に"遊び"を持たせる.
privatestaticfinalfloat GAP_FILL_DISTANCE_MULTIPLIER = 1.5f;

// ヘッダ画像スクロール時のパララックスエフェクト係数
privatestaticfinalfloat HEADER_IMAGE_BACKGROUND_PARALLAX_EFFECT_MULTIPLIER
= 0.5f;

@Override
publicvoidonScrollChanged(int deltaX, int deltaY) {
final Activity activity = getActivity();
if (activity == null || activity.isFinishing()) {
return;
}

// Reposition the header bar -- it's normally anchored to the
// top of the content, but locks to the top of the screen on scroll
int scrollY = scrollView.getScrollY();

float newTop = Math.max(headerImageHeightPixels,
scrollY + headerBarTopClearance);
headerBarContainer.setTranslationY(newTop);
headerBarBackground.setPivotY(headerBarContentsHeightPixels);

int gapFillDistance =
(int) (headerBarTopClearance * GAP_FILL_DISTANCE_MULTIPLIER);
boolean showGapFill = !showHeaderImage ||
(scrollY > (headerImageHeightPixels - gapFillDistance));
float desiredHeaderScaleY = showGapFill ?
((headerBarContentsHeightPixels + gapFillDistance + 1) * 1f
/ headerBarContentsHeightPixels)
: 1f;
if (!showHeaderImage) {
headerBarBackground.setScaleY(desiredHeaderScaleY);
} elseif (gapFillShown != showGapFill) {
headerBarBackground.animate()
.scaleY(desiredHeaderScaleY)
.setInterpolator(new DecelerateInterpolator(2f))
.setDuration(250)
.start();
}
gapFillShown = showGapFill;

// Make a shadow. TODO: Do not need if running on AndroidL
headerBarShadow.setVisibility(View.VISIBLE);

if (headerBarTopClearance != 0) {
// Fill the gap between status bar and header bar with color
float gapFillProgress = Math.min(Math.max(getProgress(scrollY,
headerImageHeightPixels - headerBarTopClearance * 2,
headerImageHeightPixels - headerBarTopClearance), 0), 1);
// TODO: Set elevation properties if running on AndroidL
headerBarShadow.setAlpha(gapFillProgress);
}

// Move background image (parallax effect)
headerImageContainer.setTranslationY(scrollY *
HEADER_IMAGE_BACKGROUND_PARALLAX_EFFECT_MULTIPLIER);
}

onScrollChanged

newTop
HeaderBarの位置を調整する. headerImageHeightPixelsとHeaderBarの隙間(headerBarTopClearance)を考慮したスクロール量(scrollY)とのmaxをとるので, HeaderImageよりもHeaderBarが下に位置することはない.
GAP_FILL_DISTANCE_MULTIPLIER
HeaderBarと画面上部の隙間を埋めるGapFillアニメーションの開始位置に係る定数. ただし, GapFillアニメーション後もHeaderBarはheaderBarTopClearance(隙間間隔)の値に到達するまで移動する点に注意.
画面スクロールのY座標が, headerBarTopClearanceと本係数との乗を超えたときにGapFillアニメーションを開始する. GapFillアニメーションの開始を早めたい場合は本係数を変更する.
gapFillDistance
前述のGAP_FILL_DISTANCE_MULTIPLIERに関係する.

ここではAndroidLが正式リリースされた際の対応をTODOコメントとして残しておく(実際にはAndroidL前後で動作を変えるラッパを用意しておくのが望ましいが, 本件の主旨ではないので割愛.

Run & improvement

これで, MaterialDesignの物理学に従った対応ができた. ここまでの実装でアプリを動作させた場合のレイアウトが下記:

enter image description here

実際に動作させてアニメーションやshadowの具合を確認してみてほしい.
Material Designは他にもTypography(Roboto, Font size/style), Bold(color, FAB), Layout baselineといった項目があり, これだけではMaterial Designに則ったデザインであるとは到底言えないが, 本稿の目的は達成したのでこれ以上は実装しない. 必要であれば残るMaterial Designの要素を実装していく必要がある.

以上.


Copyright 2014 yuki312 All Right Reserved.

Licensed under the Apache License, Version 2.0 (the “License”);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


License
Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

Android:知っておきたい標準API part.1

$
0
0

Intro

Android標準APIの中で知っておくと便利なものがいくつかある.
3rdParty製ライブラリを使うのもいいけれど, 標準で事足りるならそうしたい.
紹介するAPIについてはSupportLibraryを含んでおり, Javaパッケージは対象外.

Useful

LocalBroadcastManager

android.support.v4.content.LocalBroadcastManager
URL: http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html

Helper to register for and send broadcasts of Intents to local objects within your process. This is has a number of advantages over sending global broadcasts with sendBroadcast(Intent):

  • You know that the data you are broadcasting won’t leave your app, so don’t need to worry about leaking private data.
  • It is not possible for other applications to send these broadcasts to your app, so you don’t need to worry about having security holes they can exploit.
  • It is more efficient than sending a global broadcast through the system.

自プロセス内に閉じた, ローカルなBroadcastIntentを投げたい場合に使える. LocalBroadcastManagerを使うことの利点は次の通り.

  • 自プロセスに閉じたBroadcastIntentなのでPrivateデータを送信しても安心
  • 他のアプリケーションがBroadcastIntentを偽ることができないのでエクスプロイト対策にもなる
  • SystemにBroadcastIntentを投げさせるよりも効率的である

StickyなBroadcastIntentが投げられない等, いくつかの制約はある.
(LocalBroadcastManager自体のコードは極めてシンプルなので自分で拡張したほうが早いかも)

Usage

// Receiver登録
LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
new IntentFilter("custom-action-name"));

// Receiver解除
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);

// LocalBroadcast送信
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

LruCache

android.support.v4.util.LruCache<K, V>
URL: http://developer.android.com/reference/android/support/v4/util/LruCache.html

Static library version of LruCache. Used to write apps that run on API levels prior to 12. When running on API level 12 or above, this implementation is still used; it does not try to switch to the framework’s implementation. See the framework SDK documentation for a class overview.

LruCache本体がAPI Level12から追加された. API Level12より過去のバージョンでLruCacheを使用したい場合にこのAPIを使用する. 本クラスを使用する場合, API Level12以降でもこちらが参照される(FWでスイッチされるというようなことはない)

Usage

TechBoosterで詳しく紹介されています. TechBooster - LruCacheを使ってメモリキャッシュを実装する

メモリを圧迫しやすいBlobなデータをいい感じ(Least Recently Used)に管理してくれる.
参照されなくなったデータからメモリ解放したい場合に適している.

TimingLogger

android.util.TimingLogger
Added in API level 1
URL: http://developer.android.com/reference/android/util/TimingLogger.html

A utility class to help log timings splits throughout a method call. Typical usage is:

A区間からB区間までのタイミング(処理時間)を計測するのを支援するクラス.

TimingLogger timings = new TimingLogger(TAG, "methodA");
// ... do some work A ...
timings.addSplit("work A");
// ... do some work B ...
timings.addSplit("work B");
// ... do some work C ...
timings.addSplit("work C");
timings.dumpToLog();

The dumpToLog call would add the following to the log:

このコードを実行すると次のようなログを吐く.

D/TAG     ( 3459): methodA: begin     
D/TAG ( 3459): methodA: 9 ms, work A
D/TAG ( 3459): methodA: 1 ms, work B
D/TAG ( 3459): methodA: 6 ms, work C
D/TAG ( 3459): methodA: end, 16 ms

参考:Android:TimingLoggerで処理間隔をログ出力する

AtomicFile

android.support.v4.util.AtomicFile
URL: http://developer.android.com/reference/android/support/v4/util/AtomicFile.html

Static library support version of the framework’s AtomicFile, a helper class for performing atomic operations on a file by creating a backup file until a write has successfully completed.

ファイル書き込み前にバックアップファイルを作成し, 書き込みに失敗した場合はロールバックすることで, ファイル操作をアトミックなものにするヘルパクラス.

Atomic file guarantees file integrity by ensuring that a file has been completely written and sync’d to disk before removing its backup. As long as the backup file exists, the original file is considered to be invalid (left over from a previous attempt to write the file).

AtomicFileは整合性を保証するためにファイルの書き込みが完了し, ディスクと同期するまでバックアップファイルを削除しない. バックアップファイルが残っている限り, オリジナルファイルは無効と判断する(前回のファイル書き込み処理から残っている状態)

  • オリジナルファイル名:作業対象ファイル
  • バックアップファイル名:オリジナルのバックアップ(オリジナルファイル名 + “.bak”で管理)

Atomic file does not confer any file locking semantics. Do not use this class when the file may be accessed or modified concurrently by multiple threads or processes. The caller is responsible for ensuring appropriate mutual exclusion invariants whenever it accesses the file.

AtomicFileは単純なR/Wを想定している. ロックセマンティクスを提供していないため, マルチにアクセスされる可能性がある場合は自前でアクセス制御すること. また, AtomicFileによる操作中に(バックアップファイルも含めて)割り込まないように注意すること.

Usage

AtomicFile f = new AtomicFile(new File(...));
FileOutputStream o = null;
try {
o = file.startWrite(); // バックアップファイル作成
// TODO: ファイル出力処理
f.finishWrite(o); // コミット
} catch (IOException e) {
f.failWrite(o); // ロールバック
}

IntentService

android.app.IntentService
Added in API level 3
URL: http://developer.android.com/reference/android/app/IntentService.html

IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.

IntentServiceはIntentによるリクエストを要求に応じて非同期処理するServiceクラス. クライアントはstartService(Intent)でリクエストを投げる. IntentServiceはworker threadでこれを受けて, 処理が全て完了すると自身で停止する.

This “work queue processor” pattern is commonly used to offload tasks from an application’s main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.

work queue processorパターンはアプリケーションのメインスレッドからタスクをオフロードするために使用されるが, これを簡略化したのがIntentServiceである. IntentServiceを使用する場合はonHandleIntent(Intent)を実装する.

All requests are handled on a single worker thread – they may take as long as necessary (and will not block the application’s main loop), but only one request will be processed at a time.

全てのリクエストは single worker threadで処理される. 処理には時間がかかるかもしれない(が, アプリケーションのメインスレッドはブロックされない), しかしリクエストは1つずつ処理される.

Developer Guides
For a detailed discussion about how to create services, read the Services developer guide.

publicclassMyIntentServiceextendsIntentService{
publicMyIntentService(){
super("MyIntentService"); // 文字列はworker threadの名前に使われる
}

@Override
protectedvoidonHandleIntent(Intent intent) {
Log.d(TAG, "Intentの処理内容を記載");
}
}

Messenger

android.os.Messenger
Added in API level 1
URL: http://developer.android.com/reference/android/os/Messenger.html

プロセス間の双方向通信をサポートするService形態にはAIDLとMessengerが存在する.
AIDLとMessengerの主な違いは下記.

AIDL

  • サービスホスト(以降ホスト)は.aidlを作成し, サービスクライアント(以降クライアント)はこれを取り込む必要がある.
  • クライアントからのリクエストはBinderThread経由で, 全てのリクエストが非同期通信となる.
  • ホストは必要に応じてクライアントからのリクエストをスレッドセーフに扱う必要がある.
  • .aidlに変更があった場合, クライアントも合わせてこれを更新する必要がある.

Messenger

  • ホストとクライアント間の通信はHandler-Messageの仕組みで実現されているため.aidlが不要.
  • クライアントからのリクエストはHandler経由で通知され, 全てのリクエストが同期通信となる.
  • ホストとクライアント間のメッセージはMessageオブジェクトで表現される.

Messengerはクライアントからのリクエストをシングルスレッドで処理するため, 基本的にスレッドセーフで動作する. また通信メッセージがMessageオブジェクトで表現されるため.aidlファイルも不要.
外部公開APIに変更があっても, .aidlファイルをクライアントに配布する必要がないため, Service側でMessageの規約(プロトコル)を更新するだけで済む(互換性に注意)

AIDLでは外部公開APIはメソッドとして定義されるが, Messengerでは”Messageオブジェクトの組み立て方”でこれを表現する必要がある.
クライアントはMessengerと通信するためにメッセージの組み立て方を理解する必要がある. (アプリローカルで使用されるHandler-Messageのそれと同じ)

参考: Android:Messengerの基本

// クライアントサイド
publicclassMessengerClientextendsActivity {
private Messenger mServiceMessenger;
private Messenger mSelfMessenger;

@Override
protectedvoidonCreate(Bundle savedInstanceState) {
mSelfMessenger = new Messenger(new ResponseHandler());
mConnection = new ServiceConnection() {
@Override
publicvoidonServiceConnected(ComponentName name, IBinder service) {
mServiceMessenger = new Messenger(service);
}
};
bindService(new Intent("yuki.test.messenger.START"),
mConnection, Service.BIND_AUTO_CREATE);

((Button)findViewById(R.id.button1)).setOnClickListener(
new View.OnClickListener() {
@Override
publicvoidonClick(View v) {
if (mServiceMessenger != null) {
try {
Message msg = Message.obtain(null, 1);
msg.replyTo = mSelfMessenger;
mServiceMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}

privateclassResponseHandlerextendsHandler {
@Override
publicvoidhandleMessage(Message msg) {
Log.e("yuki", "handle response=" + msg);
}
}
}

// ホストサイド
publicclassMessengerServiceextendsService {
private Messenger mServiceMessenger;

@Override
publicvoidonCreate() {
super.onCreate();
mServiceMessenger = new Messenger(new RequestHandler());
}

@Override
public IBinder onBind(Intent intent) {
return mServiceMessenger.getBinder();
}

privateclassRequestHandlerextendsHandler {
@Override
publicvoidhandleMessage(Message msg) {
Log.e("yuki", "handle request=" + msg);

if (msg.replyTo != null) {
try {
msg.replyTo.send(Message.obtain()); // send response.
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
}

DatabaseUtils

android.database.DatabaseUtils
Added in API level 1
URL: http://developer.android.com/reference/android/database/DatabaseUtils.html

データベースとCursorに関するユーティリティメソッドを提供する.

DatabaseUtils.dumpCursor

Cursorの内容をダンプするユーティリティ. dumpCursor後にCursorのpositionは変化しない.

Cursor c = this.getContentResolver().query(
Browser.BOOKMARKS_URI, new String[]{"_id", "title"},
null, null, null);
DatabaseUtils.dumpCursor(c);
結果:
I/System.out(2944): >>>>> Dumping cursor
I/System.out(2944): 0 {
I/System.out(2944): _id=1dumpCurrentRow (Cursor cursor)
I/System.out(2944): title=Bookmarks
I/System.out(2944): }
I/System.out(2944): 1 {
I/System.out(2944): _id=2
I/System.out(2944): title=Android Developers
I/System.out(2944): }
I/System.out(2944): 2 {
I/System.out(2944): _id=3
I/System.out(2944): title=Google
I/System.out(2944): }
I/System.out(2944): <<<<<

DatabaseUtils.concatenateWhere

WHERE句を構築するユーティリティ. 半角スペースや括弧の実装負担を減らせる.

DatabaseUtils.concatenateWhere("criteria1", "criteria2");
結果:
(criteria1) AND (criteria2)

引数1と2は, それぞれ括弧で囲まれた上でAND条件結合される. 片方がnullあるいは空白である場合はもう片方の引数がそのまま返却される.

DatabaseUtils.queryNumEntries

指定されたテーブルに含まれる行数を調べる.

DatabaseUtils.queryNumEntries(db, "test");
結果:
4 // testテーブルには4レコード存在しているとする

内部ではSELECT count(*)でカラムをカウントしている.

DatabaseUtils.sqlEscapeString

手動でクエリを構築する際にはエスケープ処理に注意する必要がある.
指定される文字列のエスケープ処理にはsqlEscapeStringメソッドが便利.

DatabaseUtils.sqlEscapeString("'");
結果:
''''

指定される文字列中にシングルクォートがあるとこれをエスケープする. エスケープ文字列はシングルクォートで囲まれる.

DatabaseUtils.getSqlStatementType

getSqlStatementTypeはSQL文字列のステートメント種別を返却する. 返却される種別は次の定数で定義されている.

  • STATEMENT_SELECT
  • STATEMENT_UPDATE
  • STATEMENT_ATTACH
  • STATEMENT_BEGIN
  • STATEMENT_COMMIT
  • STATEMENT_ABORT
  • STATEMENT_PRAGMA
  • STATEMENT_DDL
  • STATEMENT_UNPREPARED
  • STATEMENT_OTHER
DatabaseUtils.getSqlStatementType("SELECT * FROM bookmarks;");
DatabaseUtils.getSqlStatementType("PRAGMA user_version;");
DatabaseUtils.getSqlStatementType(";");
DatabaseUtils.getSqlStatementType("INSERT SELECT;");
結果:
1(STATEMENT_SELECT)
7(STATEMENT_PRAGMA)
99(STATEMENT_OTHER)
2(STATEMENT_UPDATE)

4番目の結果を見るとわかるように厳密な解析結果ではない. 単純な解析(頭3文字で判定)しかしてくれないので注意.

以上.

Android:知っておきたい標準API part.2

$
0
0

Intro

Android標準APIの中で知っておくと便利なものがいくつかある.
3rdParty製ライブラリを使うのもいいけれど, 標準で事足りるならそうしたい.
紹介するAPIについてはSupportLibraryを含んでおり, Javaパッケージは対象外.

Data structure

Property

android.util.Property<T, V>
Added in API level 14
URL: http://developer.android.com/reference/android/util/Property.html

A property is an abstraction that can be used to represent a mutable value that is held in a host object. The Property’s set(Object, Object) or get(Object) methods can be implemented in terms of the private fields of the host object, or via “setter” and “getter” methods or by some other mechanism, as appropriate.

ホストオブジェクトが持つ変更可能な値を表現するのに使える抽象的なプロパティ.

Usage

publicabstractclassFloatProperty<T> extendsProperty<T, Float> {
publicFloatProperty(String name) {
super(Float.class, name);
}

/**
* A type-specific override of the {@link #set(Object, Float)} that is faster
* when dealing with fields of type <code>float</code>.
*/

publicabstractvoidsetValue(T object, float value);

@Override
finalpublicvoidset(T object, Float value) {
setValue(object, value);
}
}

publicstaticfinal Property<View, Float> X = new FloatProperty<View>("x") {
@Override
publicvoidsetValue(View object, float value) {
object.setX(value);
}

@Override
public Float get(View object) {
return object.getX();
}
};

CircularArray

android.support.v4.util.CircularArray<E>
URL: http://developer.android.com/reference/android/support/v4/util/CircularArray.html

A circular array implementation that provides O(1) random read and O(1) prepend and O(1) append

リングバッファ. O(1).

TypedValue

android.util.TypedValue
Added in API level 1
URL: http://developer.android.com/reference/android/util/TypedValue.html

Container for a dynamically typed data value. Primarily used with Resources for holding resource values.

動的型付けされたデータコンテナ. 主にリソース値を保持するために使用される.

Usage

// テーマの背景色取得
TypedValue t= new TypedValue();
getTheme().resolveAttribute(android.R.attr.colorBackground, t, true);
int id= typedValue.resourceId;
int color= getResources().getColor(id);

// dp⇒px換算
int padding = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics());

Pair

android.util.Pair<F, S>
Added in API level 5
URL: http://developer.android.com/reference/android/util/Pair.html

Container to ease passing around a tuple of two objects. This object provides a sensible implementation of equals(), returning true if equals() is true on each of the contained objects.

“組”を表現するクラス. 格納する型は自由. オブジェクトをペアで管理したい場合に便利. Pair.equals()は”組”となっている双方のオブジェクトと等価である場合にtrueを返す.

Usage

Pair<String, String> pair = Pair.create("android3.0", "Honeycomb");
Log.d(TAG, pair.first); // android3.0
Log.d(TAG, pair.second); // Honeycomb

SparseArray

android.util.SparseArray<E>
Added in API level 1
URL: http://developer.android.com/reference/android/util/SparseArray.html

SparseArrays map integers to Objects. Unlike a normal array of Objects, there can be gaps in the indices. It is intended to be more memory efficient than using a HashMap to map Integers to Objects, both because it avoids auto-boxing keys and its data structure doesn’t rely on an extra entry object for each mapping.

スパースアレイ. SparseArrayはintをキーにしたマップオブジェクト. 通常の配列とは異なりインデックスに”隙間”を許容する. SparseArrayはHashMapよりも効率が良い.

Note that this container keeps its mappings in an array data structure, using a binary search to find keys. The implementation is not intended to be appropriate for data structures that may contain large numbers of items. It is generally slower than a traditional HashMap, since lookups require a binary search and adds and removes require inserting and deleting entries in the array. For containers holding up to hundreds of items, the performance difference is not significant, less than 50%.

SparseArrayはキーのルックアップにバイナリサーチを使用するため膨大なデータに対してのパフォーマンスはHashMapに劣る. エントリ数が100程であればパフォーマンス差は50%以下に収まる.

To help with performance, the container includes an optimization when removing keys: instead of compacting its array immediately, it leaves the removed entry marked as deleted. The entry can then be re-used for the same key, or compacted later in a single garbage collection step of all removed entries. This garbage collection will need to be performed at any time the array needs to be grown or the the map size or entry values are retrieved.

コンテナはキーの削除に最適化されている. エントリが削除された場合, すぐに配列をコンパクションするのではなく, 削除マーキングのみを行う. 削除マーカーのついたエントリは再利用されるかGCのタイミングで一括削除される. このGCはArrayのサイズ拡張やサイズ取得の際に実行される.

It is possible to iterate over the items in this container using keyAt(int) and valueAt(int). Iterating over the keys using keyAt(int) with ascending values of the index will return the keys in ascending order, or the values corresponding to the keys in ascending order in the case of valueAt(int).

ketAt(int)やvalueAt(int)を使えば, 配列内をイテレートできる.

Mapインターフェイスの利用を決める前にSparseArrayの利用を検討する.
SparseArrayのキーはint型に限定されており, SparseArrayはint型のキーを持つMap<Integer, Object>と置換可能.
Mapインターフェイスと比べ, SparseArrayは汎用性を犠牲にする代わりに高いパフォーマンスを実現している.
Map

Usage

SparseArray<String> sparseArray = new SparseArray<String>();
sparseArray.put(1, "value");
String str = sparseArray.get(1);

ArrayDeque

java.util.ArrayDeque<E>
Added in API level 9
URL: http://developer.android.com/reference/java/util/ArrayDeque.html

Resizable-array implementation of the Deque interface. Array deques have no capacity restrictions; they grow as necessary to support usage. They are not thread-safe; in the absence of external synchronization, they do not support concurrent access by multiple threads. Null elements are prohibited. This class is likely to be faster than Stack when used as a stack, and faster than LinkedList when used as a queue.

容量制限のない, 非スレッドセーフな, nullを許可しない, リサイズ可能なDeque実装. よくある”使う分だけキャパシティが増える”部類のArray. StackやLinkedListよりも高速に動作する.

Most ArrayDeque operations run in amortized constant time. Exceptions include remove, removeFirstOccurrence, removeLastOccurrence, contains, iterator.remove(), and the bulk operations, all of which run in linear time.

ArrayDequeへの操作は”ならし定数時間(amortized constant time)”で処理される.
remove, removeFirstOccurrence, removeLastOccurrence, contains, iterator.remove(), やbulkオペレーションは線形時間で処理される.

The iterators returned by this class’s iterator method are fail-fast: If the deque is modified at any time after the iterator is created, in any way except through the iterator’s own remove method, the iterator will generally throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

このクラスから得られるiteratorのメソッドはfail-fastに動作する. iterator取得後にdequeが変更されたり, iteratorのremoveメソッドを呼んだりするとConcurrentModificationExceptionを投げる. 並列で同時変更されたような場合にも即座にイテレート処理が失敗する.

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

ただし, 一般的に言われているものと同じく, 非同期への確実な保証は無く, fail-fastによるConcurrentModificationExceptionスローはベストエフォートで行われることに注意.

This class and its iterator implement all of the optional methods of the Collection and Iterator interfaces.

このクラスとiteratorは, CollectionおよびIteratorインタフェースのメソッドを実装している.

Pools

android.support.v4.util.Pools
URL: https://developer.android.com/reference/android/support/v4/util/Pools.html

Pools.SimplePool
非スレッドセーフなオブジェクトプール.
Pools.SynchronizedPool
スレッドセーフなオブジェクトプール.
publicclassMyPooledClass {
privatestaticfinal SynchronizedPool sPool =
new SynchronizedPool(10);

publicstatic MyPooledClass obtain() {
MyPooledClass instance = sPool.acquire();
return (instance != null) ? instance : new MyPooledClass();
}

publicvoidrecycle() {
// Clear state if needed.
sPool.release(this);
}
. . .
}

Processor

Linkify

android.text.util.Linkify
Added in API level 1
URL: http://developer.android.com/reference/android/text/util/Linkify.html

Linkify take a piece of text and a regular expression and turns all of the regex matches in the text into clickable links. This is particularly useful for matching things like email addresses, web urls, etc. and making them actionable. Alone with the pattern that is to be matched, a url scheme prefix is also required. Any pattern match that does not begin with the supplied scheme will have the scheme prepended to the matched text when the clickable url is created. For instance, if you are matching web urls you would supply the scheme http://. If the pattern matches example.com, which does not have a url scheme prefix, the supplied scheme will be prepended to create http://example.com when the clickable url link is created.

文字列と正規表現を受け取り, 正規表現にマッチするテキストをリンカブルテキストに置き換える. 一般的にはeメールアドレスやWebアドレスなどに対して使用される. パターンはURLスキームの接頭語にマッチする必要がある. もしスキームを持たずにマッチさせた場合, リンカブルテキストを生成する際に付与させる必要がある. 例えばWebアドレスにマッチさせたい場合はhttp://を指定する. example.comをパターンマッチさせた場合は, リンカブルテキストを作成する際にhttp://example.comとなるようにhttp://を頭に付与する.

Linkify.TransformFilter

android.text.util.Linkify.TransformFilter
Added in API level 1
URL: http://developer.android.com/reference/android/text/util/Linkify.TransformFilter.html

TransformFilter enables client code to have more control over how matched patterns are represented as URLs. For example: when converting a phone number such as (919) 555-1212 into a tel: URL the parentheses, white space, and hyphen need to be removed to produce tel:9195551212.

TransformFilterを使用すると, 特定のパターンにマッチした文字列のURL表現をコントロールできる.
例えば, (919) 555-1212にマッチした文字列に対してスペースなど余分なものを削除してtel:9195551212とすることができる. Linkifyはtechboosterに詳しくある http://techbooster.org/android/ui/13512/

Rfc822Tokenizer

android.text.util.Rfc822Tokenizer
Added in API level 1
URL: http://developer.android.com/reference/android/text/util/Rfc822Tokenizer.html

This class works as a Tokenizer for MultiAutoCompleteTextView for address list fields, and also provides a method for converting a string of addresses (such as might be typed into such a field) into a series of Rfc822Tokens.

このクラスは, アドレスリストフィールドのMultiAutoCompleteTextView用のTokenizerとして機能する. また(フィールドに入力されるような)アドレス文字列を一連のRfc822Tokenに変換するメソッドを提供する.

Rfc822Token

android.text.util.Rfc822Token
Added in API level 1
URL: http://developer.android.com/reference/android/text/util/Rfc822Token.html

This class stores an RFC 822-like name, address, and comment, and provides methods to convert them to quoted strings.

Rfc822TokenにはRFC822-likeのname, address, commentが格納され, これらをquoted stringに変換するメソッドも提供する.

Rfc822Token[] tokens 
= Rfc822Tokenizer.tokenize("Foo Bar (something) <foo@google.com>");
assertNotNull(tokens);
assertEquals(1,tokens.length);
assertEquals("foo@google.com",tokens[0].getAddress());
assertEquals("Foo Bar",tokens[0].getName());
assertEquals("something",tokens[0].getComment());

Patterns

android.util.Patterns
Added in API level 8
URL: http://developer.android.com/reference/android/util/Patterns.html

Commonly used regular expression patterns.

よく使われるいくつかの正規表現Patternが定義されている(IANA top-level domains, Phone number(looks like.), web url etc…).

Usage

m = Patterns.EMAIL_ADDRESS.matcher(str).matches();
assertTrue("メールアドレスチェック", m);

m= Patterns.TOP_LEVEL_DOMAIN.matcher("com").matches();
assertTrue("トップレベルドメインチェック", m);

m = Patterns.WEB_URL.matcher("http://www.google.com").matches();
assertTrue("WebURLチェック", m);

m = Patterns.WEB_URL.matcher("ftp://www.example.com").matches();
assertFalse("不正なプロトコル", m);

m = Patterns.IP_ADDRESS.matcher("1234.5678.9.0").matches();
assertFalse("不正なIP", m);

m = Patterns.PHONE.matcher("(123) 456-7890").matches();
assertTrue("電番チェック", t);

Others

AndroidException

android.util.AndroidException
Added in API level 1
URL: http://developer.android.com/reference/android/util/AndroidException.html

Base class for all checked exceptions thrown by the Android frameworks.

Android Frameworkが投げたことを意味する例外. AndroidExceptionを継承したサブクラスは次の通り.

IntentFilter.MalformedMimeTypeException
This exception is thrown when a given MIME type does not have a valid syntax.
IntentSender.SendIntentException
Exception thrown when trying to send through a PendingIntent that has been canceled or is otherwise no longer able to execute the request.
PackageManager.NameNotFoundException
This exception is thrown when a given package, application, or component name cannot be found.
PendingIntent.CanceledException
Exception thrown when trying to send through a PendingIntent that has been canceled or is otherwise no longer able to execute the request.
RemoteException
Parent exception for all Binder remote-invocation errors
Settings.SettingNotFoundException
-
DeadObjectException
The object you are calling has died, because its hosting process no longer exists.
TransactionTooLargeException
The Binder transaction failed because it was too large.

LogPrinter

android.util.LogPrinter
Added in API level 1
URL: http://developer.android.com/reference/android/util/LogPrinter.html

Implementation of a Printer that sends its output to the system log.

System logを出力するPrinterの実装. LogCat内部で使用されている.

EventLog

android.util.EventLog
Added in API level 8
URL: http://developer.android.com/reference/android/util/EventLog.html

Access to the system diagnostic event record. System diagnostic events are used to record certain system-level events (such as garbage collection, activity manager state, system watchdogs, and other low level activity), which may be automatically collected and analyzed during system development.

システム診断イベントレコードへのアクセスクラス. システム診断イベントにはシステムレベルのイベント(GC, ActivityManagerState, watchdog, 低次レイヤーイベントなど)が含まれている. このイベントは自動収集されてシステム開発に活かされる.

This is not the main “logcat” debugging log (Log)! These diagnostic events are for system integrators, not application authors.

これはLogcatのようなアプリのためのログシステムではない.

Events use integer tag codes corresponding to /system/etc/event-log-tags. They carry a payload of one or more int, long, or String values. The event-log-tags file defines the payload contents for each type code.

イベントには整数タグコードが使用され, /system/etc/event-log-tagsに対応している. ペイロードは1つ以上のint, long, Stringの値で構成され, event-log-tagsファイルには各タイプコードに対応するペイロードの内容が定義されている.

EventLogはadb logcatのeventsバッファから収集するか, DDMSのイベントログタブから参照できる.

IntentSender

android.content.IntentSender
Added in API level 4
URL: http://developer.android.com/reference/android/content/IntentSender.html

A description of an Intent and target action to perform with it. The returned object can be handed to other applications so that they can perform the action you described on your behalf at a later time.

Intentを実行するIntentSender. IntentSenderのオブジェクトを他アプリケーションに渡すことで, あなたのアプリケーションに変わって他アプリがIntentを後から実行できるようになる.

By giving a IntentSender to another application, you are granting it the right to perform the operation you have specified as if the other application was yourself (with the same permissions and identity). As such, you should be careful about how you build the IntentSender: often, for example, the base Intent you supply will have the component name explicitly set to one of your own components, to ensure it is ultimately sent there and nowhere else.

IntentSenderを他アプリケーションに渡すことはIntent実行に必要な権限やアイデンティティまで渡すことと同義である. よくある方法としては, 自身のコンポーネントを指定した明示的IntentをセットしたIntentSenderを渡して, Intentを受け取った自コンポーネントで想定されたSenderからのリクエストかをチェックする.

A IntentSender itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application’s process is killed, the IntentSender itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of IntentSender (same operation, same Intent action, data, categories, and components, and same flags), it will receive a IntentSender representing the same token if that is still valid.

IntentSender自体はSystemによって記述されるTokenを単純に参照するものである. つまり, IntentSenderを生成したプロセスがkillされてもなお有効であることを意味する. もしアプリ起動後に再度同じIntentSender(同じoperation, intent action, data, category, component, flag)を取得した場合, 有効であるなら同じtokenを受け取ることになる.

Instances of this class can not be made directly, but rather must be created from an existing PendingIntent with PendingIntent.getIntentSender().

このクラスは直接生成するのではなく, PendingIntent.getIntentSender()から取得すること.

CancellationSignal

android.os.CancellationSignal
Added in API level 16
URL: http://developer.android.com/reference/android/os/CancellationSignal.html

Provides the ability to cancel an operation in progress.

処理のキャンセル要求を表現するクラス. これをサポートしたクラスにシグナル送信することでキャンセル要求を発出できる. ContentProviderや, AsyncTaskLoaderがこれをサポートしている.

参考: Android:CancellationSignalで処理を中断する

// Client
try {
Cursor cursor = getContentResolver().query(
Uri.parse("content://yuki.mycontentprovider"),
new String[] { "_id" }, null, null, null, mCancelSignal);
} catch (OperationCanceledException ex) {
// do something.
}

// ContentProvider
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder,
CancellationSignal cancellationSignal) {
SQLiteDatabase db = mDataBaseHelper.getReadableDatabase();
Cursor c = db.query(false, "test", projection,
selection, selectionArgs, null, null, sortOrder, null,
cancellationSignal);
... 略 ...
}

以上.

Android:Nexus5 Android5.0 preview(LPX13D)のroot化手順

$
0
0

0. はじめに

Root化は次のリスクをご認識の上行ってください.
本稿が原因で発生するあらゆる損害に対しても責任は負いません.
全て自己責任でお願いします.

  • メーカ保証が受けられなくなる
  • 端末が起動しなくなる
  • データが全て消える

Root化にあたっては Nexus5 と Android5.0preview(LPX13D) で確認しています.
Nexus7ではありません.

1. 用意するもの

Android SDK Tools(adb, fastboot)
開発で使う”いつもの”です. 詳細は省略. fastbootを使うのにAndroidSDKに環境変数PATHを通しておきます.

ブートイメージ - LPX13D
nexus5-hammerhead-lpx13d-kernel.zip

SuperSU.zip
UPDATE-SuperSU-v2.14.zip

ClockworkModリカバリ
Google Nexus 5 Download Touch Recovery 6.0.4.5

2. Root化

Step1. SuperSU.zipを端末にコピー

パスは実行する環境に合わせて読み替えてください.
push先のパスは後ほど指定する必要があるので覚えておいてください.
USBは作業が終わるまで接続し続けてください.

adb push UPDATE-SuperSU-v2.14.zip /mnt/sdcard/

Step2. ブートローダのアンロック

adb reboot bootloader

# 端末再起動されるのでブートローダ起動されたら次を実行.
# 端末データは初期化されます. これ以降メーカ保証対象外となります.
fastboot oem unlock

アンロックの再確認があれば”YES”でブートローダアンロックしてください.

Step3. リカバリイメージを書き換える

今回はリカバリイメージをflashしません(問題なければflash).
端末再起動後に再度CWMリカバリモードを起動するにはコマンドを再発行してください.

fastboot boot "recovery-clockwork-touch-6.0.4.5-hammerhead.img"

Step4. SuperSUを導入

Clockworkmodが起動したらadb pushしておいたSuperSU.zipをインストールします.
Clockworkmod画面でパスを辿ってインストールします.

# 下記は例. adb pushした場所まで移動しインストールします. 
install zip > choose zip from /sdcard > /0> UPDATE-SuperSU-v2.14.zip

インストールの確認があるので”YES”を選択します.

SuperSUのインストールが完了した後は, [GO BACK]を選択してブートローダ画面まで戻ります.

Step5. ブートイメージを導入

ブートイメージ - LPX13D(nexus5-hammerhead-lpx13d-kernel.zip)に含まれるboot.imgを導入します.
こちらもflashはしていません.

fastboot boot boot.img

これで再起動がかかり, root化は一通り完了です. 再起動がかからないようであれば fastboot reboot.

Step6. flash

root化して一通り問題ないことが確認できたら各種イメージの類いをflash(ROM書き込み)しておきます.

# リカバリイメージをflash
fastboot flash boot "recovery-clockwork-touch-6.0.4.5-hammerhead.img"

# bootイメージをflash
fastboot flash boot boot.img

以上です.

Android: 同時実行制御とSQLite3

$
0
0

Intro

同時実行制御とは, 共有リソースにアクセスする複数のトランザクションを, いかに並列処理しつつ競合によるデータ破壊を回避するかを扱う分野である.
昨今のアプリケーションではクライアントが複数いることは珍しくない. 同時アクセスを許容せず, クライアントからの要求を直列的に処理できれば同時実行制御の課題は解決されるが, アプリケーションのレスポンスは極端に低下し使い物にならない.
パフォーマンスの低下を抑えるためにトランザクションを並列化し, かつリソースの整合性を保証しなければならないため, 同時実行制御を考える必要が出てくる.

Conflict

並列処理されるトランザクションの競合を制御しなかった場合の問題は主に4種類ある.
基本的にデータの一貫性は保証されない.

Dirty Read (w-r)

コミットされていないデータを別のトランザクションから参照できてしまう問題. トランザクションがロールバックされた場合に, 別のトランザクションから参照されていたデータはDirtyになる.
Created with Raphaël 2.1.0Transaction ATransaction AShared ResourceShared ResourceTransaction BTransaction BBEGIN TRANSACTIONBEGIN TRANSACTIONREAD (x=0)WRITE (x=1)READ (x=1)ROLLBACK TRANSACTIONExpected x=0But was 1-Dirty Read-

Lost Update / Overwrite (w-w)

別のトランザクションによる書き込みで, 更新したデータが上書きされてしまう問題.
Created with Raphaël 2.1.0Transaction ATransaction AShared ResourceShared ResourceTransaction BTransaction BBEGIN TRANSACTIONBEGIN TRANSACTIONWRITE (x=1)WRITE (x=0)COMMIT TRANSACTIONCOMMIT TRANSACTIONExpected x=1But was 0-Lost Update-

Non-Repeatable Read / Fuzzy Read (r-w)

トランザクション内で別のトランザクションによるデータ更新が反映されてしまい, 同じレコードでも参照するたびに結果が変わる.
Created with Raphaël 2.1.0Transaction ATransaction AShared ResourceShared ResourceTransaction BTransaction BBEGIN TRANSACTIONBEGIN TRANSACTIONREAD (x=0)WRITE (x=1)COMMIT TRANSACTIONREAD (x=1)Expected x=0But was 1-Fuzzy Read-

Phantom Read / Inconsistent Read (r-w)

同じトランザクション内でも, データの参照結果が増減する. 別のトランザクションによるデータ更新 or 削除が参照できることが原因で発生する.
Created with Raphaël 2.1.0Transaction ATransaction AShared ResourceShared ResourceTransaction BTransaction BBEGIN TRANSACTIONBEGIN TRANSACTIONREAD ALL (x)DELETE (x)INSERT (y)COMMIT TRANSACTIONREAD ALL (y)Expected xBut was y-Phantom Read-

Isolation

Isolationは分離性や隔離性, 独立性と訳される(本項では分離性とする). 分離性とはトランザクションを並列処理する中で, どこまでトランザクション同士の干渉を回避して読み取り一貫性を保証するかの度合いである.

Consistency and Isolation

分離レベルとはトランザクションの並列性/直列性の度合いを定義したものである. ACID特性の中でも分離性は柔軟解釈されている.
データベースソフトウェアでは分離レベルを選択できるものが多い. これは分離レベルの度合いにより拡張性や性能に大きな影響を与えるためである.
分離レベルは緩いほどパフォーマンスが向上する. 反対に厳しくするほどパフォーマンスは犠牲になる. ただし, 分離レベルを厳しくするほどデータの一貫性は保証されていく. 分離レベルには次のものがある.
  1. Read Uncommitted
  2. Read Committed
  3. Monotonic View
  4. Repeatable Read
  5. Serializability
Serializabilityは特定のリソースに対するアクセスを同時に1つのトランザクションしか実行させない形式, つまり各トランザクションが完全に直列実行されるため, トランザクションは交差することなく完全に分離される. Serializabilityは最も厳しい分離レベルである. このレベルは同時実行制御に関係する多くの問題が解決されるため一貫性の面においては理想的なレベルであるが, トランザクションが直列化することによりパフォーマンスを大きく損なうため多くの場合採用するに至らない.
少なくない数のクライアントを抱えているアプリケーションやリアルタイム性を求められるアプリケーションの場合, Serializability分離レベルを選択するのは現実的ではない1.
“では, パフォーマンスを向上しよう”という話になり, トランザクションを並列化させる方向に進んでいく. つまり同時実行制御を考える必要が出てくる.
  • トランザクションの並列化を促進する程, パフォーマンスは向上する.
  • トランザクションの直列化を促進する程, パフォーマンスは低下する.
ただし,
  • トランザクションの並列化を促進する程, 同時実行制御は複雑になる.
  • トランザクションの直列化を促進する程, 同時実行制御は単純になる.

Isolation Levels

トランザクションの代表的な分離レベル(ANSI/ISO表記)を次に記載する.
データ一貫性を保証するために全ての分離レベルではDirty Writeを回避する必要がある. 分離レベルが緩い(より並列化させる)ほど同時実行制御は複雑化しデータ破壊のリスクが高まる.

Read Uncommitted

他のトランザクションによるコミット前データの読み込みを許容する分離レベル. トランザクションは極めて並列に実行されるためパフォーマンスは高い. ただし, この分離レベルではDirty Writeは回避されるもののDirty Read, Fuzzy Read, Phantom Read, Lost Updateなど様々な問題が発生するため, 競合が発生する状況下ではデータ破壊の可能性も高くなる.

Read Committed

コミット済みデータが読み込まれることを保証する分離レベル. ただし, トランザクションの途中でも他のトランザクションがコミットしたデータが読み込まれる.
この分離レベルではDirty Readを回避できるが Fuzzy Read, Phantom Read, Lost Updateは回避できない.

Repeatable Read

トランザクションで読み込んだデータはコミットするまで変更されないことを保証する分離レベル.
保証するのは読み込んだデータに対してのみであり, それ以外のレコード追加などは保証されないので範囲指定問合せによるPhantom Readは防げない.

Serializability

完全な一貫性を保証する分離レベル. 全てのトランザクションが直列に実行されているように見える特徴がある.
競合問題と分離レベルの関係をまとめる.
-Dirty ReadLost UpdateFuzzy ReadPhantom Read
READ UNCOMMITTED発生する発生する発生する発生する
READ COMMITTED発生しない発生する発生する発生する
REPEATABLE READ発生しない発生しない発生しない発生する
SERIALIZABLE発生しない発生しない発生しない発生しない

Exclusive control

Shared lock, Exclusive lock

トランザクションの競合が発生すると前述の競合問題が発生する. 競合を回避してデータの一貫性を保証するためには共有リソースへのアクセスを制限するロックメカニズムを導入して排他制御を促進する.
排他制御とは, 他のトランザクションから共有リソースへのアクセスを制限(ロック)するものである. ロックはトランザクションの完了まで保持されたあと解除され, 他のトランザクションはそれまで共有リソースへアクセスすることができない.
ロックは他のトランザクションのアクセスを制限するという特性から, パフォーマンスに大きく影響する. そのためロックにはいくつか形態があり, 用途によって使い分けられる. ロックの形態は大きく2つ存在する.

Shared lock - 共有ロック

トランザクションがデータを読み込む場合のロック方式. データが共有ロックされている間は他のトランザクションでもデータを読み込むことができるが, データを書き込むことはできない.

Exclusive lock - 排他ロック

トランザクションがデータを書き込む場合のロック方式. データが排他ロックされている間は, 他のトランザクションからデータを読み込むことも書き込むこともできない.
また, ロックするデータの範囲をロック粒度(またはロックレベル)という. ロックするデータの範囲にはテーブル全体, 行全体, 特定の列がある. ロック粒度の程度には一長一短がある.
  • ロック粒度を小さくするとトランザクションの並列性が高くなる
  • ロック粒度を小さくするとトランザクションの競合頻度は高くなる
また,
  • ロック粒度を大きくするとトランザクションの並列性が低くなる
  • ロック粒度を大きくするとトランザクションの競合頻度は低くなる

Pessimistic mechanism, Optimistic mechanism

ロックを取得する期間も重要である. トランザクションは競合を検知するとデータの一貫性を保証するためにロールバックを実行し, トランザクション処理をキャンセルする. ロックの期間を短くするのは大切だが, 短くし過ぎてロールバックが頻発するのは問題である.
  • ロック取得の期間を長くすれば競合の排除を促進できる
  • ロック取得の期間を短くすれば競合の排除は抑制される
また,
  • ロック取得の期間を長くすると空振り(ロールバック)に終わる頻度は下がる
  • ロック取得の期間を短くすると空振り(ロールバック)に終わる頻度が上がる
ただし,
  • ロック取得の期間を長くすると別のトランザクションの待ち時間が延びる
  • ロック取得の期間を短くすると別のトランザクションの待ち時間が縮まる
さらに,
  • ロック取得の期間を長くするとデッドロックの発生確率が上がる
  • ロック取得の期間を短くするとデッドロックの発生確率は下がる
ロックにはパフォーマンスの話題がつきもので, 最適なロックの粒度と期間を選択しないとパフォーマンスの低下を招く.
ロックを取得するタイミングには2通りに大別される. 悲観的ロック と 楽観的ロック である.
悲観的ロックはロックの期間を長くとる. 反対に, 楽観的ロックではロックの期間を短くとる. システムの特性にあわせてどちらの方式を採用するかを決める.

Pessimistic mechanism - 悲観的方式

排他制御において, “トランザクションは高頻度で競合する前提”で考えられた悲観的な方式. 主にロックで排他制御を実現する.
悲観的方式では, トランザクションがデータにアクセスし始めた時点からコミットまでロックを保持する. この間, 別のトランザクションがリソースにアクセスすることを制限する.
悲観的方式はトランザクションを直列処理するため, 排他制御の扱いは容易に映るが, デッドロックやパフォーマンスの面で注意が必要である.

Optimistic mechanism - 楽観的方式

排他制御において, “トランザクションは低頻度で競合する前提”で考えられた楽観的な方式. 主に競合検出で排他制御を実現する.
楽観的方式では, トランザクション中に別のトランザクションによるデータ更新がなかったかを検査(競合検出)してからコミットする. トランザクションが更新操作中でも別のトランザクションからの操作は制限されない. コミット時に競合検出された場合は当該トランザクションはロールバックされる.
悲観的方式と楽観的方式は一長一短であり, それだけで優劣をつけるものではなく要件にあって選択すべきものである.
リソースの更新リクエストが頻発すると予想されるシステムでは, 書き込みに最適化させたい場合が多い. このケースでは悲観的方式を選択できる.
リソースの参照リクエストが中心となるシステムでは読み込みに最適化させたい場合が多い. このケースでは楽観的ロックが選択できる.
一般的にRDBMSは書き込み操作に最適化されており, 悲観的方式が採用される2.
一方, Webサーバは読み込み操作に最適化されており, レスポンス性を高めるために楽観的方式が採用されやすい.

SQLite3

SQLite3における同時実行制御関連の情報.

ロック粒度

DBMSによってはロックの粒度を行や列単位で指定できるものがある. ただし, SQLiteではデータベース全体のロック粒度しか選択できない.
SQLite.org - Appropriate Uses For SQLite … High Concurrency

ロック状態

SQLiteは共有ロック, 排他ロックの仕組みを備えており, プロセスを跨いで同時実行されても適切に処理される.
SQLiteのトランザクションには複数のモードが存在し, 各モードや実行内容によって取得されるロック種別が変わる.
UNLOCKED
非ロック状態. どのプロセスも書き込み/読み込みしていないデータベースの初期状態.
SHARED
データを書き込みを伴わずに読み込む場合に取得されるロック. 他のプロセスからの読み込みを許可するが書き込みは許可しない. SHAREDロックは複数のプロセスに保持させることができるため, 他のプロセスからの読み込みに対してオープンである.
RESERVED
将来データを書き込む予定だが現状読み込みしかされていない場合に取得されるロック. SHAREDロックとRESERVEDロックを共存させることができるが, RESERVEDロックはある時点で1つしか保持されない.
PENDING
EXCLUSIVEロックを取得してデータの書き込みを実行しようとSHAREDロックの開放を待機する場合に取得されるロック. 全てのSHAREDロックが開放されるとEXCLUSIVEロックが取得される.
EXCLUSIVE
データを書き込むために必要なロック. PENDINGロックからEXCLUSIVEロックに状態遷移するため, EXCLUSIVEロックが取得されているタイミングでは他のすべてのロックは解放されている. EXCLUSIVEと他のロックとを共存させることはできない.
See. SQLite.org - File Locking And Concurrency In SQLite Version 3

分離レベル

SQLiteにおける分離レベルはANSI/ISO SQL標準の表記とは異なっており, ロックを取得するタイミングに主眼を置いた表記となっている.
DEFERRED
トランザクション開始時にはロックを取得せず, データの読み込み/書き込みをする時点までロック取得を延期する. そのため, BEGINステートメントによるトランザクション開始のみでは何のロックも取得されない. ロックの取得がBEGIN~データの読み込み/書き込みまで延期されるため, 別トランザクションによるデータ書き込みの割り込みが発生する可能性がある. (ANSI/ISO SQL標準では READ_COMMITTEDに相当. )
IMMEDIATE
トランザクション開始時にRESERVEDロックを取得する. BEGIN IMMEDIATEによりRESERVEDロックが取得されると, 他のデータベースコネクションはデータベースに書き込んだり, BEGIN IMMEDIATE or BEGIN EXCLUSIVEを実行することができなくなるが, データベースからの読み込みを継続することはできる. ( ANSI/ISO SQL標準では REPEATABLE_READに相当. )
EXCLUSIVE
トランザクション開始時にEXCLUSIVEロックを取得する. BEGIN EXCLUSIVEによりEXCLUSIVEロックが取得されると, READ_UNCOMMITTEDの接続を除いた全てのデータベースコネクションからデータを読み込むことができなくなる. データベースへの書き込みについては例外なくトランザクションの完了まで許可されない. ( ANSI/ISO SQL標準では SERIALIZABLEに相当. )
See. SQLite.org - BEGIN TRANSACTION
See. SQLite.org - PRAGMA read_uncommitted

Reference

InfoQ - Web開発者が知っておくべき八つの分離レベル
以上.

  1. eBayやAmazonといった巨大Webアプリケーションが楽観的で緩やかな一貫性保証の方が, 古くからの悲観的メカニズムより拡張性に富んでいることを証明した例もある
  2. Oracle Databaseには楽観的ロックのイメージが強いが, 悲観的ロックも指定できる

Android: SQLite3 LockとTransaction Immediate/Exclusive

$
0
0

Intro

AndroidのSQLite3のLockとTransaction Immediate/Exclusiveについてまとめた.
基礎となる知識としては こちらを参照.

Locking And Concurrency In SQLite3

Oracle等のDBMSでは”行ロック”など細かくロック粒度を制御できるが, SQLiteではこれができない.
SQLiteのロック粒度は”データベース単位”のみである. このためRead/Writeロック取得~解放までの間, 他のトランザクションはデータベースにアクセスできない. (このことは”データベースを分割する/しない”の判断基準の1つにはなりそう)

AndroidではSQLiteのトランザクションモードとしてImmediateとExclusiveをAPIで指定できる. 特に指定しない場合はExclusiveモードとなる.

Transaction Immediate

ロック取得中は他トランザクションの書き込みを制限し, 読み込みを許可するmode.
Exclusive modeより緩い分離レベルであるためトランザクションの並列化を促進でき, パフォーマンス面で期待できる. ただし, Phantom Readが発生する可能性を考慮する必要がある.

IMMEDIATE.
トランザクション開始時にRESERVEDロックを取得する. BEGIN IMMEDIATEによりRESERVEDロックが取得されると, 他のデータベースコネクションはデータベースに書き込んだり, BEGIN IMMEDIATE or BEGIN EXCLUSIVEを実行することができなくなるが, データベースからの読み込みを継続することはできる.
ANSI/ISO SQL標準では REPEATABLE_READに相当する.

アプリケーションがデータベースへアクセスするのに書き込み専用トランザクション と 読み込み専用トランザクションのようにRead/Writeを分離できるのであればImmediate modeは有効に作用する.

Immediate modeではPhantom Readが発生するため, 次のようなシーケンスでは一貫性が損なわれる.

Created with Raphaël 2.1.0Transaction ATransaction AShared ResourceShared ResourceTransaction BTransaction BBEGIN TRANSACTIONBEGIN TRANSACTIONREAD ALL (x)DELETE (x)INSERT (y)COMMIT TRANSACTIONREAD ALL (y)Expected xBut was y-Phantom Read-

Transaction Exclusive

ロック取得中は他トランザクションの読み込み/書き込みを制限するmode.
Immediateより厳しい分離レベルであるためトランザクションの直列化が促進され, データの一貫性が向上する. ただしパフォーマンスはImmediateに劣る可能性が高い.

EXCLUSIVE
トランザクション開始時にEXCLUSIVEロックを取得する. BEGIN EXCLUSIVEによりEXCLUSIVEロックが取得されると, READ_UNCOMMITTEDの接続を除いた全てのデータベースコネクションからデータを読み込むことができなくなる. データベースへの書き込みについては例外なくトランザクションの完了まで許可されない.
ANSI/ISO SQL標準では SERIALIZABLEに相当する.

データベースに対して完全なデータの一貫性が求められる場合はExclusive modeを指定する.

Implements

クライアントからTransaction modeを指定するにはSQLiteDataBaseクラスを使用する.

  • SQLiteDataBase.beginTransaction()
  • SQLiteDataBase.beginTransactionWithListener(SQLiteTransactionListener)
  • SQLiteDataBase.beginTransactionNonExclusive()
  • SQLiteDataBase.beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)

beginTransactionNonExclusive/beginTransactionWithListenerNonExclusiveはAPI Level11で追加されたAPI.

beginTransaction/beginTransactionWithListenerで開始されたトランザクションはExclusive modeで,
beginTransactionNonExclusive/beginTransactionWithListenerNonExclusiveで開始されたトランザクションはImmediate modeで動作する.

// Transaction Exclusive mode
db.beginTransaction();
try {
// do something.
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

// Transaction Immediate mode
db.beginTransactionNonExclusive();
try {
// do something.
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

SQLiteDatabaseLockedException

ロックされているデータベースに対し, SQLiteDatabase経由でクエリを実行した場合の挙動は下記.

SQLiteDatabase.query

ロックが取得できるまでトランザクションは待機される. API Level16以降はCancellationSignalを使ってクエリをキャンセルすることができる.

SQLiteDatabase.insert

SQLiteDatabaseがSQLiteDatabaseLockedExceptionをキャッチし, 呼出し元に-1を返す.

publiclonginsert(String table, String nullColumnHack, ContentValues values) {
try {
return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
} catch (SQLException e) {
Log.e(TAG, "Error inserting " + values, e);
return -1;
}
}

SQLiteDatabase.insertOrThrow

SQLiteDatabaseLockedExceptionがスローされる.

publiclonginsertOrThrow(String table, String nullColumnHack, ContentValues values)
throws SQLException {
return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
}

SQLiteDatabase.update

SQLiteDatabaseLockedExceptionがスローされる.

SQLiteDatabase.delete

SQLiteDatabaseLockedExceptionがスローされる.

SQLiteDatabase.beginTransaction

SQLiteDatabaseLockedExceptionがスローされる.

Reference

File Locking And Concurrency In SQLite Version 3

以上.

Android:Creating Apps with Material Design

$
0
0

Creating Apps with Material Design

Material design is a comprehensive guide for visual, motion, and interaction design across platforms and devices. To use material design in your Android apps, follow the guidelines described in the material design specification and use the new components and functionality available in Android 5.0 (API level 21).

Material designは, プラットフォームやデバイスの垣根を越えたビジュアル, モーション, インタラクションのためのデザインガイドです.
Material designをAndroidアプリで使用するには, ガイドラインに従い, Android 5.0(API level 21)で利用可能となった新しいコンポーネントや機能を使用してください.

This class shows you how to create material design apps with the following elements:

  • The material theme
  • Widgets for cards and lists
  • Custom shadows and view clipping
  • Vector drawables
  • Custom animations

This class also teaches you how to maintain compatibility with versions of Android earlier than 5.0 (API level 21) when you use material design features in your app.

ここでは, 以下の要素を持つMaterial designなアプリの作成方法を記載します.

  • Material theme
  • カードとリストのためのウィジェット
  • 影とViewクリップ
  • ベクターDrawable
  • カスタムアニメーション

さらに, Android5.0(API level 21)以前のバージョンへの互換性を維持する方法を記載します.

Lessons

Getting Started
Learn how to update your app with material design features.

Using the Material Theme
Learn how to apply material design styles to your app.

Creating Lists and Cards
Learn how to create lists and cards with a consistent look and feel using system widgets.

Defining Shadows and Clipping Views
Learn how to set elevation for your views to create custom shadows and how to clip views.

Working with Drawables
Learn how to create vector drawables and how to tint drawable resources.

Defining Custom Animations
Learn how to create custom animations for views and activity transitions with shared elements.

Maintaining Compatibility
Learn how to maintain compatibility with platform versions earlier than Android 5.0.


LICENSE
Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

Original source: http://developer.android.com/training/material/index.html


Android: Creating Apps with Material Design - Getting Started

$
0
0

Getting Started

To create apps with material design:

  1. Review the material design specification.
  2. Apply the material theme to your app.
  3. Create your layouts following material design guidelines.
  4. Specify the elevation of your views to cast shadows.
  5. Use system widgets for lists and cards.
  6. Customize the animations in your app.

Material designに対応したアプリを作成するためには…

  1. Material designの仕様を確認する
  2. Material themeを適用する
  3. Material designガイドラインに従ったlayoutを作成する
  4. Viewの影をおとすelevationを指定する
  5. リストとカードのためのwidgetを利用する
  6. animationをカスタマイズする

Maintain backward compatibility
You can add many material design features to your app while maintaining compatibility with versions of Android earlier than 5.0. For more information, see Maintaining Compatibility.

下位互換性の維持
Android 5.0以前のバージョンとの互換性を維持しつつ, 多くのMaterial designの機能をアプリに追加できます. 詳細はMaintaining Compatibilityを参照.

Update your app with material design
To update an existing app to incorporate material design, update your layouts following material design guidelines. Also make sure to incorporate depth, touch feedback, and animations.

Material design化されたアプリにアップデート
Material designを組み込むために既存のアプリを改良するには, レイアウトをMaterial designのガイドラインに従って更新します. また, 奥行きやタッチフィードバック, アニメーションを組み込むようにして下さい.

Create new apps with material design
If you are creating a new app with material design features, the material design guidelines provide you with a cohesive design framework. Follow those guidelines and use the new functionality in the Android framework to design and develop your app.

新しいMaterial design化されたアプリの作成
もし, Material designの機能を持つ新しいアプリを作成する場合は, Material designのガイドラインがデザインフレームワークにもなる. これらのガイドラインに従い, Androidフレームワークの新しい機能を利用・設計してアプリを開発します.

Apply the Material Theme

To apply the material theme in your app, specify a style that inherits from android:Theme.Material:

アプリにMaterial themeを適用するには, android:Theme.Materialを継承したstyleを指定します.

<!-- res/values/styles.xml -->
<resources>
<!-- your theme inherits from the material theme -->
<stylename="AppTheme"parent="android:Theme.Material">
<!--themecustomizations-->
</style>
</resources>

The material theme provides updated system widgets that let you set their color palette and default animations for touch feedback and activity transitions. For more details, see Using the Material Theme.

Material themeはカラーパレット, タッチフィードバックのための標準アニメーション, Activity transitionsを提供する刷新されたWidgetを提供します. 詳細は, Using the Material Themeを参照.

Design Your Layouts

In addition to applying and customizing the material theme, your layouts should conform to the material design guidelines. When you design your layouts, pay special attention to the following:

  • Baseline grids
  • Keylines
  • Spacing
  • Touch target size
  • Layout structure

Material themeを適用しカスタマイズすることに加えて, レイアウトをMaterial designガイドラインこれに準拠させる必要があります. レイアウトの設計には, 次の点に注意しましょう.

  • Baseline grids
  • Keylines
  • Spacing
  • Touch target size
  • Layout structure

Specify Elevation in Your Views

Views can cast shadows, and the elevation value of a view determines the size of its shadow and its drawing order. To set the elevation of a view, use the android:elevation attribute in your layouts:

Viewには影を設定することができ, Viewのelevation値は影のサイズと描画順序を決定します. Viewにelevationを設定するためには, レイアウトのattributeにandroid:elevationを使用します.

<TextView
android:id="@+id/my_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
android:background="@color/white"
android:elevation="5dp" />

The new translationZ property lets you create animations that reflect temporary changes in the elevation of a view. Elevation changes can be useful when responding to touch gestures.

For more details, see Defining Shadows and Clipping Views.

新しいプロパティtranslationZは, Viewのelevationの変更をアニメーションさせることができます. elevationの変更はタッチジェスチャーの反応を表現する時に役立ちます.

詳細は, Defining Shadows and Clipping Viewsを参照.

Create Lists and Cards

RecyclerView is a more pluggable version of ListView that supports different layout types and provides performance improvements. CardView lets you show pieces of information inside cards with a consistent look across apps. The following code example demonstrates how to include a CardView in your layout:

RecyclerViewListViewと比べて拡張性に富み, 様々なレイアウトタイプをサポートしパフォーマンスの向上を見込めます. CardViewは情報をカード内に表示し, アプリ間で一貫した外観を提供します. 次のコードはレイアウト内にCardViewを含める方法です.

<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="200dp"
android:layout_height="200dp"
card_view:cardCornerRadius="3dp">

...
</android.support.v7.widget.CardView>

For more information, see Creating Lists and Cards.

詳細はCreating Lists and Cardsを参照.

Customize Your Animations

Android 5.0 (API level 21) includes new APIs to create custom animations in your app. For example, you can enable activity transitions and define an exit transition inside an activity:

Android5.0 (API level 21)は, カスタムアニメーションを作成するための新しいAPIを含んでいます. 例えば, Activity transitionsと終了時のtransitionを定義することができます.

publicclassMyActivityextendsActivity {

@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// enable transitions
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
setContentView(R.layout.activity_my);
}

publicvoidonSomeButtonClicked(View view) {
getWindow().setExitTransition(new Explode());
Intent intent = new Intent(this, MyOtherActivity.class);
startActivity(intent,
ActivityOptions
.makeSceneTransitionAnimation(this).toBundle());
}
}

When you start another activity from this activity, the exit transition is activated.

To learn more about the new animation APIs, see Defining Custom Animations.

このActivityから別のActivityを起動する時, 終了transitionが始動します.

新しいアニメーションのAPIについてさらに学ぶには, Defining Custom Animationsを参照.

LICENSE
Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

Original source: http://developer.android.com/training/material/get-started.html

Android: Creating Apps with Material Design - Using the Material Theme

$
0
0

Using the Material Theme

The new material theme provides:

  • System widgets that let you set their color palette
  • Touch feedback animations for the system widgets
  • Activity transition animations

新しいmaterial themeは以下を提供します.

  • カラーパレットを設定できるシステムウィジェット
  • システムウィジェット用タッチフィードバックアニメーション
  • Activity transitionアニメーション

You can customize the look of the material theme according to your brand identity with a color palette you control. You can tint the action bar and the status bar using theme attributes, as shown in Figure 3.

ブランドの特徴にマッチしたmaterial themeな外観とするためにカラーパレットをカスタマイズすることができます.

The system widgets have a new design and touch feedback animations. You can customize the color palette, the touch feedback animations, and the activity transitions for your app.

The material theme is defined as:

  • @android:style/Theme.Material (dark version)
  • @android:style/Theme.Material.Light (light version)
  • @android:style/Theme.Material.Light.DarkActionBar

For a list of material styles that you can use, see the API reference for R.style.

システムウィジェットは新しいデザインとタッチフィードバックアニメーションを持っています. アプリのカラーパレットやタッチフィードバックアニメーション, Activity transitionをカスタマイズすることができます.

material themeは, 次のように定義します.

  • @android:style/Theme.Material (dark version)
  • @android:style/Theme.Material.Light (light version)
  • @android:style/Theme.Material.Light.DarkActionBar

利用可能なmaterial styleの一覧は, R.styleのAPIリファレンスを参照.

Figure 1
Figure 1. Dark material theme

Figure 2
Figure 2. Light material theme

Note: The material theme is only available in Android 5.0 (API level 21) and above. The v7 Support Libraries provide themes with material design styles for some widgets and support for customizing the color palette. For more information, see Maintaining Compatibility.

注意:material themeは, Android5.0 (API level 21)以上で利用可能です. v7サポートライブラリは, いくつかのウィジェットのためのmaterial designのstyleを提供し, カラーパレットのカスタマイズをサポートます. 詳細は, Maintaining Compatibilityを参照.

Customize the Color Palette

To customize the theme’s base colors to fit your brand, define your custom colors using theme attributes when you inherit from the material theme:

ブランドに合うthemeのベースカラーにカスタマイズするためには, material themeを継承しtheme属性を使用してカスタムカラーを定義します.

<resources>
<!-- inherit from the material theme -->
<stylename="AppTheme"parent="android:Theme.Material">
<!--Mainthemecolors-->
<!--yourappbrandingcolorfortheappbar-->
<itemname="android:colorPrimary">@color/primary</item>
<!-- darker variant for the status bar and contextual app bars -->
<item name="android:colorPrimaryDark">@color/primary_dark</item>
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">@color/accent</item>
</style>
</resources>

Figure 3
Figure 3. Customizing the material theme.

Customize the Status Bar

The material theme lets you easily customize the status bar, so you can specify a color that fits your brand and provides enough contrast to show the white status icons. To set a custom color for the status bar, use the android:statusBarColor attribute when you extend the material theme. By default, android:statusBarColor inherits the value of android:colorPrimaryDark.

material themeを使用すると, あなたのブランドに合ったステータスバー色にカスタマイズできます. ステータスバーの色は白色のステータスアイコンが見える範囲で指定します. ステータスバーにカスタムカラーを設定するには, material themeを拡張して, android:statusBarColor属性を使用します. デフォルトでandroid:statusBarColorandroid:colorPrimaryDarkの値を継承します.

You can also draw behind the status bar yourself. For example, if you want to show the status bar transparently over a photo, with a subtle dark gradient to ensure the white status icons are visible. To do so, set the android:statusBarColor attribute to @android:color/transparent and adjust the window flags as required. You can also use the Window.setStatusBarColor() method for animations or fading.

また, ステータスバーの背後に描画することもできます. 例えば, 写真の上に透明なステータスバーを表示したい場合, わずかに濃いグラデーションを敷いて白のステータスアイコンが見えるようにします. そのためには, android:statusBarColor属性に@android:color/transparentを設定し, 必要に応じてwindow flagを調整します. また, アニメーションやフェージングのためにWindow.setStatusBarColor()メソッドを使用できます.

Note: The status bar should almost always have a clear delineation from the primary toolbar, except for cases where you show edge-to-edge rich imagery or media content behind these bars and when you use a gradient to ensure that the icons are still visible.

注意:ステータスバーにコンテンツを表示したり, 全画面表示のケースを除き, ステータスバーはプライマリツールバーと明確に分けられるべきです.

When you customize the navigation and status bars, either make them both transparent or modify only the status bar. The navigation bar should remain black in all other cases.

ナビゲーションバーやステータスバーをカスタマイズする際, それら両方を透明にするかステータスバーのみを変更します. その他の全てのケースにおいてはナビゲーションバーは黒のままとすべきです.

Theme Individual Views

Elements in XML layout definitions can specify the android:theme attribute, which references a theme resource. This attribute modifies the theme for the element and any child elements, which is useful for altering theme color palettes in a specific portion of an interface.

XMLレイアウトで定義する要素には, android:theme属性でthemeリソースを指定できます. この属性は, 要素や子要素のテーマも変えるため, 特定部分のテーマカラーパレットを変更するのに便利です.

LICENSE
Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

Original source: http://developer.android.com/training/material/theme.html

Android: MaterialDesign - Creating Apps with Material Design - part.3 Creating Lists and Cards

$
0
0

Creating Lists and Cards

To create complex lists and cards with material design styles in your apps, you can use the RecyclerView and CardView widgets.

material designを適用したリストやカードUIを作成するために, RecyclerViewCardViewを使用できます.

Create Lists

Figure 2
Figure 2 - Lists with RecyclerView.

The RecyclerView widget is a more advanced and flexible version of ListView. This widget is a container for displaying large data sets that can be scrolled very efficiently by maintaining a limited number of views. Use the RecyclerView widget when you have data collections whose elements change at runtime based on user action or network events.

RecyclerView widgetは, より最新で柔軟性のあるListViewのバージョンです. このwidgetは限られたviewをリサイクルして使い回すことで, 非常に効率的にスクロールできる大きなデータセットを表示するためのコンテナです. ユーザのアクションやネットワクークのイベントに基づいて, 実行時に要素が変わるデータの集まりを持つ場合は, RecyclerView widgetを使用してください.

The RecyclerView class simplifies the display and handling of large data sets by providing:

  • Layout managers for positioning items
  • Default animations for common item operations, such as removal or addition of items

You also have the flexibility to define custom layout managers and animations for RecyclerView widgets.

RecyclerViewのクラスは以下の機能が提供され, 表示や大きなデータセットの扱いを容易にします.

  • アイテムを位置付けるレイアウトマネージャー
  • アイテムの削除や追加のような一般的な操作のためのデフォルトアニメーション

また, RecyclerView widget用のカスタムレイアウトマネージャーやアニメーションを定義するための柔軟性を兼ね備えています.

Figure 1
Figure 1. The RecyclerView widget.

To use the RecyclerView widget, you have to specify an adapter and a layout manager. To create an adapter, extend the RecyclerView.Adapter class. The details of the implementation depend on the specifics of your dataset and the type of views. For more information, see the examples below.

RecyclerView widgetを使用するには, adapterと layout managerを指定する必要があります. adapterを生成するには, RecyclerView.Adapterクラスを継承します. 実装の詳細は, データセットやviewの種類によって異なります. 詳細は本ページ下部のExamplesを参照.

A layout manager positions item views inside a RecyclerView and determines when to reuse item views that are no longer visible to the user. To reuse (or recycle) a view, a layout manager may ask the adapter to replace the contents of the view with a different element from the dataset. Recycling views in this manner improves performance by avoiding the creation of unnecessary views or performing expensive findViewById() lookups.

layout managerは, RecyclerView内のアイテムを位置付けし, ユーザからは見えなくなったviewを再利用するタイミングを決定します. viewをリサイクルするために, レイアウトマネージャーはadapterに異なるデータでview要素の入れ替えを求めることがあります. このようにviewのリサイクルすることで, 不要なviewの生成やコストのかかるfindViewById()のルックアップ処理を防ぐことでパフォーマンスを改善します.

RecyclerView provides these built-in layout managers:

  • LinearLayoutManager shows items in a vertical or horizontal scrolling list.
  • GridLayoutManager shows items in a grid.
  • StaggeredGridLayoutManager shows items in a staggered grid.

To create a custom layout manager, extend the RecyclerView.LayoutManager class.

RecyclerViewはビルトインされた次のレイアウトマネージャーを提供します.

カスタムレイアウトマネージャーを作成するには, RecyclerView.LayoutManagerクラスを継承します.

Animations

Animations for adding and removing items are enabled by default in RecyclerView. To customize these animations, extend the RecyclerView.ItemAnimator class and use the RecyclerView.setItemAnimator() method.

RecyclerViewでは, アイテムの追加や削除のアニメーションがデフォルトで有効になっています. これらのアニメーションをカスタマイズするには, RecyclerView.ItemAnimatorクラスを継承し, RecyclerView.setItemAnimator()メソッドを使用します.

Examples

The following code example demonstrates how to add the RecyclerView to a layout:

以下のコードは, レイアウトにRecyclerViewを追加する方法の一例です.

<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

Once you have added a RecyclerView widget to your layout, obtain a handle to the object, connect it to a layout manager, and attach an adapter for the data to be displayed:

レイアウトにRecyclerView widgetを追加したら, それを取得してlayout managerを登録し, データを表示するためのadapterをアタッチします.

publicclassMyActivityextendsActivity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;

@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);

// use a linear layout manager
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);

// specify an adapter (see also next example)
mAdapter = new MyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
}
...
}

The adapter provides access to the items in your data set, creates views for items, and replaces the content of some of the views with new data items when the original item is no longer visible. The following code example shows a simple implementation for a data set that consists of an array of strings displayed using TextView widgets:

adapterはデータセット内の各項目へのアクセスやviewの生成, 元のアイテムが見えなくなった時に新たなデータ項目でviewの内容を入れ替える仕組みを提供します. 以下のコードは, TextView widgetsを使用して表示したString配列から構成されたデータセットを実装する簡単な例です.

publicclassMyAdapterextendsRecyclerView.Adapter<MyAdapter.ViewHolder> {
private String[] mDataset;

// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
publicstaticclassViewHolderextendsRecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView mTextView;
publicViewHolder(TextView v) {
super(v);
mTextView = v;
}
}

// Provide a suitable constructor (depends on the kind of dataset)
publicMyAdapter(String[] myDataset) {
mDataset = myDataset;
}

// Create new views (invoked by the layout manager)
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.my_text_view, parent, false);
// set the view's size, margins, paddings and layout parameters
...
ViewHolder vh = new ViewHolder(v);
return vh;
}

// Replace the contents of a view (invoked by the layout manager)
@Override
publicvoidonBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.mTextView.setText(mDataset[position]);

}

// Return the size of your dataset (invoked by the layout manager)
@Override
publicintgetItemCount() {
return mDataset.length;
}
}

Create Cards

Figure 3
Figure 3. Card examples.

CardView extends the FrameLayout class and lets you show information inside cards that have a consistent look across the platform. CardView widgets can have shadows and rounded corners.

CardViewはFrameLayoutクラスを継承し, あらゆるプラットホームで一貫した外観を持つカード内の情報を表示することができます.

To create a card with a shadow, use the card_view:cardElevation attribute. CardView uses real elevation and dynamic shadows on Android 5.0 (API level 21) and above and falls back to a programmatic shadow implementation on earlier versions. For more information, see Maintaining Compatibility.

影があるカードを作成するには, card_view:cardElevation属性を使用します. CardViewは, Android 5.0 (API level 21)以上ではリアルなエレベーションとダイナミックな影を使い, それ以前のバージョンではプログラム的な影の実装に代替されます. 詳細は, Maintaining Compatibilityを参照.

Use these properties to customize the appearance of the CardView widget:

  • To set the corner radius in your layouts, use the card_view:cardCornerRadius attribute.
  • To set the corner radius in your code, use the CardView.setRadius method.
  • To set the background color of a card, use the card_view:cardBackgroundColor attribute.

これらのプロパティを使用してCardView widgetの外観をカスタマイズします.

  • レイアウトの角の丸みを設定するには, card_view:cardCornerRadius属性を使用します.
  • コード上で角の丸みを設定するには, CardView.setRadiusメソッドを使用します.
  • カードの背景色を設定するには, card_view:cardBackgroundColor属性を使用します.

The following code example shows you how to include a CardView widget in your layout:

以下のコード例は, レイアウトにCardView widgetを含む方法です.

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
...>

<!-- A CardView that contains a TextView -->
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_gravity="center"
android:layout_width="200dp"
android:layout_height="200dp"
card_view:cardCornerRadius="4dp">


<TextView
android:id="@+id/info_text"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</android.support.v7.widget.CardView>
</LinearLayout>

For more information, see the API reference for CardView.

詳細は, CardViewのAPIリファレンスを参照.

Add Dependencies

The RecyclerView and CardView widgets are part of the v7 Support Libraries. To use these widgets in your project, add these Gradle dependencies to your app’s module:

RecyclerViewとCardViewのwidgetsはv7サポートライブラリの一部です. これらのwidgetを使用するには, 以下のGradleの依存関係をアプリのモジュールに追加します.

dependencies {
...
compile 'com.android.support:cardview-v7:21.0.+'
compile 'com.android.support:recyclerview-v7:21.0.+'
}

LICENSE
Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.
Original source: http://developer.android.com/training/material/lists-cards.html

Android: SQLiteOpenHelperコンストラクタの引数CursorFactoryについて

$
0
0

Overview

SQLiteOpenHelperのコンストラクタを見てみると第三引数にCursorFactoryを受け取るようになっている.

SQLiteOpenHelper (Context, String, CursorFactory, int)

SQLiteデータベースを使用したサンプルコードではnullが指定されるケースが多く, あまり活用事例を見ない.

db = new MyDatabase(context, DB_NAME, null/*CursorFactory*/, DB_VERSION);

本稿ではCursorFactoryの利用する方法について記載する.

SQLiteDatabaseにクエリを発行するとCursorが返却される.
Android標準では, このCursor生成処理を拡張できるCursorFactoryクラスを用意している.
CursorFactoryを使ってCursorクラスを得るまでの一般的な流れは下記.

CursorFactoryを実装することで次のことが実現できる.

  • Cursor生成のタイミングをフックする
  • クエリ結果として独自Cursorを返す

ただし, 2点目の独自Cursorを返すについては注意事項がある(後述).

API Reference.

CursorFactoryと周辺のクラスを次に記す.

SQLiteOpenHelper - API Reference - Android Developers
SQLiteDatabaseの生成とバージョンを管理するクラス.

SQLiteDatabase - API Reference - Android Developers
SQLiteデータベースの生成・破棄・問合せといったSQLの実行や管理を行うクラス.

SQLiteDatabase.CursorFactory - API Reference - Android Developers
SQLiteDatabaseへのクエリ結果を格納したCursorのファクトリクラス. ここで生成されるCursorインスタンスがクエリの戻り値(Cursor)として使われる.

SQLiteCursor - API Reference - Android Developers
SQLiteへのクエリ結果を格納したCursorの具象クラス. 内部のSQLiteCursorを直接操作する場合は別途スレッドセーフを自前で担保する必要がある.

SQLiteQueryBuilder - API Reference - Android Developers
SQLiteDatabaseへのクエリ構築を手助けするビルダクラス.

Set CursorFactory

Android標準でCursorの生成はSQLiteDirectCursorDriver.queryで行われる.

public Cursor query(CursorFactory factory, String[] selectionArgs) {
...
if (factory == null) {
cursor = new SQLiteCursor(this, mEditTable, query);
} else {
cursor = factory.newCursor(mDatabase, this, mEditTable, query);
}
...
}

CursorFactoryが指定されていればCursorFactory.newCursorメソッドを経由してCursorを生成する.
ここで独自のCursorFactoryが指定されていればCursorの生成をフックし, 独自Cursorを返すことができる.

implements

CursorFactoryはSQLiteDatabaseの取得時に指定する.
SQLiteDatabaseにCursorFactoryを設定するメソッドはいくつかある.

しかし, 一般的にSQLiteDatabaseのメソッドを直接操作することはせず, SQLiteOpenHelperやSQLiteQueryBuilderを経由する.
そのため, SQLiteOpenHelperやSQLiteQueryBuilderにもCursorFactoryを設定するためのAPIが用意されている.

publicclassMyDBHelperextendsSQLiteOpenHelper{
publicMyDBHelper(Context context){
super(context, DB_NAME, CURSOR_FACTORY, DB_VERSION);
}
...
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setCursorFactory(CURSOR_FACTORY);
...
}

なお, CursorFactoryが指定されない場合はCursorのサブクラスであるSQLiteCursorが生成される.

次に, 独自のCursorFactoryを用意する.
CursorFactoryにはカーソルを生成するnewCursorメソッドが用意されており, ここでCursorを生成する.

publicclassMyCursorFactoryimplementsCursorFactory {
@Override
public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
String editTable, SQLiteQuery query) {
returnnew SQLiteCursor(masterQuery, editTable, query);
}
}

独自CursorFactoryを設定するためにSQLiteOpenHelperのコンストラクタ引数にこれを指定する.
他にもクエリ発行時にCursorFactoryを指定することもできる(後述).

publicclassMyContentProviderextendsContentProvider {
@Override
publicbooleanonCreate() {
db = new MySQLiteOpenHelper(context, DB_NAME,
new MyCursorFactory(), DB_VERSION);
...
}
}

Query API with CursorFactory

SQLiteDatabaseにクエリを問い合わせるために次のメソッドが用意されている.

queryWithFactory/rawQueryWithFactoryメソッドはCursorFactoryを直接指定してクエリを実行する.
一方, query/rawQueryメソッドは引数cursorFactoryにnullを指定して最終的にrawQueryWithFactoryを呼ぶ.

rawQueryWithFactoryメソッドは引数cursorFactoryにnullが指定されるとSQLiteDatabaseに設定されているCursorFactoryを使用する. この挙動にあたる部分のソースコードは下記.

// rawQuery系メソッドでは引数にnullを指定すると設定した独自CursorFactoryが使用される.
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable, CancellationSignal cancellationSignal) {
acquireReference();
try {
SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(
this, sql, editTable, cancellationSignal);
return driver.query(
cursorFactory != null ? cursorFactory : mCursorFactory,
selectionArgs);
} finally {
releaseReference();
}
}

MEMO
SQLiteDatabase.queryメソッドは簡易な検索に向いている.
複雑なクエリを組み立てるにはデータバインドにも対応しているSQLiteDatabase.rawQueryメソッドが便利.

SQLiteDatabaseにクエリを発行するにはいくつか方法がある. 下記はその一例.

  1. SQLiteDatabaseインスタンスに直接クエリを投げる
  2. SQLiteQueryBuilder経由でクエリを投げる

SQLiteDatabase

前述の通りqueryWithFactory/rawQueryWithFactoryメソッドの引数にCursorFactoryを指定できる.
nullを指定した場合はSQLiteDatabaseに設定したCursorFactoryが使用される.

SQLiteQueryBuilder

結果的にSQLiteDatabaseのrawQueryWithFactoryが実行される.
SQLiteQueryBuilderにはCursorFactoryを指定するメソッドが用意されている.

Attention

SQLiteDatabaseを使ったアプリケーションではContentProviderも使われることが多い.
CursorFactoryとContentProviderを併用する場合に注意すべき点がある.

ContentProviderサイドで生成されたCursorは直接クライアントサイドには届かない.
SQLiteDatabaseで生成されるCursorはWrapやコピーを経てクライアントサイドに届く.
つまり, CursorFactoryで独自Cursorを返却しても, それを独自Cursorとして使用(Cast)できるのはそれを生成したContentProviderの処理内に限定される.
クライアントサイドで独自Cursorにキャストし直すことはできない.

Usage

CursorFactoryは使いどころの難しいAPIではあるが, たとえばCursor生成をフックして次のようにクエリをロギングする仕組みは楽に作ることができる.

publicclassMyCursorFactoryimplementsCursorFactory {
@Override
public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
String editTable, SQLiteQuery query) {
if (debug) {
Log.d(TAG, query.toString());
}
returnnew SQLiteCursor(masterQuery, editTable, query);
}
}

以上.

Android:Lint

$
0
0

はじめに

Android LintはAndroidプロジェクトの潜在的不具合を検出するための支援プログラムである.
Android Lintでは次のようなAndroidに特化した問題を検出することができる.

  • 多言語化対応の不足 (翻訳されていない, るいは利用されていない文言)
  • レイアウトパフォーマンスの問題(旧layoutopt toolで検出されていたもの+α)
  • 未使用リソース
  • iconに関する問題(densityの間違いや間違ったサイズ etc…)
  • AndroidManifest関連のエラー
  • などなど他多数

Android Lintは単独動作できるコンポーネントでありCIツールとの連携が望まれている.
Lintのチェックリストは随時更新されており, Android SDK toolsとして配布されている.
検査結果をレポートすることもできる.

Android Lintの検査内容

Android SDK toolsに同梱されているlintバイナリに--showコマンドを発行すれば検査内容の一覧を確認できる.

$ lint --show

各検査項目にはPriority, Severity, Categoryが設定されている.

Priority
1~10(max:10). 問題の優先度.

Severity
Warning, Error, Fatal. 問題の重要度.

Category
Performance, Usability, Correctness, Security etc… 問題の種類.

Android Lintによる検査はリリースビルドを実行した際に自動実行される.
ここでは致命的なエラーのみを対象に検査され, 問題があった場合はビルドを中止する.

GradleのlintOptionでこれを停止することもできる.

android {
lintOptions {
abortOnError false
}
}

Android Lintの実行

Android StudioであればGradleのタスクとしてlintが標準で作成されている.
GradleでAndroid Lintの挙動を制御したい場合は次のオプションを指定できる.

android {
lintOptions {
// settotrueto turn off analysis progress reporting by lint
quiet true
// iftrue, stop the gradle build if errors arefound
abortOnError false
// iftrue, only report errors
ignoreWarnings true
// iftrue, emit full/absolute paths to files with errors (truebydefault)
absolutePaths true
// iftrue, checkall issues, including those that are off bydefault
checkAllWarnings true
// iftrue, treat all warnings as errors
warningsAsErrors true
// turn off checking the given issue ids
disable 'TypographyFractions','TypographyQuotes'
// turn on the given issue ids
enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'
// check *only* the given issue ids
check'NewApi', 'InlinedApi'
// iftrue, dont include source code lines in the error output
noLines true
// iftrue, showall locations for an error, donottruncate lists, etc.
showAll true
// Fallback lint configuration (default severities, etc.)
lintConfig file("default-lint.xml")
// iftrue, generate a text report of issues (falsebydefault)
textReport true
// location towrite the output;
can be a file or 'stdout'
textOutput 'stdout'
// if true, generate an XML report for use by for example Jenkins
xmlReport false
// file to write report to (if not specified, defaults to lint-results.xml)
xmlOutput file("lint-report.xml")
// if true, generate an HTML report (with issue explanations, sourcecode, etc)
htmlReport true
// optional path to report (default will be lint-results.html in the builddir)
htmlOutput file("lint-report.html")

// settotrueto have all release builds run lint on issues with severity=fatal
// and abort the build (controlled by abortOnError above) if fatal issues arefound
checkReleaseBuilds true
// Set the severity of the given issues to fatal (which means they will be
// checked during release builds (even if the lint target isnot included)
fatal 'NewApi', 'InlineApi'
// Set the severity of the given issues to error
error 'Wakelock', 'TextViewEdits'
// Set the severity of the given issues to warning
warning 'ResourceAsColor'
// Set the severity of the given issues to ignore (same as disabling the check)
ignore 'TypographyQuotes'
}
}

参考

Android:Findbugs

$
0
0

はじめに

FindBugsは次の機能を持つ静的検査ツールである.

  • Javaクラスバイナリに対する解析によりバグパターンの検査を行う
  • 解析結果を出力する

FindBugsはJavaクラスバイナリからバグパターンを解析するプログラム. ソースコードリポジトリへのコミット前後でFindBugsによるコード解析を行い, 潜在的な不具合を排除するツールとして非常に強力である.

Javaソースコードを解析したい場合はPMDが利用できる. 実動作により近いクラスバイナリを検査するという点ではFindBugsが有利であるが, ソースコード自体の品質を向上させたい場合はPMDやLintを使用する.
Groovyコードは同じくクラスコードを生成するがFindBugsによる正しい検査はできない.

また, 解析結果を出力する機能もあり, 各種CIツールとの親和性も高い.

FindBugsの動作環境

  • プラットフォーム非依存(GNU/Linux, MacOS X, Windows可)
  • J2SE 1.5以上のランタイムが必要
  • メモリ512MB以上が必要で, 解析対象が巨大である程これは増加する

FindBugs GUI

FindBugsはそれ単体をプログラムとして配布されている.
http://findbugs.sourceforge.net/ja/manual/installing.html#d0e94

FindBugsを単体実行するGUIツールも用意されているが, 昨今ではIDEアプリケーションのプラグインとして導入・実行されるケースが主であるためここでは割愛する.
http://findbugs.sourceforge.net/ja/manual/gui.html

Bug Pattern

下記ページに日本語訳(FindBugsv2.0.2)が纏められている.
http://www.acroquest.co.jp/webworkshop/JavaTroubleshooting/findbugs/

FindBugsを実行する際にはこれらのBug Patternを検査項目としてインプットする.
プロジェクトの特性に合わせて検査項目はフィルタされることもある.

Analysis Properties

FindBugsがソース解析する際の観点を分析プロパティとして実行時に指定することができる.
分析プロパティには主に次の2点を指定する.

  • 分析対象のメソッドの意味
  • 分析の精度

1点目, 分析対象メソッドの意味を指定することでより正確な分析結果を得ることができ, 誤検出を減らすことができる.
2点目, FindBugsが消費するメモリや分析時間が問題となる場合は精度を落とすことで解決できる場合がある. ただし, 検出されるべきバグを見逃す可能性が高くなるデメリットもある.

分析プロパティは-propertyで指定する. 次はその例.

$ findbugs -textui -property "cfg.noprune=true" myApp.jar

-propertyで指定できる分析オプションの一覧は下記を参照.
http://findbugs.sourceforge.net/ja/manual/analysisprops.html

FindBugs Plug-in

IntelliJ IDEA系 IDEにFindBugsを導入する場合は FindBugs-IDEA プラグインが便利.
https://plugins.jetbrains.com/plugin/3847?pr=idea

FindBugsは日本語情報も充実しており, Webで検索すればいくらでも見つけることができる.

CIツールでFindBugsを自動実行させたい場合, Gradleには標準でFindBugs-pluginが用意されている.
http://gradle.monochromeroad.com/docs/userguide/findbugs_plugin.html

NOTE
上記GradleのFindBugsプラグインはjavaプラグインと併用されることを前提としている.
Androidプロジェクトで作成されるbuild.gradleにはjavaプラグインが適用されないため, FindBugsプラグインを動作させるには少し工夫する必要がある.

次のgroovyコードをbuild.gradleに適用するとfindbugsタスクが追加され, Gradle consoleからfindbugsを実行することができるようになる.

apply plugin: 'findbugs'

task findbugs(type: FindBugs) {
ignoreFailures = true
classes = fileTree('build/intermediates/classes/debug/')
source = fileTree('src/main/java/')
classpath = files()
effort = 'max'
}
tasks.withType(FindBugs) {
reports {
xml.enabled = false
html.enabled = true
}
}

参考

以上.

Android:Calabash for Android 導入

$
0
0

はじめに

Calabash for Androidは, Ruby製のビヘイビア駆動開発(BDD:Behaviour Driven Development)ツール Cucumberを使ってAndroidアプリをテストできるライブラリ.
Rubyのパッケージ管理システムgemでインストールできる.

今回の確認環境は次の通り.

  • Mac OSX Mavericks 10.9.5
  • RVM version 1.26.7
  • Ruby 2.2.0p0

準備

Rubyの環境を整えるためにHomebrewをインストールする

ruby -e"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Homebrewが正しくインストールされたかをチェック. エラーが出た場合はメッセージに従う

brew doctor

RVMをインストールする

\curl -sSL https://get.rvm.io | bash -s stable

PATHを設定するために.bashをリロード

source ~/.bash_profile

RVMのバージョンを確認

rvm version

Rubyの最新バージョンを確認

rvm list known

Ruvyの最新バージョンをインストールし, デフォルトに設定する.

rvm install ruby-2.2.0 --default

PATHを設定するために.bashをリロード

source ~/.bash_profile

Rubyのバージョンを確認

ruby -v

Rubyのインストールロケーションを確認

which ruby

Calabash for Androidのインストール

gem install calabash-android

AndroidSDKのパスをANDROID_HOME環境変数で定義

// .bash_profileに下記を追記
export ANDROID_HOME=[AndroidSDKへのパス]

PATHを設定するために.bashをリロード

source ~/.bash_profile

ANDROID_HOMEが正しく設定できているか確認

echo$ANDROID_HOME

テスト対象のAndroidプロジェクトに移動.
AndroidManifest.xmlがあるディレクトリに移動し下記コマンドを実行.

calabash-android gen

genによりcucumberのスケルトンが作成される(作成される各種ファイルについては後述)

calabashテスト実行時にインストールされるテストアプリに付与する署名を指定する.
この署名はテスト対象のアプリと同じ署名とする. 署名の指定は次のコマンドで行う.

# 実行するとカレントディレクトリに.calabash_settingファイルが生成される
calabash-android setup

テストを実行するには同階層で下記コマンドを実行する.

calabash-android run [テスト対象のapk]

実行するとテストが実行される.
cucumberが途中で上手く動作しない場合は-vオプションを付与することで詳細なログが出力される.

NOTE
calabash-android gen, calabash-android setup, calabash-android runはAndroidManifest.xmlと同階層で実行する.

参考


Android:Robotium

$
0
0

はじめに.

RobotiumはAndroidのブラックボックステストを自動化するUIテストフレームワーク.
シナリオを手軽にかけて導入も非常に簡単である. 老舗のテストフレームワークでもあり動作は安定している.

本稿はRobotiumを導入したレポートである.

確認環境は次の通り.

  • Robotium: 5.2.1
  • Android Studio 1.0
  • Mac 10.9.5

環境準備

環境準備は次のコードをgradleに追加するのみで完了.

dependencies {
...
androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.2.1'
}

簡単. あとはテストコードを書いていく.

サンプルコード

RobotiumではメインとなるSoloクラスをsetUpで初期化する.
下記のコードはテスト開始時にMainActivityを起動し, テスト終了時にfinishさせる簡易なものである.

publicclassMainActivityTestextendsActivityInstrumentationTestCase2<MainActivity> {
private Solo solo = null;

publicMainActivityTest() {
super(MainActivity.class);
}

@Override
protectedvoidsetUp() throws Exception {
solo = new Solo(getInstrumentation(), getActivity());
super.setUp();
}

@Override
protectedvoidtearDown() throws Exception {
solo.finishOpenedActivities();
super.tearDown();
}

publicvoidtestMainActivity() {
// ここにシナリオを記述する
}
}

TestCaseのそれと同じく, testメソッドにシナリオを書いていく.
下記は次の手順をシナリオ化したもの.

  1. MainActivityが起動できているかを検査
  2. id.buttonをクリック
  3. ダイアログオープンをウェイト
  4. ダイアログに表示されているテキストを検査
  5. “Yes”を押下
  6. 表示されるToastに表示されている
publicvoidtestMainActivity() {
solo.assertCurrentActivity("wrong activity", MainActivity.class);
solo.waitForActivity(MainActivity.class);
solo.clickOnView(solo.getCurrentActivity().findViewById(R.id.button));
solo.waitForDialogToOpen();
Assert.assertTrue("wrong dialog text", solo.searchText("Test"));
solo.clickOnButton("Yes");
Assert.assertTrue("wrong toast text", solo.searchText("Hello!"));
}

RobotiumはInstrumentationTestCaseがベースであるため, Android Testing Frameworkのそれと同じように扱える.
普段通りAndroidTestとして実行すればRobotiumのテストが実行できる.

以上.

JDepends

$
0
0

はじめに.

Javaパッケージ単位でメトリクス計測するにはJDependが使える.
JDependは次のメトリクスを計測する.

  • 抽象クラスの数(AC: Abstract Classes)
  • 具象クラスの数(CC: Concrete Classes)
  • 1パッケージに依存する他パッケージの数(Ca: Afferent Couplings)
  • パッケージが依存する他パッケージの数(Ce: Efferent Couplings)
  • 抽象度合(A: Abstractness )
  • 不安定性(I: Instability)
  • 距離(D: Distance)

Afferent Couplings

Ca値. この値が大きいほど当該パッケージが他パッケージから参照されている.
Ca値の高いパッケージに対する変更は他パッケージへの変更波及性が高くなる傾向にある.

Efferent Couplings

Ce値. この値が大きいほど当該パッケージが他パッケージを参照している.
Ce値の高いパッケージは他パッケージの変更による影響を受けやすい傾向にある.

Abstractness

A値. 当該パッケージが内包する抽象クラスorインタフェースの度合い.
A = AC / (AC + CC)で求められる.
A値の高いパッケージは外部への変更波及性が小さくなる傾向にある.
もう1つの観点として, 当該パッケージのCa値が低い場合, 抽象度を高くする必要性は低いと言える.

Instability

I値. 当該パッケージの不安定度合い. 当該パッケージが変更を必要とされる頻度である.
I = Ce / (Ce + Ca)で求められる.
I値が大きい程, 他パッケージに依存しており, I値が低い程, 他パッケージから依存されていることを
意味する.
この値が大きい程, 外部の変更による影響を受けやすく, 当該パッケージも変更が必要となりやすい傾向にある.
この値が小さい程, 外部に与える影響が高いため当該パッケージの変更には注意する必要がある.

Distance

D値. 当該パッケージが他パッケージとどの程度隔離されているかの度合い.
D = abs((A + I) - 1)で求められる.
メトリクス計測ではこのD値が重要な指標となる.

いくつかのメトリクスを見てみる.

A = 0, I = 1, Ce = 8, Ca = 0
パッケージの抽象可はされていないものの, Caが0であるため変更波及性は低く, このパッケージは変更しやすい.
D値は0となり, パッケージの状態は良好といえる.

A = 0.4, I = 0.6, Ce = 3, Ca = 2
不安定性がやや高いものの, 抽象度合いも確保されているため, 外部に与える影響は少なく済む.
D値は0となり, パッケージの状態は良好といえる.

A = 0, I = 0.2, Ce = 1, Ca = 4
全く抽象化されていないパッケージ. Ca値が高く外部からの依存度合いも高い.
そのため, 当該パッケージを変更することによる変更波及性は高くなってしまう.
D値は0.8となり, パッケージの状態は悪いといえる.

A = 0.6, I = 1
当該パッケージは外部から依存されていないにも関わらず抽象度合が高いことを示す.
D値は0.6となり, パッケージの状態は改善の余地があるといえる.

一般的に, 依存されている度合い(Ca値)の高いパッケージは抽象度を高くする方が好まれる(.結果, D値が低くなる)

Gradle

apply plugin: 'jdepend'

task(jdepend, type: JDepend) {
classesDir = file('build/intermediates/classes/debug/')
reports {
xml.enabled false
text.enabled true
}
}

参考

JDependsExtension

Android: StethoでSQLite, Preferenceの中を覗く

$
0
0
StethoはAndroidアプリケーション用のデバックブリッジ.
Chrome Developer Toolsを使用してChrome Desktop Browserからリモートデバックを実現する.
ネットワークパフォーマンスの解析等を可能にするが, SQLiteやPreferenceの中を覗くこともできる.
今回はStethoを使っPreferenceを確認してみる.
http://facebook.github.io/stetho/

Gradleを編集

Stethoライブラリを導入するために下記をgradleに追加.
dependencies {
compile 'com.facebook.stetho:stetho:1.0.0'
}

Stethoの初期化

ApplicationクラスのonCreateで下記を実行.
publicclassMyApplicationextendsApplication {
publicvoidonCreate() {
super.onCreate();
Stetho.initialize(
Stetho.newInitializerBuilder(this)
.enableDumpapp(
Stetho.defaultDumperPluginsProvider(this))
.enableWebKitInspector(
Stetho.defaultInspectorModulesProvider(this))
.build());
}
}
あとはアプリを実行し, 端末とPCを接続.
PCのChromeブラウザからchrome://inspect/#devicesにアクセスし, デバッグ対象の端末のinspectを選択.
Developer Toolが起動するのでResources>Local Storageからアプリが持つPreferenceを確認・編集することができる.


以上.

Android: UIAutomator 2.0

$
0
0

はじめに.

2015.03.13, UIAutomator2.0のリリースアナウンスがあった.
We’re pleased to announce the release of UIAutomator 2.0! - Google+

UIAutomator2.0はAndroid Instrumentationベースに生まれ変わり, ./gradlew connectedCheckコマンドでテスト実行することができるようになった.

UIAutomator2.0はAndroid Testing Support Libraryにパッケージされた. UIAutomator2.0の導入にはSDK ManagerからAndroid Support Repositoryをダウンロードすること.

UIAutomatorはAndroid Developersサイトでも記載されている.
Testing Support Library - Android Developers

NOTE
類似のUI Testing Framework “Espresso”は1つのアプリに絞ったTesting Frameworkであるため, きめ細やかな制御が可能.
一方, “UI Automator”は複数のアプリを跨いだクロスアプリケーションテストが可能

UIAutomatorのAPI ReferenceおよびSample codeは下記.
- android.support.test - Android Developers
- googlesamples android-testing - GitHub

UIAutomatorは Requires Android 4.3 (API level 18) or higher.

準備

まずはbuild.gradleを編集する.

android {
defaultConfig {
minSdkVersion 18// Requires Android 4.3 (API level 18)
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
packagingOptions {
exclude 'LICENSE.txt'// Duplicate files copied
}
}

dependencies {
// Testing-only dependencies
androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
// UiAutomator Testing
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.0.0'
}

現状, そのままビルドするとLICENSE.txtの重複コピーでエラーが出るためpackagingOptionsを指定する. minSdkVersionの設定と必要なライブラリが揃えばandroidTestフォルダにTestCaseを持つクラスを追加する.
テストクラスのひな形は下記.

import android.support.test.filters.SdkSuppress;
import android.support.test.runner.AndroidJUnit4;

@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 18)
publicclassApplicationTest {

}

サンプルコードを参考にすればすぐにでもUIテストを開始できる.
下記はランチャーからテスト対象のアプリを起動するまでのSetup処理.

// Copyright 2015, The Android Open Source Project

@Before
publicvoidstartMainActivityFromHomeScreen() {
// Initialize UiDevice instance
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

// Start from the home screen
mDevice.pressHome();

// Wait for launcher
final String launcherPackage = getLauncherPackageName();
assertThat(launcherPackage, notNullValue());
mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT);

// Launch the blueprint app
Context context = InstrumentationRegistry.getContext();
final Intent intent = context.getPackageManager()
.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // Clear out any previous instances
context.startActivity(intent);

// Wait for the app to appear
mDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), LAUNCH_TIMEOUT);
}

APIs

UIAutomatorではデバイスへのファサードとしてUiDeviceクラスを定義している.
UiDeviceクラスを使えは次のことも実現できる.

  • Change the device rotation
  • Press a D-pad button
  • Press the Back, Home, or Menu buttons
  • Open the notification shade
  • Take a screenshot of the current window

UIAutomator APIには次のクラスが定義される.

  • UiCollection: Enumerates a container’s UI elements for the purpose of counting, or targeting sub-elements by their visible text or content-description property.
  • UiObject: Represents a UI element that is visible on the device.
  • UiScrollable: Provides support for searching for items in a scrollable UI container.
  • UiSelector: Represents a query for one or more target UI elements on a device.
  • Configurator: Allows you to set key parameters for running UI Automator tests.

これらを駆使してUIテストシナリオを作成していく.

以上.

Android : Deprecated HTTP Classes on Android5.1

$
0
0

Deprecated HTTP Classes on Android5.1

The org.apache.http classes and the AndroidHttpClient class have been deprecated in Android 5.1. These classes are no longer being maintained and you should migrate any app code using these APIs to the URLConnection classes as soon as possible.

org.apache.httpパッケージとAndroidHttpClientクラスはAndroid5.1で非推奨扱いとなる. 今後これらのクラスはメンテナンスされることがない. これらのAPIを使用しているアプリケーションはURLConnectionクラスへの変更が推奨される.

Deprecated APIs

org.apache.http.* と AndroidHttpClient

org.apache.http.impl.client.DefaultHttpClientとそのサブクラスであるAndroidHttpClientはWebブラウザ向けに最適化されたHTTPクライアントである. これらのAPIは巨大でフレキシブルなAPIを備えており安定した実装であるが, いくつかのバグを含んでいる.

巨大なAPIであるため互換性を維持しながら改善することが困難であり, AndroidチームはこれらのAPIを積極的に保守することをしていない.

今回, Android5.1のリリースを迎えてこれらのAPIは公式に保守されなく(Deprecatedと)なった.

HttpURLConnection

HttpURLConnection多くのアプリケーションに適応できる汎用かつ軽量なHTTPクライアントである. 軽量であるため保守性にも優れている. Android5.1で非推奨となったHttpClient系のかわりにこちらを使用すること.

HttpURLConnectionはAndroid Froyo以前で重大なバグを抱えている(Issue 2939).
ReadableなInputStreamからclose()を呼ぶとConnection poolを汚染することがある. Connection pooling を無効にしてこの問題を回避する方法は下記.

privatevoiddisableConnectionReuseIfNecessary() {
// HTTP connection reuse which was buggy pre-froyo
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
}

このバグはGingerbreadで改修されている.
さらにGingerbreadからtransparent response compressionに対応し, ICSからはResponse cacheに対応している.

以降はURLConnection系クラスのoverviewである.

URLConnection Class Overview

A connection to a URL for reading or writing. For HTTP connections, see HttpURLConnection for documentation of HTTP-specific features.
For example, to retrieve ftp://mirror.csclub.uwaterloo.ca/index.html:

読み書きのためURLへ接続する. HTTPコネクションはHTTP機能に特化したHttpURLConnectionを参照.
ftp://mirror.csclub.uwaterloo.ca/index.htmlを取得するサンプルは下記.

   URL url = new URL("ftp://mirror.csclub.uwaterloo.ca/index.html");
URLConnection urlConnection = url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
try {
readStream(in);
finally {
in.close();
}

URLConnection must be configured before it has connected to the remote resource. Instances of URLConnection are not reusable: you must use a different instance for each connection to a resource.

URLConnectionの設定はリモートリソースに接続する前に行うこと. URLConnectionのインスタンスは再利用できない. 異なるリソースへの接続は異なるインスタンスで行う事.

Timeouts

URLConnection supports two timeouts: a connect timeout and a read timeout. By default, operations never time out.

URLConnectionは接続タイムアウトとリードタイムアウトの2種類をサポートする. デフォルトでは操作でタイムアウトすることは無い.

Built-in Protocols

  • File
    Resources from the local file system can be loaded using file: URIs. File connections can only be used for input.

  • FTP
    File Transfer Protocol (RFC 959) is supported, but with no public subclass. FTP connections can be used for input or output but not both.
    By default, FTP connections will be made using anonymous as the username and the empty string as the password. Specify alternate usernames and passwords in the URL: ftp://username:password@host/path.

  • HTTP and HTTPS
    Refer to the HttpURLConnection and HttpsURLConnection subclasses.

  • Jar
    Refer to the JarURLConnection subclass.

  • File
    ローカルファイルシステムのリソースに対してはfile:スキームを使用する. File接続はinputのみ使用できる.

  • FTP
    File Transfer Protocol(RFC959)がサポートされているが, 公開されたサブクラスはない. FTPではinputかoutputの片方を使用することができ, 両方の使用はできない.

  • HTTP and HTTPS
    HttpURLConnectionとHttpsURLConnectionのサブクラスを参照.

  • Jar
    JarURLConnectionのサブクラスを参照.

Registering Additional Protocols

Use setURLStreamHandlerFactory(URLStreamHandlerFactory) to register handlers for other protocol types.

setURLStreamHandlerFactory(URLStreamHandlerFactory)を使い, 異なるプロトコル種別のハンドラを設定する.

HttpURLConnection Class Overview

An URLConnection for HTTP (RFC 2616) used to send and receive data over the web. Data may be of any type and length. This class may be used to send and receive streaming data whose length is not known in advance. Uses of this class follow a pattern:

URLConnectionはHTTP(RFC2616)を使用したWebを介したデータ送受信のために使用される. データの種類や長さは任意. このクラスは事前に長さが知らされていないストリーミングデータを受信するのにも使用できる.
このクラスの使用パターンは下記.

  1. Obtain a new HttpURLConnection by calling URL.openConnection() and casting the result to HttpURLConnection.
  2. Prepare the request. The primary property of a request is its URI. Request headers may also include metadata such as credentials, preferred content types, and session cookies.
  3. Optionally upload a request body. Instances must be configured with setDoOutput(true) if they include a request body. Transmit data by writing to the stream returned by getOutputStream().
  4. Read the response. Response headers typically include metadata such as the response body’s content type and length, modified dates and session cookies. The response body may be read from the stream returned by getInputStream(). If the response has no body, that method returns an empty stream.
  5. Disconnect. Once the response body has been read, the HttpURLConnection should be closed by calling disconnect(). Disconnecting releases the resources held by a connection so they may be closed or reused.
  1. 新しいHttpURLConnectionを取得する. URL.openConnection()を呼び, HttpURLConnectionにキャストする.

  2. リクエストを準備する. 主なプロパティはURIである. リクエストヘッダには認証情報, コンテンツ種別, セッションクッキーのメタデータが含まれる.

  3. 必要に応じてリクエストボディをアップロードする. リクエストボディを含めるにはsetDoOutput(true)を設定し, getOutputStream()で返却されるストリームにデータを書き込む.

  4. レスポンスを読み込む. レスポンスヘッダには一般的にレスポンスボディのコンテントタイプ, 長さ, 更新日とセッションクッキーといったメタデータが含まれる. レスポンスボディはgetInputStream()で取得できるストリームから読み込める. レスポンスにボディが含まれない場合, このメソッドは空のストリームを返す.

  5. コネクションの切断. レスポンスボディが読み込まれた後, HttpURLConnectiondisconnect()メソッドで閉じる必要がある. コネクションを切断する事で関連するリソースを開放し, コネクションが再利用できるようになる.

For example, to retrieve the webpage at http://www.android.com/:

   URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
readStream(in);
finally {
urlConnection.disconnect();
}

Secure Communication with HTTPS

Calling openConnection() on a URL with the “https” scheme will return an HttpsURLConnection, which allows for overriding the default HostnameVerifier and SSLSocketFactory. An application-supplied SSLSocketFactory created from an SSLContext can provide a custom X509TrustManager for verifying certificate chains and a custom X509KeyManager for supplying client certificates. See HttpsURLConnection for more details.

“https”スキーム付きのURLでopenConnection()を呼び出すとHttpsURLConnectionが返却される. これはデフォルトで使用されるHostnameVerifierとSSLSocketFactoryのオーバライドを可能にする.
SSLContextから生成されるアプリケーション提供のSSLSocketFactoryは, 証明書チェーンのためのカスタムX509TrustManagerと, クライアント証明書のためのカスタムX509KeyManagerを提供する.

Response Handling

HttpURLConnection will follow up to five HTTP redirects. It will follow redirects from one origin server to another. This implementation doesn’t follow redirects from HTTPS to HTTP or vice versa.
If the HTTP response indicates that an error occurred, getInputStream() will throw an IOException. Use getErrorStream() to read the error response. The headers can be read in the normal way using getHeaderFields(),

HttpURLConnectionは5回分のHTTPリダイレクトをフォローアップする. オリジンサーバから異なるサーバへのリダイレクトがフォローされる. この実装はHTTPsからHTTPへのリダイレクトやその逆はフォローされない. もしHTTPレスポンスがエラーを示す場合, getInputStream()がIOExceptionをスローする. getErrorStream()を使用してエラーレスポンスを読み込むことができる. 通常通りgetHeaderFields()でヘッダを読み込むことができる.

Posting Content

To upload data to a web server, configure the connection for output using setDoOutput(true).
For best performance, you should call either setFixedLengthStreamingMode(int) when the body length is known in advance, or setChunkedStreamingMode(int) when it is not. Otherwise HttpURLConnection will be forced to buffer the complete request body in memory before it is transmitted, wasting (and possibly exhausting) heap and increasing latency.

WebサーバにデータをアップロードするにはsetDoOutput(true)でコネクションを出力用に設定する. パフォーマンスのために, ボディの長さが判明している場合はsetFixedLengthStreamingMode(int)を設定する. そうでない場合ははsetChunkedStreamingMode(int)を設定する. そうでない場合HttpURLConnectionはリクエスト送信を終えるまでリクエストボディを全てメモリにバッファするためヒープと待ち時間をいたずらに消費する.

For example, to perform an upload:

   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
urlConnection.setDoOutput(true);
urlConnection.setChunkedStreamingMode(0);

OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
writeStream(out);

InputStream in = new BufferedInputStream(urlConnection.getInputStream());
readStream(in);
finally {
urlConnection.disconnect();
}
}

Performance

The input and output streams returned by this class are not buffered. Most callers should wrap the returned streams with BufferedInputStream or BufferedOutputStream. Callers that do only bulk reads or writes may omit buffering.
When transferring large amounts of data to or from a server, use streams to limit how much data is in memory at once. Unless you need the entire body to be in memory at once, process it as a stream (rather than storing the complete body as a single byte array or string).

URLConnectionクラスはバッファされないinput / output streamを返す. 多くの場合これらをBufferedInputStream / BufferedOutputStreamでラップする. もし一度にまとめて読み書きしたい場合にはバッファリングは省略されるだろう.
サーバへ/から巨大なデータを転送する場合, 確保必要なメモリ容量を抑えるためにstreamは使用される. もしボディーの情報を全てメモリ上に展開してバイト配列や文字列として扱う
必要でも無い限りstreamを使用すること.

To reduce latency, this class may reuse the same underlying Socket for multiple request/response pairs. As a result, HTTP connections may be held open longer than necessary. Calls to disconnect() may return the socket to a pool of connected sockets. This behavior can be disabled by setting the http.keepAlive system property to false before issuing any HTTP requests. The http.maxConnections property may be used to control how many idle connections to each server will be held.

待ち時間を短縮するために, このクラスは対となる複数の要求/応答に同じSocketを使用する.
しかし, この結果HTTPコネクションは必要以上に保持される.
disconnect()を呼ぶと接続済SocketプールにSocketが返却される. この振る舞いはHTTPリクエストの開始より前にシステムプロパティhttp.keepAliveをfalseに設定することで無効化できる. http.maxConnectionsプロパティは各サーバ毎にどれだけのidleコネクションを保持させるかを制御する.

By default, this implementation of HttpURLConnection requests that servers use gzip compression. Since getContentLength() returns the number of bytes transmitted, you cannot use that method to predict how many bytes can be read from getInputStream(). Instead, read that stream until it is exhausted: when read() returns -1. Gzip compression can be disabled by setting the acceptable encodings in the request header:

HttpURLConnectionの標準実装では, サーバがgzip圧縮を使用するリクエストを投げる. getContentLength()は送信されたバイト数を返却するため, getInputStream()でどれだけのバイトが読み込まれるかを予測するためにこの数字を使用することはできない. かわりに, streamのread()が-1を返すまで読み続ける. Gzip圧縮はリクエストヘッダのAccept-Encodingで無効化することができる.

urlConnection.setRequestProperty("Accept-Encoding", "identity");

Handling Network Sign-On

Some Wi-Fi networks block Internet access until the user clicks through a sign-on page. Such sign-on pages are typically presented by using HTTP redirects. You can use getURL() to test if your connection has been unexpectedly redirected. This check is not valid until after the response headers have been received, which you can trigger by calling getHeaderFields() or getInputStream(). For example, to check that a response was not redirected to an unexpected host:

いくつかのWi-Fiネットワークはユーザのサインオンページを経由してインターネットにアクセスする. このようなサインオンページは通常HTTPリダイレクトを使用して提供される.
getURL()を使用することで期待しないリダイレクトによる接続であるかをテストできる. このチェックはレスポンスヘッダの受信後では有効ではない. getHeaderFields()getInputStream()を呼び出す際にトリガーすることができる. 次のコードは期待しないホストへリダイレクトされていないことをチェックするものである.

   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
if (!url.getHost().equals(urlConnection.getURL().getHost())) {
// we were redirected! Kick the user out to the browser to sign on?

...
} finally {
urlConnection.disconnect();
}

HTTP Authentication

HttpURLConnection supports HTTP basic authentication. Use Authenticator to set the VM-wide authentication handler:

HttpURLConnectionはHTTPベーシック認証をサポートする. VM全体で使う認証ハンドラにAuthenticator
を設定するには次,

   Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
returnnew PasswordAuthentication(username, password.toCharArray());

});
}

Unless paired with HTTPS, this is not a secure mechanism for user authentication. In particular, the username, password, request and response are all transmitted over the network without encryption.

これはHTTPSで使用されない限りセキュアでないユーザ認証である. ユーザ名, パスワードや要求/応答は暗号化されずにネットワークを介してデータ送信される.

Sessions with Cookies

To establish and maintain a potentially long-lived session between client and server, HttpURLConnection includes an extensible cookie manager. Enable VM-wide cookie management using CookieHandler and CookieManager:

クライアントとサーバ間の潜在的なセッションを長時間確立するため, HttpURLConnectionは拡張可能なcookie managerを包含している. CookieHandlerとCookieManagerを使ってVM全体のCookie管理を有効にする.

   CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);

By default, CookieManager accepts cookies from the origin server only. Two other policies are included: ACCEPT_ALL and ACCEPT_NONE. Implement CookiePolicy to define a custom policy.
The default CookieManager keeps all accepted cookies in memory. It will forget these cookies when the VM exits. Implement CookieStore to define a custom cookie store.

標準で, CookieManagerはorigin serverからのみcookieを受け入れる. 異なる2つのポリシーとして, ACCEPT_ALLACCEPT_NONEが用意されている. カスタムポリシーを定義するためにはCookiePolicyを実装する. デフォルトのCookieManagerは記憶された受け入れcookieを全て保持する. VMが終了するとこれらのcookieは忘れられる. カスタムcookieを記録するにはCookieStoreを実装する.

In addition to the cookies set by HTTP responses, you may set cookies programmatically. To be included in HTTP request headers, cookies must have the domain and path properties set.
By default, new instances of HttpCookie work only with servers that support RFC 2965 cookies. Many web servers support only the older specification, RFC 2109. For compatibility with the most web servers, set the cookie version to 0.

HTTPレスポンスで設定されるcookieの他に, プログラムでcookieを設定することができる. HTTPリクエストヘッダに含まれるようにcookieが設定されているドメインとパスのプロパティを設定する.

For example, to receive www.twitter.com in French:

フランス語でwww.twitter.comを受信する例は以下の通り。

   HttpCookie cookie = new HttpCookie("lang", "fr");
cookie.setDomain("twitter.com");
cookie.setPath("/");
cookie.setVersion(0);
cookieManager.getCookieStore().add(new URI("http://twitter.com/"), cookie);

HTTP Methods

HttpURLConnection uses the GET method by default. It will use POST if setDoOutput(true) has been called. Other HTTP methods (OPTIONS, HEAD, PUT, DELETE and TRACE) can be used with setRequestMethod(String).

HttpURLConnectionは標準でGETメソッドを使用する. POSTメソッドを使うにはsetDoOutput(true)を使用する. 他のHTTPメソッド(OPTIONS, HEAD, PUT, DELETE, TRACE)はsetRequestMethod(String)を使用する.

Proxies

By default, this class will connect directly to the origin server. It can also connect via an HTTP or SOCKS proxy. To use a proxy, use URL.openConnection(Proxy) when creating the connection.

標準でこのクラスはorigin serverへ直接接続する. これはHTTPかSOCKS proxy経由で接続することができる. Proxyを使用するにはコネクションを生成するのにURL.openConnection(Proxy)を使用する.

IPv6 Support

This class includes transparent support for IPv6. For hosts with both IPv4 and IPv6 addresses, it will attempt to connect to each of a host’s addresses until a connection is established.

このクラスはIPv6をサポートする. ホストがIPv4とIPv6両方をサポートする場合, 接続が確立されるまで両方での接続を試みます.

Response Caching

Android 4.0 (Ice Cream Sandwich, API level 15) includes a response cache. See android.net.http.HttpResponseCache for instructions on enabling HTTP caching in your application.

Android4.0でresponse cacheが追加された. アプリケーションでHTTPキャッシングを有効にする方法についてはandroid.net.http.HttpResponseCacheを参照.

Avoiding Bugs In Earlier Releases

Prior to Android 2.2 (Froyo), this class had some frustrating bugs. In particular, calling close() on a readable InputStream could poison the connection pool. Work around this by disabling connection pooling:

Android2.2以前, このクラスにはイライラするバグを抱えている. 具体的にはreadableなInputStreamでclose()を呼んだ時コネクションプールを汚染するというものである. コネクションプーリングを無効化することでこの問題を回避できる.

privatevoiddisableConnectionReuseIfNecessary() {
// Work around pre-Froyo bugs in HTTP connection reuse.
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
}

Each instance of HttpURLConnection may be used for one request/response pair. Instances of this class are not thread safe.

HttpURLConnectionのインスタンスは要求/応答のペアに対して1つ使用できる. このクラスはスレッドセーフではない.

HttpsURLConnection Class Overview

An HttpURLConnection for HTTPS (RFC 2818). A connected HttpsURLConnection allows access to the negotiated cipher suite, the server certificate chain, and the client certificate chain if any.

HTTPS(RFC2818)のためのHttpURLConnection. HttpsURLConnectionによる接続はChiperスイートによるネゴシエーション, サーバ証明書チェーン, クライアント証明書チェーンがある場合にアクセスを可能とする.

Providing an application specific X509TrustManager

If an application wants to trust Certificate Authority (CA) certificates that are not part of the system, it should specify its own X509TrustManager via a SSLSocketFactory set on the HttpsURLConnection. The X509TrustManager can be created based on a KeyStore using a TrustManagerFactory to supply trusted CA certificates. Note that self-signed certificates are effectively their own CA and can be trusted by including them in a KeyStore.
For example, to trust a set of certificates specified by a KeyStore:

アプリケーションがシステムの一部ではないCA証明書を信頼したい場合, HttpsURLConnectionでSSLSocketFactoryを介して独自のX509TrustManagerを設定する.

   KeyStore keyStore = ...;
String algorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
tmf.init(keyStore);

SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);

URL url = new URL("https://www.example.com/");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();

It is possible to implement X509TrustManager directly instead of using one created by a TrustManagerFactory. While this is straightforward in the insecure case of allowing all certificate chains to pass verification, writing a proper implementation will usually want to take advantage of CertPathValidator. In general, it might be better to write a custom KeyStore implementation to pass to the TrustManagerFactory than to try and write a custom X509TrustManager.

TrustManagerFactoryによって生成されたものではなく, 直接X509TrustManagerを実装することができる. 全ての証明書チェーンが検証をパスしないと安全でないような簡単なケースで実装にはCertPathValidatorを使用したいと考えるだろう. 一般的にカスタムされたX509TrustManagerを実装するよりはTrustManagerFactoryにカスタムKeyStoreを渡すほうが良い方法となる.

Providing an application specific X509KeyManager

A custom X509KeyManager can be used to supply a client certificate and its associated private key to authenticate a connection to the server. The X509KeyManager can be created based on a KeyStore using a KeyManagerFactory.
For example, to supply client certificates from a KeyStore:

カスタムされたX509KeyManagerはクライアント証明書と秘密鍵で関連づけられたサーバへの接続の認証に使用できる. X509KeyManagerはKeyManagerFactoryを使用してKeyStoreを基に作成できる.

   KeyStore keyStore = ...;
String algorithm = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
kmf.init(keyStore);

SSLContext context = SSLContext.getInstance("TLS");
context.init(kmf.getKeyManagers(), null, null);

URL url = new URL("https://www.example.com/");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();

A X509KeyManager can also be implemented directly. This can allow an application to return a certificate and private key from a non-KeyStore source or to specify its own logic for selecting a specific credential to use when many may be present in a single KeyStore.

X509KeyManagerは直接実装できる. これはアプリケーションにKeyStoreをソースとしない秘密鍵と証明書を返却させるか, 多くは1つのKeyStoreに存在する特定の証明書を選択する独自ロジックを実装する.

TLS Intolerance Support

This class attempts to create secure connections using common TLS extensions and SSL deflate compression. Should that fail, the connection will be retried with SSLv3 only.

このクラスは一般的なTLS拡張とSSL deflate圧縮を使用したセキュアなコネクションを生成する. 接続が失敗した際にはSSLv3での再接続を試みる.

APIs

参考

License:
Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

Viewing all 146 articles
Browse latest View live