0
votes

I'm developing an app which requires Detect available Beacons near by your region and the detected beacon details need send to my server using API call. I'm getting beacon details but I'm not able to send the details to my server from background of app found any beacon.

Here is the details of Beacons;

    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) {
        }
    }   

Help me how to send beacon details to my server when I found the beacons in the app background.

2
why are you not able to do this?Tim
When the app is in the background, you can use Android X Work Manager to start a job which can send data to your server.waterbyte
yes i can able to send easily from one particular screen of application .. but i need to send from app background cases also please give me exaples or any stackoverflow solved this type linksLaxman Marth

2 Answers

0
votes

First of all, AsyncTask needs ui thread to work in, you can use any other threading apis: HandlerThread, custom handler, ExecutorService or just a normal thread. You can read in more details from here and here.

Another FYI, to detect beacon from background I hope you are not using normal service, it can cause you problems on Oreo and above devices. Please using foregroundService instead. Read about services here and the reason for this from here.

0
votes

While you have not shown any code that attempts to send data to a server, since you have successfully used a AsyncTask to process beacon data, you can also use another AsyncTask to send data to a server -- the principal is the same.

Example:

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);
}

Then you can call it with:

    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);

Be careful not to send data to the server too often. A server call can take one sec or more and beacons can be detected more often than that. If you send data too often you will run out of threads and overload your server. Consider batching your calls so multiple beacon detections are sent to the server, say, every 60 seconds.