如何在后台将检测到的 Beacon 信息的详细信息发送到服务器?
Posted
技术标签:
【中文标题】如何在后台将检测到的 Beacon 信息的详细信息发送到服务器?【英文标题】:How to send details of detected Beacon information to server in background? 【发布时间】:2018-10-04 09:32:08 【问题描述】:我正在开发一个应用程序,该应用程序需要检测您所在地区附近的可用信标,并且检测到的信标详细信息需要使用 API 调用发送到我的服务器。 我正在获取信标详细信息,但我无法从应用程序后台将详细信息发送到我的服务器,发现任何信标。
这里是 Beacon 的详细信息;
private class ScanProcessor extends AsyncTask<ScanData, Void, Void>
@Override
protected Void doInBackground(ScanData... params)
ScanData scanData = params[0];
IBeacon iBeacon = IBeacon.fromScanData(scanData.scanRecord, scanData.rssi);
if (iBeacon != null)
lastIBeaconDetectionTime = new Date();
trackedBeacons.add(iBeacon);
Log.d(TAG, "iBeacon detected :"+iBeacon.getProximityUuid()+" Major: "+iBeacon.getMajor()+" Minor: "+iBeacon.getMinor()+" accuracy: "+iBeacon.getAccuracy()+" proximity: "+iBeacon.getProximity());
List<Region> matchedRegions = matchingRegions(iBeacon, monitoredRegionState.keySet());
Iterator<Region> matchedRegionIterator = matchedRegions.iterator();
while (matchedRegionIterator.hasNext())
Region region = matchedRegionIterator.next();
MonitorState state = monitoredRegionState.get(region);
// if (state.markInside())
// state.getCallback().call(IBeaconService.this, "monitoringData", new MonitoringData(state.isInside(), region));
//
Log.d(TAG, "looking for ranging region matches for this ibeacon");
matchedRegions = matchingRegions(iBeacon, rangedRegionState.keySet());
matchedRegionIterator = matchedRegions.iterator();
while (matchedRegionIterator.hasNext())
Region region = matchedRegionIterator.next();
Log.d(TAG, "matches ranging region: "+region);
RangeState rangeState = rangedRegionState.get(region);
rangeState.addIBeacon(iBeacon);
//I see a device: 00:02:72:C5:EC:33 with scan data: 02 01 1A 1A FF 4C 00 02 15 84 2A F9 C4 08 F5 11 E3 92 82 F2 3C 91 AE C0 5E D0 00 00 69 C5 0000000000000000000000000000000000000000000000000000000000000000
//
// 9: proximityUuid (16 bytes) 84 2A F9 C4 08 F5 11 E3 92 82 F2 3C 91 AE C0 5E
// 25: major (2 bytes unsigned int)
// 27: minor (2 bytes unsigned int)
// 29: tx power (1 byte signed int)
return null;
@Override
protected void onPostExecute(Void result)
@Override
protected void onPreExecute()
@Override
protected void onProgressUpdate(Void... values)
当我在应用后台找到信标时,请帮助我如何将信标详细信息发送到我的服务器。
【问题讨论】:
你为什么不能这样做? 当应用处于后台时,您可以使用 android X Work Manager 启动一个可以向您的服务器发送数据的作业。 是的,我可以从应用程序的一个特定屏幕轻松发送 .. 但我需要从应用程序后台案例发送也请给我示例或任何 *** 解决了这种类型的链接 【参考方案1】:首先,AsyncTask 需要 ui 线程才能工作,您可以使用任何其他线程 api:HandlerThread、custom handler、ExecutorService 或只是一个普通线程。您可以从here 和here 阅读更多详细信息。
另一个仅供参考,从后台检测信标我希望您没有使用正常服务,它可能会导致您在 Oreo 及以上设备上出现问题。请改用foregroundService。从here 了解服务here 及其原因。
【讨论】:
【参考方案2】:虽然您没有显示任何尝试将数据发送到服务器的代码,但由于您已成功使用 AsyncTask 处理信标数据,您还可以使用另一个 AsyncTask 将数据发送到服务器 - 主体是相同的.
例子:
public class AsyncCaller extends AsyncTask<Void, Void, Void>
public RestResponseHandler mResponseHandler;
public String mUrl;
public String mOperation;
public String mRequestBody;
public Map<String,String> mRequestHeaders;
Map<String,List<String>> mResponseHeaders;
int mResponseCode;
String mResponseBody;
Exception mException;
public AsyncCaller prepareCall(String url, String operation, String requestBody, Map<String,String> headers, RestResponseHandler responseHandler)
mResponseHandler = responseHandler;
mOperation = operation;
mRequestBody = requestBody;
mUrl = url;
mRequestHeaders = mRequestHeaders;
return this;
@Override
protected void onPreExecute()
super.onPreExecute();
mRequestActive = true;
@Override
protected Void doInBackground(Void... params)
Log.d(TAG, "start doInBackground");
mException = null;
try
sendRequest();
catch (Exception e)
Log.e(TAG, "Cannot send request", e);
mException = new Exception("Cannot send request", e);
Log.d(TAG, "finish doInBackground");
return null;
@Override
protected void onPostExecute(Void result)
Log.d(TAG, "start onPostExecute");
super.onPostExecute(result);
mRequestActive = false;
if (mResponseHandler != null)
if (mException != null)
mResponseHandler.onFail(mException);
else
mResponseHandler.onResponse(mResponseCode, mResponseHeaders, mResponseBody );
Log.d(TAG, "finish onPostExecute");
public void sendRequest() throws Exception
StringBuilder responseBuilder = new StringBuilder();
HttpURLConnection conn = null;
URL url = new URL(mUrl);
mResponseCode = -1;
mResponseBody = null;
mResponseHeaders = null;
Log.d(TAG, "calling service at " + mUrl);
conn = (HttpURLConnection) url.openConnection();
for (String headerKey : mRequestHeaders.keySet())
conn.addRequestProperty(headerKey, mRequestHeaders.get(headerKey));
conn.setRequestMethod(mOperation.toUpperCase());
if (mRequestBody != null)
OutputStream out = conn.getOutputStream();
try
Writer writer = new OutputStreamWriter(out, "UTF-8");
Log.d(TAG, "posting: " + mRequestBody);
writer.write(mRequestBody);
writer.close();
finally
if (out != null)
out.close();
mResponseCode = conn.getResponseCode();
mResponseHeaders = conn.getHeaderFields();
Log.d(TAG, "response code is " + conn.getResponseCode());
BufferedReader in = null;
try
if (mResponseCode >= 200 && mResponseCode <= 299)
in = new BufferedReader(
new InputStreamReader(
conn.getInputStream())
);
else
in = new BufferedReader(
new InputStreamReader(
conn.getErrorStream()
)
);
String inputLine;
while ((inputLine = in.readLine()) != null)
responseBuilder.append(inputLine);
in.close();
Log.d(TAG, "response is " + responseBuilder.toString());
mResponseBody = responseBuilder.toString();
finally
if (in != null)
in.close();
public interface RestResponseHandler
public void onFail(Exception e);
public void onResponse(int httpStatus, Map<String,List<String>> headers, String body);
然后你可以调用它:
mAsyncCsller = new AsyncCaller();
mAsyncCaller.mUrl = "https://myserver.ner/path";
mAsyncCaller.mOperation = "POST";
mAsyncCaller.mRequestBody = "\uuid\":\""+beacon.getId1()+"\"";
mAsyncCaller.mRequestHeaders = new HashMap<String,String>();
mAsyncCaller.mResponseHandler = null;
mAsyncCaller.execute(null, null, null);
注意不要过于频繁地向服务器发送数据。服务器调用可能需要一秒或更长时间,并且可以更频繁地检测到信标。如果您过于频繁地发送数据,您将耗尽线程并使服务器过载。考虑对您的调用进行批处理,以便每隔 60 秒将多个信标检测发送到服务器。
【讨论】:
感谢@david 的回复。但是你能帮我在后台应用程序时如何打电话吗?我需要从哪里调用我的服务器? 您是否在询问如何以编程方式确定您的应用何时处于后台? 是的,大卫我可以在应用程序处于后台时检测到信标。但是我如何使用该页面的 api 调用来调用我的服务器?即使应用程序也在后台,我是否需要在我的应用程序中运行任何后台服务或作业来发送呼叫......?如果是,那么请您提供我的样品以上是关于如何在后台将检测到的 Beacon 信息的详细信息发送到服务器?的主要内容,如果未能解决你的问题,请参考以下文章
扑动 Firebase 动画列表视图如何将数据传递到详细信息屏幕
802.11 ------ Beacon帧Beacon IntervalTBTTListen IntervalTIMDTIM