1

I have a service. The service starts another thread on completion of which I need to start a new fragmentactivity called MapPage.class which displays a google map. The thread gets a json from a server which contains GPS coordinates. I am saving these coordinates in a singleton class. So, on completion of the thread, I need to start MapPage fragmentactivity using the data in the singleton class.

I do not know how to start MapPage.class from the background thread. I have seen examples of usage of handler from the main activity but I am not sure how I can apply it to my problem. The closest answer I could find was this.

I want to know if creating a handler is the only option I have? If there is any other option? Is usage of handler in an application class the right thing to do for my problem?

My service Class:

     public class TrackingService extends Service {
    private class MyLocationListener implements LocationListener {
        private final Context context;

        public MyLocationListener(Context context) {
            this.context = context;
        }

        @Override
        public void onLocationChanged(Location location) {
            double latitude = location.getLatitude();
            double longtude = location.getLongitude();
            double altitude = location.getAltitude();
            double accuracy = location.getAccuracy();
            float bearing = location.getBearing();
            String provider = location.getProvider();
            Cood cood = new Cood(latitude, longtude, altitude, accuracy,
                    new Date().getTime(), bearing, provider);

            LocationInformation.getInstanceof().getMapPoint().getCood()
                    .add(cood);

            int size = LocationInformation.getInstanceof().getMapPoint()
                    .getCood().size();

            mBuilder.setContentTitle("GPS Tracker - " + size + "/"
                    + SystemSettings.getInstanceOf().getSize());
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.notify(1, mBuilder.build());

            if (size >= SystemSettings.getInstanceOf().getSize()) {
                Toast.makeText(context, "before creating new thread for Track",
                        Toast.LENGTH_SHORT).show();
                new Thread(new Track(context)).start();
                Toast.makeText(context, "after creating new thread for Track",
                        Toast.LENGTH_SHORT).show();

            }
        }

        @Override
        public void onProviderDisabled(String provider) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    }

    LocationManager manag;
    LocationListener locationListener;
    private Context context;
    private Long frequency;
    private Integer minDistance;
    private String deviceRegNo;
    private Integer pointCount;
    private Boolean mode;
    private Builder mBuilder;

    @Override
    public void onCreate() {
        super.onCreate();
        context = this;
    }

    @Override
    public IBinder onBind(Intent arg0) {

        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

    }

    @Override
    public boolean onUnbind(Intent intent) {

        return super.onUnbind(intent);
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {

    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();

    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (intent == null) {

            return Service.START_STICKY;
        }

        manag = (LocationManager) context
                .getSystemService(Context.LOCATION_SERVICE);

        locationListener = new MyLocationListener(context);

        frequency = (Long) intent.getExtras().get("frequency");
        minDistance = (Integer) intent.getExtras().get("minDistance");
        deviceRegNo = (String) intent.getExtras().get("deviceRegNo");
        pointCount = (Integer) intent.getExtras().get("pointCount");
        mode = (Boolean) intent.getExtras().get("prodMode");

        if (frequency == null) {
            Toast.makeText(context, "frequency null", Toast.LENGTH_SHORT)
                    .show();
            return Service.START_STICKY;
        }

        if (minDistance == null) {

            return Service.START_STICKY;
        }

        if (deviceRegNo == null) {

            return Service.START_STICKY;
        }

        if (pointCount == null) {
            Toast.makeText(context, "pointCount null", Toast.LENGTH_SHORT)
                    .show();
            return Service.START_STICKY;
        }
        if (mode == null) {
            Toast.makeText(context, "mode is null", Toast.LENGTH_SHORT).show();
            return Service.START_STICKY;
        }

        if (LocationInformation.getInstanceof().getMapPoint().getDevice() == null) {
            Device device = new Device();
            device.setDeviceRegNo(deviceRegNo);
            LocationInformation.getInstanceof().getMapPoint().setDevice(device);
        }

        SystemSettings.getInstanceOf().setSize(pointCount);
        SystemSettings.getInstanceOf().setProdMode(mode);
        Toast.makeText(context, "On the line before pendingIntent statement",
                Toast.LENGTH_SHORT).show();
        Intent resultIntent = new Intent(context, SettingScreen.class);
        PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0,
                resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        int size = LocationInformation.getInstanceof().getMapPoint().getCood()
                .size();

        mBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentTitle("GPS Tracker - " + size + "/" + pointCount)
                .setContentText(
                        LocationInformation.getInstanceof().getMapPoint()
                                .getDevice().getDeviceRegNo())
                .setContentIntent(resultPendingIntent);
        Toast.makeText(context, "On the line after NotificationCompat.builder",
                Toast.LENGTH_SHORT).show();

        Notification notification = mBuilder.build();
        Toast.makeText(context, "On the line after mBuilder.build",
                Toast.LENGTH_SHORT).show();
        startForeground(1, notification);
        Toast.makeText(context, "On the line after startForeground",
                Toast.LENGTH_SHORT).show();

        manag.requestLocationUpdates(LocationManager.GPS_PROVIDER, frequency,
                minDistance, locationListener);
        return Service.START_STICKY;
    }
}

My thread code is :

     HttpResponse response = httpClient.execute(httpPost);
        BufferedReader br = new BufferedReader(new InputStreamReader(
                response.getEntity().getContent()));
        String line = "";
        while ((line = br.readLine()) != null) {
            text += line;
            System.out.println("RESULT: " + line);
        }
        MapCoords.getInstanceof().setMapPoint(
                (gson.fromJson(jsonString, MapCoords.class)).getMapPoint());

I have to start MapPage Activity here. My MapPage Activity code is as follows:

        public class MapPage extends FragmentActivity {
    ArrayList<Cood> cd = MapCoords.getInstanceof().getMapPoint().getCood();
    Double latitude = cd.get(0).getLatitude();
    Double longitude = cd.get(0).getLongitude();
    LatLng point1;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.basic_demo);
        Toast.makeText(this, "Entered MapPage Activity", Toast.LENGTH_LONG)
                .show();
        setUpMapIfNeeded();

    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMapIfNeeded();
    }

    private void setUpMapIfNeeded() {

        if (mMap == null) {
            mMap = ((SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.map)).getMap();
            point1 = new LatLng(latitude, longitude);
            mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(point1, 17));
            if (mMap != null) {
                setUpMap();
            }
        }
    }

    private void setUpMap() {
        mMap.addMarker(new MarkerOptions()
                .position(point1)
                .title("Point1")
                .snippet("This is the first GPS co-ordinate"));
    }

}
Ajeett
  • 814
  • 2
  • 7
  • 18

1 Answers1

2

You can start your activity from anywhere you want. you might have to add a new_task flag to your intent.

    Intent intent = new Intent(context, MapPage.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(intent); 

If your background thread is inside a service, you can pass your_service_class.this as the context. otherwise you will have to pass the context to the background thread, if its a non-activity or a non-service class.

Sayed Jalil Hassan
  • 2,535
  • 7
  • 30
  • 42
  • I have edited my question to show the service class too. If I start the new activity in a new task, the older task is stopped, right? . I want the service to be running all the time. Is it possible for me to create an activity in the same task? –  Mar 26 '14 at 09:23
  • Starting the activity wont stop your service. It runs in the background until you stop it explicitly. – Sayed Jalil Hassan Mar 26 '14 at 09:40
  • and if you want your service to run periodically, you may consider using an intent service with an alarm manager. – Sayed Jalil Hassan Mar 26 '14 at 09:42
  • My application is crashing after I give the command to start the thread. It was working perfectly fine before I added code to start activity. Any help? The following [link](http://www.techotopia.com/index.php/A_Basic_Overview_of_Android_Threads_and_Thread_handlers) says "The second, equally important rule is that the code within a separate thread must never, under any circumstances, directly update any aspect of the user interface." What does it mean? –  Mar 26 '14 at 09:54
  • yes you can not update user interface from a background thread. Interface can only be modified from the UI thread post your logcat for the exact cause of the error. where are you updating the interface in the background thread ? i couldn't see any code in your service that is modifying the interface. – Sayed Jalil Hassan Mar 26 '14 at 10:37
  • I thought that starting an activity is considered as updation of interface. So, why is my app crashing? I added the code you gave me at the end of the thread. The last toast I can see is Toast.makeText(context, "before creating new thread for Track", Toast.LENGTH_SHORT).show(); that I gave in my service class before starting the thread. How do I debug? Please suggest. Thankyou for all the previous replies. –  Mar 26 '14 at 10:51
  • you should see and post the logcat of your application. There is no way otherwise to see whats causing the crash. your IDE should have a logcat window in it. monitor that and post the stack trace – Sayed Jalil Hassan Mar 26 '14 at 11:03
  • My app takes GPS data. So I have to disconnect it and use only the installation on the phone. Is there a way to simulate GPS data? –  Mar 26 '14 at 11:07
  • yes why not. you can set any location using emulator controls. google it and you will find plenty of examples on how to emulate location. – Sayed Jalil Hassan Mar 26 '14 at 11:22
  • also if its inevitable to use the phone, you could use a bug reporting library to upload the crash reports to your own server. ACRA is a good library for this purpose. – Sayed Jalil Hassan Mar 26 '14 at 11:57