Служба Restful API

Я ищу, чтобы сделать сервис, который я могу использовать для звонков в веб-REST API.

В принципе, я хочу запустить службу в приложении init, тогда я хочу попросить эту службу запросить URL-адрес и вернуть результаты. Тем временем я хочу показать окно прогресса или что-то подобное.

Я создал службу в настоящее время, которая использует IDL, я где-то читал, что вам действительно нужно это только для общения через приложение, поэтому подумайте, что это нужно, но не знаете, как делать обратные вызовы без него. Кроме того, когда я попал в post(Config.getURL("login"), values) приложение, похоже, некоторое время приостанавливается (кажется странным – мысль о том, что служба была в том, что она работает в другом потоке!)

В настоящее время у меня есть служба с сообщением и методы http внутри, несколько файлов AIDL (для двусторонней связи), ServiceManager, который занимается запуском, остановкой, привязкой и т. Д. К службе, и я динамически создаю обработчик с определенным кодом Для обратных вызовов по мере необходимости.

Я не хочу, чтобы кто-нибудь дал мне полную базу кода, над которой можно было бы работать, но некоторые указатели будут очень благодарны.

Код в (в основном) полный:

 public class RestfulAPIService extends Service { final RemoteCallbackList<IRemoteServiceCallback> mCallbacks = new RemoteCallbackList<IRemoteServiceCallback>(); public void onStart(Intent intent, int startId) { super.onStart(intent, startId); } public IBinder onBind(Intent intent) { return binder; } public void onCreate() { super.onCreate(); } public void onDestroy() { super.onDestroy(); mCallbacks.kill(); } private final IRestfulService.Stub binder = new IRestfulService.Stub() { public void doLogin(String username, String password) { Message msg = new Message(); Bundle data = new Bundle(); HashMap<String, String> values = new HashMap<String, String>(); values.put("username", username); values.put("password", password); String result = post(Config.getURL("login"), values); data.putString("response", result); msg.setData(data); msg.what = Config.ACTION_LOGIN; mHandler.sendMessage(msg); } public void registerCallback(IRemoteServiceCallback cb) { if (cb != null) mCallbacks.register(cb); } }; private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { // Broadcast to all clients the new value. final int N = mCallbacks.beginBroadcast(); for (int i = 0; i < N; i++) { try { switch (msg.what) { case Config.ACTION_LOGIN: mCallbacks.getBroadcastItem(i).userLogIn( msg.getData().getString("response")); break; default: super.handleMessage(msg); return; } } catch (RemoteException e) { } } mCallbacks.finishBroadcast(); } public String post(String url, HashMap<String, String> namePairs) {...} public String get(String url) {...} }; 

Несколько файлов AIDL:

 package com.something.android oneway interface IRemoteServiceCallback { void userLogIn(String result); } 

а также

 package com.something.android import com.something.android.IRemoteServiceCallback; interface IRestfulService { void doLogin(in String username, in String password); void registerCallback(IRemoteServiceCallback cb); } 

И сервис-менеджер:

 public class ServiceManager { final RemoteCallbackList<IRemoteServiceCallback> mCallbacks = new RemoteCallbackList<IRemoteServiceCallback>(); public IRestfulService restfulService; private RestfulServiceConnection conn; private boolean started = false; private Context context; public ServiceManager(Context context) { this.context = context; } public void startService() { if (started) { Toast.makeText(context, "Service already started", Toast.LENGTH_SHORT).show(); } else { Intent i = new Intent(); i.setClassName("com.something.android", "com.something.android.RestfulAPIService"); context.startService(i); started = true; } } public void stopService() { if (!started) { Toast.makeText(context, "Service not yet started", Toast.LENGTH_SHORT).show(); } else { Intent i = new Intent(); i.setClassName("com.something.android", "com.something.android.RestfulAPIService"); context.stopService(i); started = false; } } public void bindService() { if (conn == null) { conn = new RestfulServiceConnection(); Intent i = new Intent(); i.setClassName("com.something.android", "com.something.android.RestfulAPIService"); context.bindService(i, conn, Context.BIND_AUTO_CREATE); } else { Toast.makeText(context, "Cannot bind - service already bound", Toast.LENGTH_SHORT).show(); } } protected void destroy() { releaseService(); } private void releaseService() { if (conn != null) { context.unbindService(conn); conn = null; Log.d(LOG_TAG, "unbindService()"); } else { Toast.makeText(context, "Cannot unbind - service not bound", Toast.LENGTH_SHORT).show(); } } class RestfulServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName className, IBinder boundService) { restfulService = IRestfulService.Stub.asInterface((IBinder) boundService); try { restfulService.registerCallback(mCallback); } catch (RemoteException e) {} } public void onServiceDisconnected(ComponentName className) { restfulService = null; } }; private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() { public void userLogIn(String result) throws RemoteException { mHandler.sendMessage(mHandler.obtainMessage(Config.ACTION_LOGIN, result)); } }; private Handler mHandler; public void setHandler(Handler handler) { mHandler = handler; } } 

Сервис init и bind:

 // this I'm calling on app onCreate servicemanager = new ServiceManager(this); servicemanager.startService(); servicemanager.bindService(); application = (ApplicationState)this.getApplication(); application.setServiceManager(servicemanager); 

Вызов сервисной функции:

 // this lot i'm calling as required - in this example for login progressDialog = new ProgressDialog(Login.this); progressDialog.setMessage("Logging you in..."); progressDialog.show(); application = (ApplicationState) getApplication(); servicemanager = application.getServiceManager(); servicemanager.setHandler(mHandler); try { servicemanager.restfulService.doLogin(args[0], args[1]); } catch (RemoteException e) { e.printStackTrace(); } ...later in the same file... Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case Config.ACTION_LOGIN: if (progressDialog.isShowing()) { progressDialog.dismiss(); } try { ...process login results... } } catch (JSONException e) { Log.e("JSON", "There was an error parsing the JSON", e); } break; default: super.handleMessage(msg); } } }; 

Solutions Collecting From Web of "Служба Restful API"

Если ваша служба будет частью вашего приложения, вы сделаете ее более сложной, чем она должна быть. Поскольку у вас есть простой пример получения некоторых данных из веб-службы RESTful, вы должны изучить ResultReceiver и IntentService .

Этот шаблон Service + ResultReceiver работает путем запуска или привязки к службе с помощью startService (), когда вы хотите выполнить какое-либо действие. Вы можете указать операцию для выполнения и передачи в свой ResultReceiver (активность) через дополнительные функции в намерении.

В сервисе, который вы реализуете onHandleIntent, выполните операцию, указанную в Intent. Когда операция завершена, вы используете переданный в ResultReceiver, чтобы отправить сообщение обратно в Activity, в который будет вызываться onReceiveResult .

Например, вы хотите извлечь некоторые данные из своей веб-службы.

  1. Вы создаете намерение и вызываете startService.
  2. Операция в службе начинается, и она отправляет в действие сообщение с сообщением о начале
  3. Активность обрабатывает сообщение и показывает прогресс.
  4. Служба завершает операцию и отправляет некоторые данные обратно в вашу деятельность.
  5. Ваша деятельность обрабатывает данные и помещается в виде списка
  6. Служба отправляет вам сообщение о том, что оно сделано, и оно убивает себя.
  7. Действие получает сообщение завершения и скрывает диалог выполнения.

Я знаю, что вы упомянули, что вам не нужна база кода, но приложение с открытым исходным кодом Google I / O 2010 использует сервис таким образом, о котором я рассказываю.

Обновлено, чтобы добавить пример кода:

Активность.

 public class HomeActivity extends Activity implements MyResultReceiver.Receiver { public MyResultReceiver mReceiver; public void onCreate(Bundle savedInstanceState) { mReceiver = new MyResultReceiver(new Handler()); mReceiver.setReceiver(this); ... final Intent intent = new Intent(Intent.ACTION_SYNC, null, this, QueryService.class); intent.putExtra("receiver", mReceiver); intent.putExtra("command", "query"); startService(intent); } public void onPause() { mReceiver.setReceiver(null); // clear receiver so no leaks. } public void onReceiveResult(int resultCode, Bundle resultData) { switch (resultCode) { case RUNNING: //show progress break; case FINISHED: List results = resultData.getParcelableList("results"); // do something interesting // hide progress break; case ERROR: // handle the error; break; } } 

Обслуживание:

 public class QueryService extends IntentService { protected void onHandleIntent(Intent intent) { final ResultReceiver receiver = intent.getParcelableExtra("receiver"); String command = intent.getStringExtra("command"); Bundle b = new Bundle(); if(command.equals("query") { receiver.send(STATUS_RUNNING, Bundle.EMPTY); try { // get some data or something b.putParcelableArrayList("results", results); receiver.send(STATUS_FINISHED, b) } catch(Exception e) { b.putString(Intent.EXTRA_TEXT, e.toString()); receiver.send(STATUS_ERROR, b); } } } } 

Расширение ResultReceiver – изменено для реализации MyResultReceiver.Receiver

 public class MyResultReceiver implements ResultReceiver { private Receiver mReceiver; public MyResultReceiver(Handler handler) { super(handler); } public void setReceiver(Receiver receiver) { mReceiver = receiver; } public interface Receiver { public void onReceiveResult(int resultCode, Bundle resultData); } @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (mReceiver != null) { mReceiver.onReceiveResult(resultCode, resultData); } } } 

Кроме того, когда я попал в сообщение (Config.getURL («login»), значения), приложение, похоже, некоторое время приостанавливается (кажется странным – мысль о том, что служба была в том, что она работает в другом потоке!)

Нет, вам нужно создать поток самостоятельно, по умолчанию работает локальная служба в потоке пользовательского интерфейса.

Разработка клиентских приложений REST для Android была для меня огромным ресурсом. Динамик не показывает никакого кода, он просто рассматривает конструктивные соображения и методы для создания солидного Rest Api в андроиде. Если ваш подкаст какой-то человек или нет, я бы рекомендовал дать ему хотя бы одно прослушивание, но лично я слушал его как 4 или 5 раз, и, вероятно, я снова его послушаю.

Разработка клиентских приложений Android REST
Автор: Вергилий Добжанский
Описание:

На этом сеансе будут представлены архитектурные соображения для разработки приложений RESTful на платформе Android. Он фокусируется на шаблонах проектирования, интеграции платформы и производительности, характерных для платформы Android.

И есть так много соображений, которые я действительно не сделал в первой версии моего api, что мне пришлось реорганизовать

Я знаю, что @Martyn не хочет полного кода, но я думаю, что это аннотирование полезно для этого вопроса:

10 приложений с открытым исходным кодом для Android, которые каждый разработчик Android должен изучить

Foursquared для Android является открытым исходным кодом и имеет интересный шаблон кода, взаимодействующий с API REST с четырьмя запросами.

Просто хотел указать всех вас в сторону отдельного класса, который я прокатил, который включает в себя все функциональные возможности.

http://github.com/StlTenny/RestService

Он выполняет запрос как неблокирующий и возвращает результаты в простой обработчик. Даже поставляется с примером реализации.

Я бы очень рекомендовал REST-клиент Retrofit .

Я нашел это хорошо написанное сообщение в блоге чрезвычайно полезным, оно также содержит простой пример кода. Автор использует Retrofit, чтобы сетевые вызовы и Отто реализовали шаблон шины данных:

http://www.mdswanson.com/blog/2014/04/07/durable-android-rest-clients.html

Допустим, я хочу запустить сервис в событии – onItemClicked () кнопки. Механизм приемника не будет работать в этом случае, потому что: –
A) Я передал приемник на службу (как и в Intent extra) из onItemClicked ()
Б) Действие перемещается на задний план. В onPause () я установил ссылку получателя в ResultReceiver равным null, чтобы избежать утечки Activity.
C) Активность уничтожается.
D) Активность снова создается. Однако на данный момент Служба не сможет выполнить обратный вызов для Activity, поскольку эта информация приемника потеряна.
Механизм ограниченного вещания или PendingIntent представляется более полезным в таких сценариях – см. « Уведомлять активность из службы»

Обратите внимание, что решения от Robby Pond так или иначе не хватает: таким образом вы разрешаете только один вызов api за раз, поскольку IntentService обрабатывает только одно намерение за раз. Часто вы хотите выполнять параллельные вызовы api. Если вы хотите сделать это, вам нужно расширить Service вместо IntentService и создать свой собственный поток.

Кроме того, когда я попал в сообщение (Config.getURL («login»), значения), приложение, похоже, некоторое время приостанавливается (кажется странным – мысль о том, что служба была в том, что она работает в другом потоке!)

В этом случае лучше использовать asynctask, которая работает в другом потоке и возвращает результат обратно в поток ui при завершении.

Здесь есть и другой подход, который в основном помогает забыть обо всем управлении запросами. Он основан на методе асинхронной очереди и ответе на вызов / обратный вызов. Главное преимущество заключается в том, что с помощью этого метода вы сможете полностью обработать весь процесс (запрос, получить и проанализировать ответ, sabe to db). Как только вы получите код ответа, работа уже выполнена. После этого вам просто нужно позвонить в свой db, и все готово. Это также помогает с проблемой того, что происходит, когда ваша деятельность неактивна. Что будет здесь, так это то, что все ваши данные будут сохранены в локальной базе данных, но ответ не будет обработан вашей деятельностью, это идеальный способ.

Я написал об общем подходе здесь http://ugiagonzalez.com/2012/07/02/theres-life-after-asynctasks-in-android/

Я буду размещать конкретный образец кода в следующих сообщениях. Надеюсь, что это поможет, не стесняйтесь обращаться ко мне за разделение подхода и решение потенциальных проблем или проблем.

Робби дает отличный ответ, хотя я вижу, что вы все еще ищете дополнительную информацию. Я реализовал REST api – это простой, но неправильный способ. Только после просмотра этого видео ввода-вывода Google я понял, где я ошибся. Это не так просто, как собрать AsyncTask с вызовом get / put HttpUrlConnection.