在 Android 平板电脑地图上绘制叠加层时正确处理主线程连接上的网络
在玩了很多 honeycomb 之后,事实证明,如果你做了任何 HTTP 的事情,它就会引发 NetworkOnMainThread 问题。我通过将对 http 的调用放在一个单独的 AsynTask 中来处理这个问题,这似乎工作得很好...
现在我正在尝试加载正在获取的 WMS 图层(通过 https)并将其放在地图上。这工作正常,但我使用 AsyncTask 的方式并没有削减它,因为每次在覆盖层上调用绘图时(我认为每次移动地图时)它都会执行另一个操作,
new getWmsAsync().execute();
这意味着一段时间后就会出现最大线程。
我不确定正确的解决方法是什么。或者在按照我知道如何失败的方式完成之后如何以正确的方式进行设计。我缺少哪些部分?是否可以在不同的线程上获取 https 请求(我认为每次移动地图时都必须完成)。
原始调用:
在 WMSOverlay extends Overlay
类中:
@Override
public void draw(Canvas canvas, MapView mapView,
boolean shadow) {
super.draw(canvas, mapView, shadow);
mCanvas=canvas;
wmsclient = new WMSLoader(mapView.getContext());
cornerCoords = MapUtils.getCornerCoordinates(mapView.getProjection(), canvas);
//new getWmsAsync().execute();
Paint semitransparent = new Paint();
semitransparent.setAlpha(0x888);
mCanvas.drawBitmap( , 0, 0, semitransparent);
}
但是我的 wsmClient.loadMap
中有 http 调用,因此它会因上述 NetworkOnMainThread 而终止。我的修复是这样的:
@Override
public void draw(Canvas canvas, MapView mapView,
boolean shadow) {
super.draw(canvas, mapView, shadow);
mCanvas=canvas;
wmsclient = new WMSLoader(mapView.getContext());
cornerCoords = MapUtils.getCornerCoordinates(mapView.getProjection(), canvas);
new getWmsAsync().execute(); //too many threads here...
}
private class getWmsAsync extends AsyncTask<Void, Void, Bitmap>{
@Override
protected void onPostExecute(Bitmap image) {
Paint semitransparent = new Paint();
semitransparent.setAlpha(0x888);
mCanvas.drawBitmap(image, 0, 0, semitransparent);
this.cancel(true);
}
@Override
protected Bitmap doInBackground(Void... params) {
// TODO Auto-generated method stub
return wmsclient.loadMap(mCanvas.getWidth(), mCanvas.getHeight(), cornerCoords[0], cornerCoords[1], null);
}
}
如果我将这种方式与 .execute()
一起使用,我最终会遇到此错误:
08-23 17:01:05.520: ERROR/AndroidRuntime(5436): java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$3@41147c88 rejected from java.util.concurrent.ThreadPoolExecutor@40880c00[Running, pool size = 128, active threads = 127, queued tasks = 10, completed tasks = 59]
After playing with honeycomb a lot, it turns out if you do any HTTP stuff it wines about a NetworkOnMainThread issue. I was dealing with this by putting my calls to http in a separate AsynTask and this seemed to work well...
Now I am trying to load a WMS layer im fetching (Via https) and put it on the map. This is working okay but my way of using AsyncTask isn't cutting it as everytime the draw was called on the overlay (which I think is everytime you move the map) it was doing another
new getWmsAsync().execute();
which means after a while there was max threads.
I am not sure what the right fix for this is. Or how to engineer this in the correct way after doing it the way I knew how failed me. What pieces am I missing? Is there away to get the https request on a different thread (it has to be done every time the map is moved I think).
The original calls:
in the WMSOverlay extends Overlay
class:
@Override
public void draw(Canvas canvas, MapView mapView,
boolean shadow) {
super.draw(canvas, mapView, shadow);
mCanvas=canvas;
wmsclient = new WMSLoader(mapView.getContext());
cornerCoords = MapUtils.getCornerCoordinates(mapView.getProjection(), canvas);
//new getWmsAsync().execute();
Paint semitransparent = new Paint();
semitransparent.setAlpha(0x888);
mCanvas.drawBitmap( , 0, 0, semitransparent);
}
But my wsmClient.loadMap
has http calls in it so it dies with the above NetworkOnMainThread. My fix was this:
@Override
public void draw(Canvas canvas, MapView mapView,
boolean shadow) {
super.draw(canvas, mapView, shadow);
mCanvas=canvas;
wmsclient = new WMSLoader(mapView.getContext());
cornerCoords = MapUtils.getCornerCoordinates(mapView.getProjection(), canvas);
new getWmsAsync().execute(); //too many threads here...
}
private class getWmsAsync extends AsyncTask<Void, Void, Bitmap>{
@Override
protected void onPostExecute(Bitmap image) {
Paint semitransparent = new Paint();
semitransparent.setAlpha(0x888);
mCanvas.drawBitmap(image, 0, 0, semitransparent);
this.cancel(true);
}
@Override
protected Bitmap doInBackground(Void... params) {
// TODO Auto-generated method stub
return wmsclient.loadMap(mCanvas.getWidth(), mCanvas.getHeight(), cornerCoords[0], cornerCoords[1], null);
}
}
if I use that way with the .execute()
i end up with this error:
08-23 17:01:05.520: ERROR/AndroidRuntime(5436): java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$3@41147c88 rejected from java.util.concurrent.ThreadPoolExecutor@40880c00[Running, pool size = 128, active threads = 127, queued tasks = 10, completed tasks = 59]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
AFAIK,如果您使用
StrictMode
,您应该只收到消息。无论如何,比 LogCat 消息更重要的是,如果您在主应用程序线程上执行网络 I/O,您将冻结您的 UI。通常,您会缓存 HTTP 请求结果,因此无需重新请求它们。
或者,如果您的每个请求都针对不同的数据,请等到用户暂停,然后对最终结果执行单个请求,就像 Google 地图对其自己的地图图块所做的那样。
AFAIK, you should only get messages if you are using
StrictMode
. Regardless, more important than the LogCat messages is that you are freezing your UI if you do network I/O on the main application thread.Well, typically, you cache your HTTP request results, so you do not need to re-request them.
Or, if each of your requests would be for different data, wait until the user pauses, then do a single request for the end result, the same way Google Maps does it for its own map tiles.