【问题标题】:How to send details of detected Beacon information to server in background?如何在后台将检测到的 Beacon 信息的详细信息发送到服务器?
【发布时间】:2023-03-14 11:52:02
【问题描述】:

我正在开发一个应用程序,该应用程序需要检测您所在地区附近的可用信标,并且检测到的信标详细信息需要使用 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 启动一个可以向您的服务器发送数据的作业。
  • 是的,我可以从应用程序的一个特定屏幕轻松发送 .. 但我需要从应用程序后台案例发送也请给我示例或任何 stackoverflow 解决了这种类型的链接

标签: android ibeacon ibeacon-android


【解决方案1】:

首先,AsyncTask 需要 ui 线程才能工作,您可以使用任何其他线程 api:HandlerThreadcustom handlerExecutorService 或只是一个普通线程。您可以从herehere 阅读更多详细信息。

另一个仅供参考,从后台检测信标我希望您没有使用正常服务,它可能会导致您在 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 调用来调用我的服务器?即使应用程序也在后台,我是否需要在我的应用程序中运行任何后台服务或作业来发送呼叫......?如果是,那么请您提供我的样品
    猜你喜欢
    • 2018-04-03
    • 2017-07-16
    • 1970-01-01
    • 1970-01-01
    • 2019-04-29
    • 1970-01-01
    • 2015-10-07
    • 2017-06-27
    • 2018-07-06
    相关资源
    最近更新 更多