Android 使用 Volley 的应用获取竞争条件
Android App using Volley get race condition
我正在开发一个 Android 移动应用程序,应用程序本身最重要的功能之一是能够与第三方 API 服务对话。
提供这些 API 的第三方服务希望 "beacon" 包含在我发出的每个 API 请求中。
"beacon" 是一个 "long integer",它必须是唯一的并且对于每个请求都是递增的。
问题是:
我正在触发其中的几个请求,但我不知道这些请求中的哪一个会先完成,所以我 运行 进入了竞争状态:第二个请求在第一个请求使第一个请求无效之前快速结束!
单击按钮时将执行以下操作:
public void fireRequests(View view)
{
long first_beacon = System.nanoTime();
fireFirstRequest(view, first_beacon);
long second_beacon = System.nanoTime();
fireSecondRequest(view, second_beacon);
}
我正在以正确的方式使用 Volley,设置回调等。此处示例:
fireFirstRequest 方法:
public void fireFirstRequest(View view, long beacon)
{
final ThirdPartyLib api_lib = new ThirdPartyLib(getActivity());
api_lib.doOperationA(beacon, new ThirdPartyLib.MyOwnCallback()
{
@Override
public void update(JSONObject jsonObject)
{
try
{
JSONObject result = jsonObject.getJSONObject("response");
/* my code */
Log.d("doOperationA", result)
}
catch (JSONException e)
{
e.printStackTrace();
}
}
});
}
fireSecondRequest 方法:
public void fireSecondRequest(View view, long beacon)
{
final ThirdPartyLib api_lib = new ThirdPartyLib(getActivity());
api_lib.doOperationB(beacon, new ThirdPartyLib.MyOwnCallback()
{
@Override
public void update(JSONObject jsonObject)
{
try
{
JSONObject result = jsonObject.getJSONObject("response");
/* my code */
Log.d("doOperationB", result)
}
catch (JSONException e)
{
e.printStackTrace();
}
}
});
}
这是执行日志:
03-12 14:26:56.252 18769-18769/it.example.app D/Volley: queued doOperationA
03-12 14:26:58.124 18769-18769/it.example.app D/Volley: queued doOperationB
03-12 14:26:59.433 18769-18769/it.example.app D/App: doOperationB: {
"error": false,
"payload": {
"foo": "bar"
}
}
03-12 14:27:04.181 18769-18769/it.example.app D/App: doOperationA: {
"error": true,
"errorMessage": "invalid beacon"
"payload": {}
}
问题是:在触发 API 请求之前跟踪信标或保持 "execution order" 分离的最佳方法是什么,即使我们谈论的是异步请求?
我的粗略解决方案是当我完全确定第一个请求已完成时,在 fireFirstRequest() 的回调中调用 fireSecondRequest()。
我知道,这是杀死异步请求这个令人敬畏的世界的最好方法。
修改后的动作:
public void fireRequests(View view)
{
long first_beacon = System.nanoTime();
fireFirstRequest(view, first_beacon);
}
fireFirstRequest 修改方法与 final 查看参数:
public void fireFirstRequest(final View view, long beacon)
{
final ThirdPartyLib api_lib = new ThirdPartyLib(getActivity());
api_lib.doOperationA(beacon, new ThirdPartyLib.MyOwnCallback()
{
@Override
public void update(JSONObject jsonObject)
{
try
{
JSONObject result = jsonObject.getJSONObject("response");
/* my code */
Log.d("doOperationA", result)
/* fire second request */
// EDIT
fireSecondRequest(view, System.nanoTime());
}
catch (JSONException e)
{
e.printStackTrace();
}
}
});
}
您没有添加启动 Volley 的代码部分 RequestQueue
,但我假设您正在使用以下方式创建默认方式:
RequestQueue requestQueue = Volley.newRequestQueue(context, stack);
执行此操作时,您会得到一个默认允许 4 个并发请求的请求队列。您可以通过查看此方法用于创建请求队列的构造函数来了解这一点:
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
...
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
如果不使用创建 RequestQueue
的默认方法,而是创建线程池大小为 1 的自己的 RequestQueue
,则可以解决此问题。这样,就没有2个并发请求,请求将按派发顺序发送。
当然,这样做的缺点是这会大大降低您的应用程序的速度。如果所有请求都必须等到前一个请求完成,这会在您的应用程序中造成严重的瓶颈。
或许可以考虑使用1个以上的请求队列,并且只对依赖这个特殊约束的请求使用这个特殊的请求队列。
希望这对您有所帮助。
我正在开发一个 Android 移动应用程序,应用程序本身最重要的功能之一是能够与第三方 API 服务对话。
提供这些 API 的第三方服务希望 "beacon" 包含在我发出的每个 API 请求中。
"beacon" 是一个 "long integer",它必须是唯一的并且对于每个请求都是递增的。
问题是: 我正在触发其中的几个请求,但我不知道这些请求中的哪一个会先完成,所以我 运行 进入了竞争状态:第二个请求在第一个请求使第一个请求无效之前快速结束!
单击按钮时将执行以下操作:
public void fireRequests(View view)
{
long first_beacon = System.nanoTime();
fireFirstRequest(view, first_beacon);
long second_beacon = System.nanoTime();
fireSecondRequest(view, second_beacon);
}
我正在以正确的方式使用 Volley,设置回调等。此处示例:
fireFirstRequest 方法:
public void fireFirstRequest(View view, long beacon)
{
final ThirdPartyLib api_lib = new ThirdPartyLib(getActivity());
api_lib.doOperationA(beacon, new ThirdPartyLib.MyOwnCallback()
{
@Override
public void update(JSONObject jsonObject)
{
try
{
JSONObject result = jsonObject.getJSONObject("response");
/* my code */
Log.d("doOperationA", result)
}
catch (JSONException e)
{
e.printStackTrace();
}
}
});
}
fireSecondRequest 方法:
public void fireSecondRequest(View view, long beacon)
{
final ThirdPartyLib api_lib = new ThirdPartyLib(getActivity());
api_lib.doOperationB(beacon, new ThirdPartyLib.MyOwnCallback()
{
@Override
public void update(JSONObject jsonObject)
{
try
{
JSONObject result = jsonObject.getJSONObject("response");
/* my code */
Log.d("doOperationB", result)
}
catch (JSONException e)
{
e.printStackTrace();
}
}
});
}
这是执行日志:
03-12 14:26:56.252 18769-18769/it.example.app D/Volley: queued doOperationA
03-12 14:26:58.124 18769-18769/it.example.app D/Volley: queued doOperationB
03-12 14:26:59.433 18769-18769/it.example.app D/App: doOperationB: {
"error": false,
"payload": {
"foo": "bar"
}
}
03-12 14:27:04.181 18769-18769/it.example.app D/App: doOperationA: {
"error": true,
"errorMessage": "invalid beacon"
"payload": {}
}
问题是:在触发 API 请求之前跟踪信标或保持 "execution order" 分离的最佳方法是什么,即使我们谈论的是异步请求?
我的粗略解决方案是当我完全确定第一个请求已完成时,在 fireFirstRequest() 的回调中调用 fireSecondRequest()。 我知道,这是杀死异步请求这个令人敬畏的世界的最好方法。
修改后的动作:
public void fireRequests(View view)
{
long first_beacon = System.nanoTime();
fireFirstRequest(view, first_beacon);
}
fireFirstRequest 修改方法与 final 查看参数:
public void fireFirstRequest(final View view, long beacon)
{
final ThirdPartyLib api_lib = new ThirdPartyLib(getActivity());
api_lib.doOperationA(beacon, new ThirdPartyLib.MyOwnCallback()
{
@Override
public void update(JSONObject jsonObject)
{
try
{
JSONObject result = jsonObject.getJSONObject("response");
/* my code */
Log.d("doOperationA", result)
/* fire second request */
// EDIT
fireSecondRequest(view, System.nanoTime());
}
catch (JSONException e)
{
e.printStackTrace();
}
}
});
}
您没有添加启动 Volley 的代码部分 RequestQueue
,但我假设您正在使用以下方式创建默认方式:
RequestQueue requestQueue = Volley.newRequestQueue(context, stack);
执行此操作时,您会得到一个默认允许 4 个并发请求的请求队列。您可以通过查看此方法用于创建请求队列的构造函数来了解这一点:
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
...
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
如果不使用创建 RequestQueue
的默认方法,而是创建线程池大小为 1 的自己的 RequestQueue
,则可以解决此问题。这样,就没有2个并发请求,请求将按派发顺序发送。
当然,这样做的缺点是这会大大降低您的应用程序的速度。如果所有请求都必须等到前一个请求完成,这会在您的应用程序中造成严重的瓶颈。
或许可以考虑使用1个以上的请求队列,并且只对依赖这个特殊约束的请求使用这个特殊的请求队列。
希望这对您有所帮助。