Короткий ответ, если вы нацеливаетесь на уровень API 7, «Не надо».Ситуация, возможно, улучшилась в более поздних API, но как это было ... Я настоятельно рекомендовал бы полностью избегать SyncAdapter;он очень плохо документирован, и «автоматическое» управление учетными записями / аутентификацией обходится дорого, поскольку API для него также сложен и недостаточно документирован.Эта часть API не была продумана за пределами самых тривиальных вариантов использования.
Итак, вот схема, с которой я закончил.Внутри моей деятельности у меня был обработчик с простым добавлением из пользовательского суперкласса Handler (можно было проверить m_bStopped
bool):
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 (что я бы порекомендовал).В большинстве видов деятельности я бы вызывал mHandler.stopHandler();
в onPause()
и mHandler.startHandler();
в onResume()
, чтобы избежать возврата HTTP-ответа на неактивное действие и т. Д. Это оказалось довольно надежным подходом.
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
очень полезен при построении неуклюжих запросов XML, требуемыхAPI REST, с которым мне пришлось интегрироваться, например, в 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
, который используется для отправки результатов обратно в ResponseHandler
I, описанный выше.syncResult
- это параметр out, используемый SyncAdapter для экспоненциального отката и т. Д. Я использую его в executeRequest()
, увеличивая количество ошибок и т. Д. Опять же, очень плохо документировано и PITA работает.parseXML()
использует превосходный Simple XML lib .
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))
{
...
}
...
}
Вы должны установить некоторые тайм-ауты для HTTP-запросов, чтобы приложение не ожидало вечно, если мобильные данные выпадают, илион переключается с Wi-Fi на 3G.Это вызовет исключение, если произойдет тайм-аут.
// 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 просто потрясающий.Я бы использовал класс AsyncTask сейчас вместо того, чтобы создавать свои собственные потоки, как я делал выше, для порождения HTTP-запросов.
Надеюсь, это бессвязное объяснение кому-нибудь немного поможет.