我正在寻找一个服务,我可以使用它来调用基于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);
        }

    }

};

当前回答

我只是想给你们指出一个独立的类,它包含了所有的功能。

http://github.com/StlTenny/RestService

它以非阻塞的方式执行请求,并以易于实现的处理程序返回结果。甚至还附带了一个示例实现。

其他回答

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

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

开发Android REST客户端应用程序对我来说是一个很棒的资源。演讲者没有展示任何代码,他只是介绍了设计考虑因素和技术,在android中把一个坚实的Rest Api放在一起。不管你是不是播客达人,我建议你至少听一遍,不过就我个人而言,我已经听了4到5遍了,我可能还会再听一遍。

开发Android REST客户端应用程序 作者:Virgil Dobjanschi 描述:

本节课将介绍在Android平台上开发RESTful应用程序的架构考虑事项。它着重于Android平台的设计模式、平台集成和性能问题。

在我的api的第一个版本中,有很多我没有考虑到的因素,我不得不进行重构

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

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

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

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

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