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

基本上我想在app init上启动一个服务,然后我希望能够请求该服务请求一个url并返回结果.同时,我希望能够显示进度窗口或类似的内容.

我目前创建了一个使用IDL的服务,我在某个地方读到,你只需要在跨应用程序通信中使用它,所以认为这些需要剥离,但不确定如何在没有它的情况下进行回调.此外,当我点击post(Config.getURL("login"), values)时,应用程序似乎暂停了一段时间(似乎很奇怪——我认为服务背后的 idea 是它运行在不同的线程上!)

目前,我有一个包含post和get 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;
        mH和ler.sendMessage(msg);
    }

    public void registerCallback(IRemoteServiceCallback cb) {
        if (cb != null)
            mCallbacks.register(cb);
    }
};

private final H和ler mH和ler = new H和ler() {
    public void h和leMessage(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.h和leMessage(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.和roid

oneway interface IRemoteServiceCallback {
    void userLogIn(String result);
}

package com.something.和roid
import com.something.和roid.IRemoteServiceCallback;

interface IRestfulService {
    void doLogin(in String username, in String password);
    void registerCallback(IRemoteServiceCallback cb);
}

和 the service manager:

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.和roid", "com.something.和roid.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.和roid", "com.something.和roid.RestfulAPIService");
            context.stopService(i);
            started = false;
        }
    }

    public void bindService() {
        if (conn == null) {
            conn = new RestfulServiceConnection();
            Intent i = new Intent();
            i.setClassName("com.something.和roid", "com.something.和roid.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 {
            mH和ler.sendMessage(mH和ler.obtainMessage(Config.ACTION_LOGIN, result));

        }
    };

    private H和ler mH和ler;

    public void setH和ler(H和ler h和ler) {
        mH和ler = h和ler;
    }
}

Service 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.setH和ler(mH和ler);

try {
    servicemanager.restfulService.doLogin(args[0], args[1]);
} catch (RemoteException e) {
    e.printStackTrace();
}

...later in the same file...

H和ler mH和ler = new H和ler() {
    public void h和leMessage(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.h和leMessage(msg);
        }

    }

};

推荐答案

如果您的服务将成为应用程序的一部分,那么您将使其变得比需要的更复杂.因为您有一个从RESTful Web服务获取一些数据的简单用例,所以应该查看ResultReceiverIntentService.

此Service+ResultReceiver模式的工作原理是,当您想要执行某些操作时,使用startService()启动或绑定到服务.您可以指定要执行的操作,并通过Intent中的extras传入ResultReceiver(活动).

在服务中,您实现onHandleIntent来执行意图中指定的操作.操作完成后,使用传入的ResultReceiver将消息返回给将调用点onReceiveResult的活动.

例如,您希望从Web服务中提取一些数据.

  1. 创建意图并调用startService.
  2. 服务中的操作启动,并向活动发送一条消息,表示已启动
  3. 该活动处理消息并显示进度.
  4. 服务完成操作并将一些数据发送回您的活动.
  5. 您的活动将处理数据并将其放入列表视图中
  6. 该服务会向您发送一条消息,告诉您它已经完成,并且会自杀.
  7. 该活动将收到完成消息并隐藏进度对话框.

我知道你提到你不想要一个代码库,但开源Google I/O 2010应用程序使用的服务就是我描述的方式.

Updated to add sample code:

活动.

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.接受者

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相关问答推荐

Jetpack编写Lazy列滑动删除动画不顺利结束

合成 colored颜色 的GSON反序列化

Android compose ,在图像中zoom 而不裁剪?

如何阻止Gradle在编译时生成app-metadata.properties

LocalContext.current的问题(@Composable调用只能从@Composable函数的上下文发生)

如何在DownloadManager Android中显示ProgressBar和Complete Listener

看不到选项菜单栏

任务:app:kaptGenerateStubsDebugKotlin执行失败. > 'compileDebugJavaWithJavac' 任务(当前目标是 1.8)

如何在每次显示可组合项时执行代码(并且只执行一次)

为一组闪烁的可组合项制作动画,控制同步/定时

ArrayList 上的 Android intent.getParcelableArrayListExtra 引发 Nullpointer 异常

在 Jetpack Compose 中重用具有重复代码的列

如何使用 Jetpack Compose 制作两个圆圈

如何使用 Jetpack Compose 在图像上叠加文本

如何在最后一个可见项目之后计算惰性列中的空白空间

为什么我不能直接记住 mutableStateOf 可组合函数?

运行一次 kotlin 流,但在下游收到两次

协程是否在 if 条件下保持秩序?

如何使用 recyclerview 实现这样的布局?

Jetpack compose 绘制形状