I'm a beginner in Android Studio. I've recently picked up some Demo Apps for managing BLE devices, made them work separately, and am now trying to join two of them in a single App. Both Apps used a BLE Service, so I have to join them into a single service (or have them work together).
While looking at the code I noticed that one of these Service classes has no onCreate() method. Then I looked into the implementation and found the Service is Instantiated using a nested class of the Service that extends the Binder class.
Here's the relevant code from the service class:
#SuppressLint("NewApi")
public class BluetoothLeService extends Service {
private final String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private BluetoothGattCharacteristic mNotifyCharacteristic;
private static EncryptDecode encryptDecode = new EncryptDecode(); // Encryption and Decryption tool task
private IBleOperateCallback mBleOperateCallback;
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBleOperateCallback.bleData(SmctConstant.KEY_BLE_CONNECT_STATE, SmctConstant.VALUE_BLE_CONNECTED);
Log.i(TAG, "Connected to GATT server.");
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mBleOperateCallback.bleData(SmctConstant.KEY_BLE_CONNECT_STATE, SmctConstant.VALUE_BLE_DISCONNECTED);
close();
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
mBleOperateCallback.bleData(SmctConstant.KEY_BLE_CONNECT_STATE,
SmctConstant.VALUE_BLE_SERVICE_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
};
public class LocalBinder extends Binder {
public BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
/**
* Initializes a reference to the local Bluetooth adapter.
*
* #return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter
// through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
...
SOME MORE FUNCTIONS...
...
}
And this is how the Service instance gets declared in the Activity that uses it:
BluetoothLeService mBluetoothLeService;
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
I am trying to understand: how exactly is the Class instantiated without the onCreate() method? I've checked the onCreate() method from the Service class and it just throws and exception. I need to understand it because the other service I'm using does have such method and I want to join them.
Also: What is the difference between using this LocalBinder nested class and straight up using a class constructor?
EDIT: Here's the onCreate() method from the extended class Service. You can see it just throws a Runtime Exception. onStart() is identical.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package android.app;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.IBinder;
import java.io.FileDescriptor;
import java.io.PrintWriter;
public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
public static final int START_CONTINUATION_MASK = 15;
public static final int START_FLAG_REDELIVERY = 1;
public static final int START_FLAG_RETRY = 2;
public static final int START_NOT_STICKY = 2;
public static final int START_REDELIVER_INTENT = 3;
public static final int START_STICKY = 1;
public static final int START_STICKY_COMPATIBILITY = 0;
public static final int STOP_FOREGROUND_DETACH = 2;
public static final int STOP_FOREGROUND_REMOVE = 1;
public Service() {
super((Context)null);
throw new RuntimeException("Stub!");
}
public final Application getApplication() {
throw new RuntimeException("Stub!");
}
public void onCreate() {
throw new RuntimeException("Stub!");
}
/** #deprecated */
#Deprecated
public void onStart(Intent intent, int startId) {
throw new RuntimeException("Stub!");
}
public int onStartCommand(Intent intent, int flags, int startId) {
throw new RuntimeException("Stub!");
}
public void onDestroy() {
throw new RuntimeException("Stub!");
}
public void onConfigurationChanged(Configuration newConfig) {
throw new RuntimeException("Stub!");
}
public void onLowMemory() {
throw new RuntimeException("Stub!");
}
public void onTrimMemory(int level) {
throw new RuntimeException("Stub!");
}
public abstract IBinder onBind(Intent var1);
public boolean onUnbind(Intent intent) {
throw new RuntimeException("Stub!");
}
public void onRebind(Intent intent) {
throw new RuntimeException("Stub!");
}
public void onTaskRemoved(Intent rootIntent) {
throw new RuntimeException("Stub!");
}
public final void stopSelf() {
throw new RuntimeException("Stub!");
}
public final void stopSelf(int startId) {
throw new RuntimeException("Stub!");
}
public final boolean stopSelfResult(int startId) {
throw new RuntimeException("Stub!");
}
public final void startForeground(int id, Notification notification) {
throw new RuntimeException("Stub!");
}
public final void stopForeground(boolean removeNotification) {
throw new RuntimeException("Stub!");
}
public final void stopForeground(int flags) {
throw new RuntimeException("Stub!");
}
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
throw new RuntimeException("Stub!");
}
}
EDIT2: As Gabe pointed out in his answer: This is just the stub code from the Service, not the actual implementation. So I got confused by the onCreate() method that Android Studio showed me.
There's a default implementation of onCreate in the Service class. If you don't override it, you just use that default implementation. That's sufficient to create the Service correctly, if you don't need additional logic.
Your other question should be asked separately (1 question per post), but there's not enough code for me to answer it- I have no idea what the variable service is. However, you never create a service via constructor- it will not be initialized properly. You always call startService or bindService and let Android create it.
Related
I require a service to send messages to the Cloud while receiving data from the device as a result I have the following code:
public class MessageService extends Service {
private int mAlert = 0;
private PanicReceiver mPanicReceiver;
#Override
public void onCreate() {
super.onCreate();
mPanicReceiver = new PanicReceiver();
IntentFilter panicFilter = new IntentFilter();
panicFilter.addAction(Constants.PANIC_ON_RECEIVER_ACTION);
panicFilter.addAction(Constants.PANIC_OFF_RECEIVER_ACTION);
registerReceiver(mPanicReceiver, panicFilter);
}
#Override
public void onDestroy() {
unregisterReceiver(mPanicReceiver);
super.onDestroy();
}
private class PanicReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case Constants.PANIC_ON_RECEIVER_ACTION:
mAlert = 2;
break;
case Constants.PANIC_OFF_RECEIVER_ACTION:
mAlert = 0;
break;
}
}
}
}
I would like to seperate the broadcast receiver to a seperate file. How can you do that?
MessageService.class
public class MessageService extends Service {
private PanicReceiver mPanicReceiver;
#Override
public void onCreate() {
super.onCreate();
mPanicReceiver = new PanicReceiver();
IntentFilter panicFilter = new IntentFilter();
panicFilter.addAction(Constants.PANIC_ON_RECEIVER_ACTION);
panicFilter.addAction(Constants.PANIC_OFF_RECEIVER_ACTION);
registerReceiver(mPanicReceiver, panicFilter);
}
#Override
public void onDestroy() {
unregisterReceiver(mPanicReceiver);
super.onDestroy();
}
private int getAlert() {
return mPanicReceiver.getAlert();
}
}
PanicReceiver.java
private class PanicReceiver extends BroadcastReceiver {
private int mAlert = 0;
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case Constants.PANIC_ON_RECEIVER_ACTION:
this.setAlert(2);
break;
case Constants.PANIC_OFF_RECEIVER_ACTION:
this.setAlert(0);
break;
}
}
public int getAlert() {
return mAlert;
}
public void setAlert(int mAlert) {
this.mAlert = mAlert;
}
}
Just move mAlert from MessageService to PanicReceiver, than you can use the IDE to assist you to refactor out the class pressing F6 with the cursor upside the class name, or with a right click:
I am trying to make example of Play Billing application described here
In Last step they have described
To clean all the resources and unregister the observer, you just need to call BillingClient.endConnection. So define a method with this call inside BillingManager and then call it from GamePlayActivity.onDestroy:
according to above information I have made function called destroy like this in BillingManagerjava class.
public void destroy() {
mBillingClient.endConnection();
}
My Full BillingManager Class is like below
public class BillingManager implements PurchasesUpdatedListener {
private final BillingClient mBillingClient;
private final Activity mActivity;
private static final String TAG = "BillingManager";
public BillingManager(Activity activity) {
mActivity = activity;
mBillingClient = BillingClient.newBuilder(mActivity).setListener(this).build();
mBillingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(#BillingClient.BillingResponse int billingResponse) {
if (billingResponse == BillingClient.BillingResponse.OK) {
Log.i(TAG, "onBillingSetupFinished() response: " + billingResponse);
} else {
Log.w(TAG, "onBillingSetupFinished() error code: " + billingResponse);
}
}
#Override
public void onBillingServiceDisconnected() {
Log.w(TAG, "onBillingServiceDisconnected()");
}
});
}
public void startPurchaseFlow(final String skuId, final String billingType) {
// Specify a runnable to start when connection to Billing client is established
Runnable executeOnConnectedService = new Runnable() {
#Override
public void run() {
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setType(billingType)
.setSku(skuId)
.build();
mBillingClient.launchBillingFlow(mActivity, billingFlowParams);
}
};
// If Billing client was disconnected, we retry 1 time
// and if success, execute the query
startServiceConnectionIfNeeded(executeOnConnectedService);
}
#Override
public void onPurchasesUpdated(#BillingClient.BillingResponse int responseCode,
List<Purchase> purchases) {
Log.d(TAG, "onPurchasesUpdated() response: " + responseCode);
}
private static final HashMap<String, List<String>> SKUS;
static
{
SKUS = new HashMap<>();
SKUS.put(BillingClient.SkuType.INAPP, Arrays.asList("gas", "premium"));
SKUS.put(BillingClient.SkuType.SUBS, Arrays.asList("gold_monthly", "gold_yearly"));
}
public List<String> getSkus(#BillingClient.SkuType String type) {
return SKUS.get(type);
}
public void querySkuDetailsAsync(#BillingClient.SkuType final String itemType,
final List<String> skuList, final SkuDetailsResponseListener listener) {
// Specify a runnable to start when connection to Billing client is established
Runnable executeOnConnectedService = new Runnable() {
#Override
public void run() {
SkuDetailsParams skuDetailsParams = SkuDetailsParams.newBuilder()
.setSkusList(skuList).setType(itemType).build();
mBillingClient.querySkuDetailsAsync(skuDetailsParams,
new SkuDetailsResponseListener() {
#Override
public void onSkuDetailsResponse(int responseCode,
List<SkuDetails> skuDetailsList) {
listener.onSkuDetailsResponse(responseCode, skuDetailsList);
}
});
}
};
// If Billing client was disconnected, we retry 1 time
// and if success, execute the query
startServiceConnectionIfNeeded(executeOnConnectedService);
}
private void startServiceConnectionIfNeeded(final Runnable executeOnSuccess) {
if (mBillingClient.isReady()) {
if (executeOnSuccess != null) {
executeOnSuccess.run();
}
} else {
mBillingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(#BillingClient.BillingResponse int billingResponse) {
if (billingResponse == BillingClient.BillingResponse.OK) {
Log.i(TAG, "onBillingSetupFinished() response: " + billingResponse);
if (executeOnSuccess != null) {
executeOnSuccess.run();
}
} else {
Log.w(TAG, "onBillingSetupFinished() error code: " + billingResponse);
}
}
#Override
public void onBillingServiceDisconnected() {
Log.w(TAG, "onBillingServiceDisconnected()");
}
});
}
}
public void destroy() {
mBillingClient.endConnection();
}
}
And My GamePlayActivity is like below
public class GamePlayActivity extends FragmentActivity implements BillingProvider {
#Override
protected void onDestroy() {
super.onDestroy();
// I want call method here
}
}
Now I want call above function in my game play activity. I have no idea how to call it.
As it mentioned in documentation
call it from GamePlayActivity.onDestroy
but you defined your own method.
Override onDestroy method of GamePlayActivity and put mBillingClient.endConnection(); into it.
#Override
protected void onDestroy() {
mBillingClient.endConnection();
}
I assume your Activity already has an instance of the BillingManager
public class GamePlayActivity extends FragmentActivity implements BillingProvider {
BillingManager bm; // assign this in onCreate
#Override
protected void onDestroy() {
super.onDestroy();
bm.destroy();
}
}
I am working on a project that has a class for GPS
I know that to call a class I have to use instant of the class
something like this
GPS insgps = new GPS();
if (insgps .canGetLocation())
{/* Do Something */}
but when I try to use this code I get error
GPS has private access in 'com.myapp.locationapp.app.GPS'
I dont know why and how to fix that?
here is the class I use
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
public final class GPS implements LocationListener, ActivityCompat.OnRequestPermissionsResultCallback {
private static GPS _instance = new GPS();
private static Activity _activity;
private static boolean _isGPSEnabled = false;
private static boolean _isNetworkEnabled = false;
private static boolean _canGetLocation = false;
private static boolean _isPermissionEnabled = false;
private Location _location;
private double _latitude;
private double _longitude;
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 1; // 10 meters
private static final long MIN_TIME_BW_UPDATES = 1; // 1 minute
private static LocationManager _locationManager;
private LocationPermissionResponseListener _locationPermissionListener;
public static final int LOCATION_REQUEST_CODE = 200;
private GPS() {}
public static GPS sharedInstance(Activity activity) {
_activity = activity;
_locationManager = (LocationManager) _activity.getSystemService(Context.LOCATION_SERVICE);
_isGPSEnabled = _locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
_isNetworkEnabled = _locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!_isGPSEnabled && !_isNetworkEnabled) {
_canGetLocation = false;
} else {
_canGetLocation = true;
}
if (ActivityCompat.checkSelfPermission(_activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
_isPermissionEnabled = false;
} else {
_isPermissionEnabled = true;
}
return _instance;
}
public Location getLastKnownLocation() {
if (ActivityCompat.checkSelfPermission(_activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
_isPermissionEnabled = false;
} else {
if (_canGetLocation) {
if (_isNetworkEnabled) {
_locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (_locationManager != null) {
_location = _locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (_location != null) {
_latitude = _location.getLatitude();
_longitude = _location.getLongitude();
}
}
}
if (_isGPSEnabled) {
if (_location == null) {
_locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (_locationManager != null) {
_location = _locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (_location != null) {
_latitude = _location.getLatitude();
_longitude = _location.getLongitude();
}
}
}
}
}
}
return _location;
}
public void stopUsingGPS() {
if (_locationManager != null) {
if (ActivityCompat.checkSelfPermission(_activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
_locationManager.removeUpdates(GPS.this);
}
}
}
public double getLatitude() {
if (_locationManager != null) {
_latitude = _location.getLatitude();
}
return _latitude;
}
public double getLongitude() {
if (_locationManager != null) {
_longitude = _location.getLongitude();
}
return _longitude;
}
public boolean canGetLocation() {
return _canGetLocation;
}
public boolean isPermissionEnabled() {
return _isPermissionEnabled;
}
public void showSettingsAlert() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(_activity);
alertDialog.setTitle("GPS Settings");
alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu ?");
alertDialog.setPositiveButton("Settings",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(
Settings.ACTION_LOCATION_SOURCE_SETTINGS);
_activity.startActivity(intent);
}
});
alertDialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
public void requestLocationPermission(LocationPermissionResponseListener listener) {
_locationPermissionListener = listener;
ActivityCompat.requestPermissions(_activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE);
}
#Override
public void onLocationChanged(Location location) {
this._location = location;
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case GPS.LOCATION_REQUEST_CODE: {
_locationPermissionListener.onResponse(grantResults[0] == PackageManager.PERMISSION_GRANTED);
}
}
}
public static interface LocationPermissionResponseListener {
public void onResponse(Boolean permissionGranted);
}
}
From the looks of it, GPS is a singleton class.
There is a private static field _instance of type GPS and there is also a static method called sharedInstance(Activity). These are features of a singleton.
A singleton class basically means that there will only be one instance of the class at runtime. In this case, it is _instance. It is not allowed to create other instances of GPS. That is why the constructor is marked private, making you unable to access it.
Because if this, you should not create a new instance of GPS. You should instead access the only one instance by calling the method sharedInstance.
GPS insgps = GPS.sharedInstance(anActivity);
If you're writing this code in a subclass of Activity, replace anActivity above with this. If you're writing this code in some other class, get an instance of Activity and replace anActivity with it.
Your constructor is private:
private GPS() {}
This would need to be public
public GPS() {}
Saying that however, it looks like your class is using a shared instance function so you'd likely want:
GPS insgps = GPS.sharedInstance([myactivitycontext]);
I'm trying to run a background service in React-Native. From what I've heard I need to write it in native Java and connect it to the react-native code. When I try to emit an event I get an error:
Tried to access a JS module before the React instance was fully set up. Calls to should only happen once initialize() has been called on your native module.
So I added a check to see if the Module is running:
if (reactContext.getLifecycleState() == LifecycleState.RESUMED)
But it always returns false. The lifecycle is stuck on BEFORE_CREATE. How should I emit my event.
Service:
public class TestService extends Service {
double distance = 0.0;
ReactContext reactContext;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
reactContext = new ReactContext(getApplicationContext());
new Timer().scheduleAtFixedRate(new TimerTask(){
#Override
public void run(){
WritableMap params = Arguments.createMap();
distance+= 0.7;
Log.d("LOG", "Trying to send distance: "+distance+" on lifecycle: "+reactContext.getLifecycleState());
params.putDouble("distance", distance);
sendEvent(reactContext, "updateDistance", params);
}
},0,1000);
return START_STICKY;
}
private void sendEvent(ReactContext reactContext, String eventName, #Nullable WritableMap params) {
if (reactContext.getLifecycleState() == LifecycleState.RESUMED) {
reactContext.getJSModule(DeviceEventManagerModule
.RCTDeviceEventEmitter.class)
.emit(eventName, params);
Log.d("LOG", "Sent distance: "+distance);
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Module:
public class ServiceModule extends ReactContextBaseJavaModule {
ReactContext reactContext;
public ServiceModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
this.initialize();
}
#ReactMethod
public void startTrackingService() {
Intent intent = new Intent(reactContext, TestService.class);
reactContext.startService(intent);
}
#Override
public String getName() {
return "ServiceModule";
}
}
Package:
public class ServicePackage implements ReactPackage {
#Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ServiceModule(reactContext));
return modules;
}
#Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
#Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
MainApplication:
#Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new ReactNativePushNotificationPackage(),
new ServicePackage()
);
}
I solved it :)
In the service I was creating a new context from base context which is NOT the same object. The workaround was to broadcast the data from the service and then send them do javascript.
ServiceModule:
public class ServiceModule extends ReactContextBaseJavaModule {
public static String UPDATE = "updateDistance";
public static String DISTANCE = "distance";
private IntentFilter intentFilter;
private BroadcastReceiver receiver;
public ServiceModule(ReactApplicationContext reactContext) {
super(reactContext);
initializeBroadcastReceiver();
}
#ReactMethod
public void startTrackingService() {
Intent intent = new Intent(getReactApplicationContext(), TestService.class);
getReactApplicationContext().startService(intent);
}
#ReactMethod
public void stopTrackingService() {
Intent intent = new Intent(getReactApplicationContext(), TestService.class);
getReactApplicationContext().stopService(intent);
}
private void sendEvent(ReactContext reactContext, String eventName, #Nullable WritableMap params) {
if (reactContext.hasActiveCatalystInstance()) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
}
private void initializeBroadcastReceiver() {
intentFilter = new IntentFilter();
intentFilter.addAction(UPDATE);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
WritableMap params = Arguments.createMap();
params.putDouble(DISTANCE, intent.getDoubleExtra(DISTANCE, 0));
sendEvent(getReactApplicationContext(), UPDATE, params);
}
};
getReactApplicationContext().registerReceiver(receiver, intentFilter);
}
#Override
public String getName() {
return "ServiceModule";
}
}
TestService:
public class TestService extends Service {
double distance = 0.0;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Timer().scheduleAtFixedRate(new TimerTask(){
#Override
public void run(){
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(ServiceModule.UPDATE);
broadcastIntent.putExtra(ServiceModule.DISTANCE, distance);
sendBroadcast(broadcastIntent);
distance+= 0.7;
}
},0,1000);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I need to execute some tasks when my application is closed.
I have made a service for do this and tried many things, but i don't have the good result.
If someone have a tutorial or some path to follow, it would be great
This is my service:
public class TrackersImporter extends Service {
private static TrackersImporter instance;
private static long refreshDelay = 1; // Minutes
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private boolean isInit = false;
public ArrayList<Tracker> trackers = new ArrayList<>();
public static TrackersImporter getInstance(){
if (instance == null)
instance = new TrackersImporter();
return instance;
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("TrackersImporter",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
Message message = mServiceHandler.obtainMessage();
message.arg1 = startId;
mServiceHandler.sendMessage(message);
} catch (Exception e) {
Log.w("TrackersImporter", e.getMessage());
}
return START_STICKY;
}
public void addTracker(Tracker tracker) {
trackers.add(tracker);
}
protected void showToast(final String msg){
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
});
}
// Object responsible for
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
addTracker(Runkeeper.getInstance(MainActivity.getActivity()));
addTracker(Strava.getInstance(MainActivity.getActivity()));
startImport(MainActivity.getActivity().getBaseContext(), MainActivity.getActivity().getAppUser(), trackers);
stopSelf(msg.arg1);
}
/**
* Perform data imports.
* Imports are performed only 1 time.
* Additional calls to this method are equivalent to no-op.
* Call init() then performImport() for each TrackerImportable
* #param user user receiving the datas
*/
public void startImport(Context context, User user, ArrayList<Tracker> trackers) {
Context ctx = MainActivity.getActivity().getApplicationContext();
LocalDateTime now = new LocalDateTime();
if (Preferences.getPref(ctx, "tracker_import_date") == "")
Preferences.setPref(ctx, "tracker_import_date", now.toString());
LocalDateTime past = LocalDateTime.parse(Preferences.getPref(ctx, "tracker_import_date"));
long duration = new Duration(past.toDateTime(), now.toDateTime()).getStandardMinutes();
if (isInit)
return;
if (duration > refreshDelay) {
Preferences.setPref(ctx, "tracker_import_date", now.toString());
for (Tracker tracker : trackers) {
if (tracker.isEnabled() && Tracker.isUserEnabled(context, tracker.getName())) {
tracker.init();
tracker.performImport(user);
}
}
}
isInit = true;
}
}
}
This is my mainActivity
public class MainActivity extends BaseActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
if (ConnectivityUtil.isConnected(this.getApplicationContext())) {
initGoogleFit();
initTrackers(appUser);
}
}
private void initTrackers(User user) {
Intent trackersIntentService = new Intent(this, TrackersImporter.class);
trackersIntentService.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startService(trackersIntentService);
}
#Override
protected void onResume() {
...
if (ConnectivityUtil.isConnected(this.getApplicationContext())) {
initTrackers(appUser);
}
}
}
First Create one launcher Activity which is like your Main Activity.
In Activity "onCreate" Method you need to start Service and Do Some thing if you wont in Service "onStartCommand" Method.
public class MainActivity extends Activity {
ArrayList<Integer> list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(MainActivity.this,TrackersImporter.class);
}
public class TrackersImporter extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// do something
Log.v(TAG ,"Service is started");
}
}
And also Register this Service at manifest.xml like this.
<service android:name=".TrackersImporter"></service>
if you like stop service
stopService(new Intent(MainActivity.this,TrackersImporter.class);