我正在寻找一个服务,我可以使用它来调用基于web的REST API。

我想在app init上启动一个服务然后我想让这个服务请求一个url并返回结果。与此同时,我希望能够显示一个进度窗口或类似的东西。

我目前创建了一个使用IDL的服务,我在某处读到过,你只需要它来跨应用程序通信,所以认为这些需求剥离,但不确定如何做回调没有它。另外,当我点击帖子(Config.getURL(“login”),值)时,应用程序似乎暂停了一段时间(看起来很奇怪-以为服务背后的想法是它在不同的线程上运行!)

目前,我有一个服务与post和获取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);
}

and

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;
    }
}

服务初始化和绑定:

// 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);
        }

    }

};

当前回答

我知道@Martyn不想要完整的代码,但我认为这个注释对这个问题有好处:

10个开源Android应用,每个Android开发者都必须看看

Android版foursquare是开源的,并且有一个有趣的代码模式与foursquare REST API交互。

其他回答

Lets say I want to start the service on an event - onItemClicked() of a button. The Receiver mechanism would not work in that case because :- a) I passed the Receiver to the service (as in Intent extra) from onItemClicked() b) Activity moves to the background. In onPause() I set the receiver reference within the ResultReceiver to null to avoid leaking the Activity. c) Activity gets destroyed. d) Activity gets created again. However at this point the Service will not be able to make a callback to the Activity as that receiver reference is lost. The mechanism of a limited broadcast or a PendingIntent seems to be more usefull in such scenarios- refer to Notify activity from service

当我点击 帖子(Config.getURL(“登录”), 值)应用程序似乎暂停了一个 虽然(看起来很奇怪——这个想法想 服务的背后是它运行在 不同的线程!)

不,你必须自己创建一个线程,默认情况下本地服务运行在UI线程中。

注意,Robby Pond的解决方案在某种程度上是缺乏的:在这种方式下,你只允许一次执行一个api调用,因为IntentService一次只处理一个意图。通常你想要执行并行api调用。如果你想这样做,你必须扩展Service而不是IntentService,并创建你自己的线程。

我强烈推荐REST客户端Retrofit。

我发现这篇写得很好的博客文章非常有用,它还包含简单的示例代码。 作者使用了Retrofit进行网络调用,Otto实现了一个数据总线模式:

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

我知道@Martyn不想要完整的代码,但我认为这个注释对这个问题有好处:

10个开源Android应用,每个Android开发者都必须看看

Android版foursquare是开源的,并且有一个有趣的代码模式与foursquare REST API交互。