-3

So there is a background Service which creates Runnable objects as soon as GPS Location is changed. Runnable contains HTTPConnection to make POST and twice send broadcast message via sendBroadcast().

So the problem I am facing if there is no chance to send data by this scheme something happened and app craches.

Any clue to refactor code or may be change approach to TaskAsync and cancel pending TaskAsync when new TaskAsync is ready?

Any clue?

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.text.format.DateFormat;
import android.util.Log;

import com.google.gson.Gson;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;


public class gps_service2 extends Service {
    private static final String TAG = "GPS SERVICE";
    private LocationManager mLocationManager = null;
    private static final int LOCATION_INTERVAL = 10000;
    private static final float LOCATION_DISTANCE = 10f;
    Context context;

    private class LocationListener implements android.location.LocationListener
    {
        Location mLastLocation;

        public LocationListener(String provider)
        {
            Log.e(TAG, "LocationListener " + provider);
            mLastLocation = new Location(provider);
        }

        @Override
        public void onLocationChanged(Location location)
        {
            Log.e(TAG, "onLocationChanged: " + location);

            try
            {
                ComplexPreferences complexPreferences = ComplexPreferences.getComplexPreferences(context, "App_Settings", 0);
                AppSettings appSettings = complexPreferences.getObject("App_Settings", AppSettings.class);
                if (appSettings != null) {

                    LocationItem locationItem = new LocationItem();
                    locationItem.DeviceID = appSettings.getDeviceID();
                    locationItem.Latitude =  Double.toString(location.getLatitude());
                    locationItem.Longitude = Double.toString(location.getLongitude());
                    Date d = new Date();
                    CharSequence timeOfRequest = DateFormat.format("yyyy-MM-dd HH:mm:ss", d.getTime()); // YYYY-MM-DD HH:mm:ss
                    locationItem.TimeOfRequest = timeOfRequest.toString();
                    locationItem.SerialNumber = appSettings.getSerialNumber();


                    Gson gson = new Gson();
                    String requestObject = gson.toJson(locationItem);
                    String url = appSettings.getIpAddress() + "/api/staff/savedata";
                    makeRequest(url, requestObject, dLocation);
                }
            }
            catch (Exception ex)
            {                
            } 
        }

        @Override
        public void onProviderDisabled(String provider)
        {
            Log.e(TAG, "onProviderDisabled: " + provider);
        }

        @Override
        public void onProviderEnabled(String provider)
        {
            Log.e(TAG, "onProviderEnabled: " + provider);
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras)
        {
            Log.e(TAG, "onStatusChanged: " + provider);
        }
    }

    LocationListener[] mLocationListeners = new LocationListener[] {
            new LocationListener(LocationManager.GPS_PROVIDER),
            new LocationListener(LocationManager.NETWORK_PROVIDER)
    };

    @Override
    public IBinder onBind(Intent arg0)
    {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        Log.e(TAG, "onStartCommand");
        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

    @Override
    public void onCreate()
    {
        context = this;
        Log.e(TAG, "onCreate");
        initializeLocationManager();
        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
                    mLocationListeners[1]);
        } catch (java.lang.SecurityException ex) {
            Log.i(TAG, "fail to request location update, ignore", ex);
        } catch (IllegalArgumentException ex) {
            Log.d(TAG, "network provider does not exist, " + ex.getMessage());
        }
        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
                    mLocationListeners[0]);
        } catch (java.lang.SecurityException ex) {
            Log.i(TAG, "fail to request location update, ignore", ex);
        } catch (IllegalArgumentException ex) {
            Log.d(TAG, "gps provider does not exist " + ex.getMessage());
        }
    }

    @Override
    public void onDestroy()
    {
        Log.e(TAG, "onDestroy");
        super.onDestroy();
        if (mLocationManager != null) {
            for (int i = 0; i < mLocationListeners.length; i++) {
                try {
                    mLocationManager.removeUpdates(mLocationListeners[i]);
                } catch (Exception ex) {
                    Log.i(TAG, "fail to remove location listners, ignore", ex);
                }
            }
        }
    }

    private void initializeLocationManager() {
        Log.e(TAG, "initializeLocationManager");
        if (mLocationManager == null) {
            mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        }
    }

    public static double round(double value, int places) {
        if (places < 0) throw new IllegalArgumentException();
        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(places, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }

    public void makeRequest(String uri, String json, DLocation dLocation) {

        HandlerThread handlerThread = new HandlerThread("URLConnection");
        handlerThread.start();
        Handler mainHandler = new Handler(handlerThread.getLooper());
        Runnable myRunnable = createRunnable(uri, json, dLocation);
        mainHandler.post(myRunnable);
    }

    private Runnable createRunnable(final String uri, final String data,final DLocation dLocation){

        Runnable aRunnable = new Runnable(){
            public void run(){
                try {
                    //Connect
                    HttpURLConnection urlConnection;
                    urlConnection = (HttpURLConnection) ((new URL(uri).openConnection()));
                    urlConnection.setDoOutput(true);
                    urlConnection.setRequestProperty("Content-Type", "application/json");
                    urlConnection.setRequestProperty("Accept", "application/json");
                    urlConnection.setRequestMethod("POST");
                    urlConnection.connect();

                    //Write
                    OutputStream outputStream = urlConnection.getOutputStream();
                    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
                    try {
                        writer.write(data);
                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.d(TAG,"Ошибка записи в буфер для пережачи по HTTP");
                    }
                    writer.close();
                    outputStream.close();

                    //Read
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));

                    String line = null;
                    StringBuilder sb = new StringBuilder();

                    while ((line = bufferedReader.readLine()) != null) {
                        sb.append(line);
                    }

                    bufferedReader.close();
                    String result = sb.toString();

                    Log.d(TAG, result);

                    Intent iResult = new Intent("location_update");

                    DLocation dLocation = new DLocation();                    
                    iResult.putExtra("result", dLocation);
                    sendBroadcast(iResult);                   

                }catch( Exception err){
                    err.printStackTrace();
                    Log.d(TAG, "HTTP " + err.getMessage());
                }
            }
        };

        return aRunnable;
    }
}
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
NoWar
  • 36,338
  • 80
  • 323
  • 498
  • 2
    **`scheme something happened and app craches.`** where is your crash log – AskNilesh Dec 21 '17 at 08:36
  • @Nilu In the emulator it works fine. It craches under device. But well no log... And It craches when there is a problem with transfer data like low speed mobile network or bad signal... – NoWar Dec 21 '17 at 08:45
  • @AcademyofProgrammer "getting crashes" this could be caused by several reasons, please add the error message displayed into the LogCat. – Jorgesys Dec 29 '17 at 00:51
  • check before it crash did you get ANR? – Anu Martin Jan 01 '18 at 05:58

2 Answers2

5

Runnable is just an interface, when you create a thread using Runnable interface basically it will run under the the thread where it created, in here runnable associate with UI thread, as per google documentation Network calls must be in a worker thread not in UI thread.

Then Why it runs on emulator
android had DVM(dalvik virtual machine),it works like JVM but instead of .class file DVM uses .dex extension, so may the device had older or newer version of DVM.

Fix
Use android's AsyncTask for network calls. android(DVM) had limited resources compare to JVM, when it comes to thread, so better use AsyncTask

check this answer too

AsyncTask code for passing JSON to server, and get responds as callback

public class WebService extends AsyncTask<String,String,String> {
private static final String TAG="SyncToServerTAG";




private String urlString;
private JSONObject jsonObject=null;
private int screenId=1;

public WebService(String url) {
    this.urlString=url;
}

public WebService(Context context, String url, JSONObject jsonObject) {
    this.urlString = url;
    this.jsonObject = jsonObject;
}

@Override
protected String doInBackground(String... strings) {
    try {
        URL url = new URL(urlString);
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setChunkedStreamingMode(0);
        urlConnection.setConnectTimeout(5000);
        urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);
        urlConnection.setRequestMethod("POST");
        if(jsonObject!=null) {
            OutputStream os = urlConnection.getOutputStream();
            os.write(jsonObject.toString().getBytes("UTF-8"));
        }

        InputStream in = new BufferedInputStream(urlConnection.getInputStream());
        BufferedReader br = new BufferedReader(new InputStreamReader(
                (urlConnection.getInputStream())));

        String output="";
        while (true) {
            String line=br.readLine();
                Log.d(TAG,line+" ");
            if(line!=null)
                output+=line;
            else
                break;
        }

        in.close();
        urlConnection.disconnect();
        JSONObject j;
        if(output.equals(""))
            publishProgress("Server give null");
        else {
            j=new JSONObject(output);
            return output;
        }
        return output;
    } catch (MalformedURLException e) {
        e.printStackTrace();
        publishProgress(e.toString());
    } catch (IOException e) {
        e.printStackTrace();
        publishProgress(e.toString());
    } catch (JSONException e) {
        e.printStackTrace();
        publishProgress(e.toString());
    }
    return null;
}

@Override
protected void onProgressUpdate(String... values) {
    super.onProgressUpdate(values);
    fireError(values[0]);
}

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);
    if(s!=null) {
        try {
            JSONObject jsonObject=new JSONObject(s);
            fireComplete(0, jsonObject);
        } catch (JSONException e) {
            e.printStackTrace();
            fireError("Non acceptable responds from server ["+urlString+"]");
        }
    }
}

public interface OnWebCompleteListener{
    void onComplete(JSONObject result, int dataSource);
    void onError(String error);
}
private OnWebCompleteListener onWebCompleteListener;
private void fireComplete(int sourse,JSONObject cache){
    if(onWebCompleteListener!=null)
        onWebCompleteListener.onComplete(cache,sourse);
}
private void fireError(String message){
    if(onWebCompleteListener!=null)
        onWebCompleteListener.onError(message);
}
public void start(OnWebCompleteListener onWebCompleteListener){
    if(onWebCompleteListener==null)
        throw new RuntimeException("You must provide non-null value as start listener");
    this.onWebCompleteListener=onWebCompleteListener;
    execute((String)null);
}

}

Usage

    WebService webService=new WebService(context,"url",jsonObject);
    webService.start(new WebService.OnWebCompleteListener() {
    @Override
    public void onComplete(JSONObject result, int dataSource) {

    }

    @Override
    public void onError(String error) {

    }
    });
Anu Martin
  • 711
  • 1
  • 9
  • 20
1

Your code is very vulnerable. I think that you crash because your makeRequest method exits before you Runnable had the chance to complete the task. You closed the resource as soon as you send them, freeing system resources. There for the second time you call broadcast, the resources are not there anymore causing the crash....

Sagi Forbes
  • 2,139
  • 2
  • 13
  • 16