簡単な答えは、〜APIレベル7をターゲットにしている場合、「しない」です。状況は後のAPIで改善された可能性がありますが、そうであったように...SyncAdapterを完全に回避することを強くお勧めします。文書化が非常に不十分であり、「自動」アカウント/認証管理は、そのAPIも複雑で文書化が不十分であるため、高額になります。APIのこの部分は、最も些細なユースケースを超えて考え抜かれていません。
これが私が最終的に使用したパターンです。私のアクティビティの中には、カスタムHandlerスーパークラスからの単純な追加を含むハンドラーがありました(m_bStopped
ブール値をチェックできます):
private ResponseHandler mHandler = new ResponseHandler();
class ResponseHandler extends StopableHandler {
@Override
public void handleMessage(Message msg) {
if (isStopped()) {
return;
}
if (msg.what == WebAPIClient.GET_PLANS_RESPONSE) {
...
}
...
}
}
アクティビティは、以下に示すようにRESTリクエストを呼び出します。ハンドラーはWebClientクラス(HTTPリクエストなどを構築/作成するためのヘルパークラス)に渡されることに注意してください。WebClientは、アクティビティにメッセージを返すHTTP応答を受信するときにこのハンドラーを使用し、データが受信され、私の場合はSQLiteデータベースに保存されたことを通知します(これをお勧めします)。ほとんどのアクティビティでは、HTTP応答が非アクティブなアクティビティなどにシグナルで返されるのを避けるために、呼び出しと呼び出しを行います。これは、非常に堅牢なアプローチであることがわかりましたmHandler.stopHandler();
。onPause()
mHandler.startHandler();
onResume()
final Bundle bundle = new Bundle();
bundle.putBoolean(WebAPIRequestHelper.REQUEST_CREATESIMKITORDER, true);
bundle.putString(WebAPIRequestHelper.REQUEST_PARAM_KIT_TYPE, sCVN);
final Runnable runnable = new Runnable() { public void run() {
VendApplication.getWebClient().processRequest(null, bundle, null, null, null,
mHandler, NewAccountActivity.this);
}};
mRequestThread = Utils.performOnBackgroundThread(runnable);
Handler.handleMessage()
メインスレッドで呼び出されます。したがって、ここで進行状況ダイアログを停止して、他のアクティビティを安全に実行できます。
ContentProviderを宣言しました:
<provider android:name="au.com.myproj.android.app.webapi.WebAPIProvider"
android:authorities="au.com.myproj.android.app.provider.webapiprovider"
android:syncable="true" />
そして、SQLiteデータベースへのアクセスを作成および管理するためにそれを実装しました:
public class WebAPIProvider extends ContentProvider
したがって、次のように、アクティビティのデータベースにカーソルを合わせることができます。
mCursor = this.getContentResolver().query (
WebAPIProvider.PRODUCTS_URI, null,
Utils.getProductsWhereClause(this), null,
Utils.getProductsOrderClause(this));
startManagingCursor(mCursor);
このorg.apache.commons.lang3.text.StrSubstitutor
クラスは、REST APIに必要な不器用なXMLリクエストを作成するのに非常に役立つことがわかりました。たとえば、WebAPIRequestHelper
次のようなヘルパーメソッドがあります。
public static String makeAuthenticateQueryString(Bundle params)
{
Map<String, String> valuesMap = new HashMap<String, String>();
checkRequiredParam("makeAuthenticateQueryString()", params, REQUEST_PARAM_ACCOUNTNUMBER);
checkRequiredParam("makeAuthenticateQueryString()", params, REQUEST_PARAM_ACCOUNTPASSWORD);
valuesMap.put(REQUEST_PARAM_APIUSERNAME, API_USERNAME);
valuesMap.put(REQUEST_PARAM_ACCOUNTNUMBER, params.getString(REQUEST_PARAM_ACCOUNTNUMBER));
valuesMap.put(REQUEST_PARAM_ACCOUNTPASSWORD, params.getString(REQUEST_PARAM_ACCOUNTPASSWORD));
String xmlTemplate = VendApplication.getContext().getString(R.string.XMLREQUEST_AUTHENTICATE_ACCOUNT);
StrSubstitutor sub = new StrSubstitutor(valuesMap);
return sub.replace(xmlTemplate);
}
これを適切なエンドポイントURLに追加します。
WebClientクラスがHTTPリクエストを実行する方法の詳細は次のとおりです。これはprocessRequest()
、Runnableで以前に呼び出されたメソッドです。上記handler
のIに結果をメッセージで返すために使用されるパラメーターに注意してください。ResponseHandler
SyncAdaptersyncResult
が指数バックオフなどを行うために使用するisinoutパラメーター。executeRequest()
さまざまなエラーカウントなどをインクリメントして、で使用します。繰り返しになりますが、文書化が非常に不十分で、PITAが機能します。優れたSimpleXMLlibparseXML()
を活用します。
public synchronized void processRequest(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult, Handler handler, Context context)
{
// Helper to construct the query string from the query params passed in the extras Bundle.
HttpUriRequest request = createHTTPRequest(extras);
// Helper to perform the HTTP request using org.apache.http.impl.client.DefaultHttpClient.
InputStream instream = executeRequest(request, syncResult);
/*
* Process the result.
*/
if(extras.containsKey(WebAPIRequestHelper.REQUEST_GETBALANCE))
{
GetServiceBalanceResponse xmlDoc = parseXML(GetServiceBalanceResponse.class, instream, syncResult);
Assert.assertNotNull(handler);
Message m = handler.obtainMessage(WebAPIClient.GET_BALANCE_RESPONSE, xmlDoc);
m.sendToTarget();
}
else if(extras.containsKey(WebAPIRequestHelper.REQUEST_GETACCOUNTINFO))
{
...
}
...
}
モバイルデータがドロップアウトした場合、またはWifiから3Gに切り替わった場合にアプリが永久に待機しないように、HTTPリクエストにタイムアウトを設定する必要があります。これにより、タイムアウトが発生した場合に例外がスローされます。
// Set the timeout in milliseconds until a connection is established.
int timeoutConnection = 30000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT) in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 30000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
HttpClient client = new DefaultHttpClient(httpParameters);
したがって、全体として、SyncAdapterとAccountsは非常に苦痛であり、利益が得られないために多くの時間を費やしました。ContentProviderは、主にカーソルとトランザクションのサポートに非常に役立ちました。SQLiteデータベースは本当に良かった。そして、Handlerクラスは素晴らしいです。上記のように独自のスレッドを作成してHTTPリクエストを生成する代わりに、AsyncTaskクラスを使用します。
このとりとめのない説明が誰かに少し役立つことを願っています。