我正在寻找一个可以用来调用基于Web的REST API的服务.
基本上我想在app init上启动服务然后我希望能够要求该服务请求URL并返回结果.与此同时,我希望能够显示进度窗口或类似的东西.
我已经创建了一个目前使用IDL的服务,我已经阅读过你只需要这个用于跨应用程序通信的地方,所以请考虑这些需求,但不确定如何在没有它的情况下进行回调.此外,当我点击post(Config.getURL("login"), values)
应用程序似乎暂停一段时间(似乎很奇怪 - 认为服务背后的想法是它运行在不同的线程!)
目前我有一个带post的服务,里面有http方法,一些AIDL文件(用于双向通信),一个ServiceManager,它处理启动,停止,绑定等服务,我正在动态创建一个具有特定代码的Handler根据需要进行回调.
我不希望任何人给我一个完整的代码库来工作,但一些指针将不胜感激.
代码(大部分)已满:
public class RestfulAPIService extends Service { final RemoteCallbackListmCallbacks = new RemoteCallbackList (); 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 values = new HashMap (); 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 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 RemoteCallbackListmCallbacks = new RemoteCallbackList (); 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; } }
服务初始化和绑定:
// 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); } } };
Robby Pond.. 282
如果您的服务将成为您应用程序的一部分,那么您将使它变得比它需要的更复杂.由于您有一个从RESTful Web服务获取某些数据的简单用例,因此您应该查看ResultReceiver和IntentService.
当您要执行某些操作时,此Service + ResultReceiver模式通过使用startService()启动或绑定到服务来工作.您可以指定要执行的操作,并通过Intent中的extras传入ResultReceiver(活动).
在服务中,您实现onHandleIntent以执行Intent中指定的操作.操作完成后,使用传入的ResultReceiver 将消息发送回Activity,此时将调用onReceiveResult.
例如,您希望从Web Service中提取一些数据.
您创建意图并调用startService.
服务中的操作开始,它向活动发送一条消息,说明它已启动
活动处理消息并显示进度.
该服务完成操作并将一些数据发送回您的活动.
您的活动处理数据并将其放入列表视图中
该服务会向您发送一条消息,说明已完成,并且它会自行终止.
活动获取完成消息并隐藏进度对话框.
我知道您提到过您不想使用代码库,但开源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); } } }
答案的一小部分:当你执行mReceiver.setReceiver(null); 在onPause方法中,你应该做mReceiver.setReceiver(this); 在onResume方法中.否则,如果您的活动在未重新创建的情况下恢复,则可能无法收到活动 (29认同)
不要文档说你不必调用stopSelf,因为IntentService会为你做这件事吗? (7认同)
@MikaelOhlson正确,如果你继承了`IntentService`,你应该_not_调用`stopSelf`,因为如果你这样做,你将失去对同一个`IntentService`的任何待处理请求. (2认同)
Terrance.. 17
开发Android REST客户端应用程序对我来说是一个很棒的资源.演讲者没有显示任何代码,他只是在设计考虑因素和技术上将一个坚如磐石的Rest Api放在android中.如果你的播客有点与否,我建议给这个人至少一个听,但是,就我个人而言,我已经听了4到5次,我可能会再听一遍.
开发Android REST客户端应用程序
作者:Virgil Dobjanschi
描述:
本次会议将介绍在Android平台上开发RESTful应用程序的架构注意事项.它侧重于Android平台特有的设计模式,平台集成和性能问题.
在我的api的第一个版本中我真的没有做过很多考虑,我必须重构
如果您的服务将成为您应用程序的一部分,那么您将使它变得比它需要的更复杂.由于您有一个从RESTful Web服务获取某些数据的简单用例,因此您应该查看ResultReceiver和IntentService.
当您要执行某些操作时,此Service + ResultReceiver模式通过使用startService()启动或绑定到服务来工作.您可以指定要执行的操作,并通过Intent中的extras传入ResultReceiver(活动).
在服务中,您实现onHandleIntent以执行Intent中指定的操作.操作完成后,使用传入的ResultReceiver 将消息发送回Activity,此时将调用onReceiveResult.
例如,您希望从Web Service中提取一些数据.
您创建意图并调用startService.
服务中的操作开始,它向活动发送一条消息,说明它已启动
活动处理消息并显示进度.
该服务完成操作并将一些数据发送回您的活动.
您的活动处理数据并将其放入列表视图中
该服务会向您发送一条消息,说明已完成,并且它会自行终止.
活动获取完成消息并隐藏进度对话框.
我知道您提到过您不想使用代码库,但开源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); } } }
开发Android REST客户端应用程序对我来说是一个很棒的资源.演讲者没有显示任何代码,他只是在设计考虑因素和技术上将一个坚如磐石的Rest Api放在android中.如果你的播客有点与否,我建议给这个人至少一个听,但是,就我个人而言,我已经听了4到5次,我可能会再听一遍.
开发Android REST客户端应用程序
作者:Virgil Dobjanschi
描述:
本次会议将介绍在Android平台上开发RESTful应用程序的架构注意事项.它侧重于Android平台特有的设计模式,平台集成和性能问题.
在我的api的第一个版本中我真的没有做过很多考虑,我必须重构
此外,当我点击帖子(Config.getURL("登录"),值)应用程序似乎暂停了一段时间(似乎很奇怪 - 认为服务背后的想法是它在不同的线程上运行!)
不,您必须自己创建一个线程,默认情况下,本地服务在UI线程中运行.
我知道@Martyn不想要完整的代码,但我认为这个注释对这个问题有好处:
每个Android开发人员必须研究的10个开源Android应用程序
Foursquared for Android是开源的,并且有一个有趣的代码模式与foursquare REST API交互.
我强烈推荐REST客户端Retrofit.
我发现这篇写得很好的博客文章非常有帮助,它还包含简单的示例代码.作者使用Retrofit进行网络调用,使用Otto实现数据总线模式:
http://www.mdswanson.com/blog/2014/04/07/durable-android-rest-clients.html
只是想让大家指出我所推出的包含所有功能的独立类的方向.
http://github.com/StlTenny/RestService
它以非阻塞的形式执行请求,并以易于实现的处理程序返回结果.甚至附带一个示例实现.