Unable to run a service via the react native bridge - android

I have created a native module in Java which is responsible for running a service in background.
I have this method in ClassA:
#ReactMethod
public void startService(final Promise promise) {
Intent intent = new Intent(getCurrentActivity(), BackgroundService.class);
intent.putExtra(BackgroundService.FILENAME, "test123.html");
intent.putExtra(BackgroundService.URL,
"http://www.vogella.com/index.html");
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
promise.reject("Activity doesnt exist");
} else {
getCurrentActivity().startService(intent);
}
}
Here is the code in BackgroundService:
public class BackgroundService extends IntentService {
private int result = Activity.RESULT_CANCELED;
public static final String URL = "urlpath";
public static final String FILENAME = "filename";
public static final String FILEPATH = "filepath";
public static final String RESULT = "result";
public static final String NOTIFICATION = "com.vogella.android.service.receiver";
public BackgroundService() {
super("BackgroundService");
}
public String getName() {
return "BackgroundService";
}
#Override
protected void onHandleIntent(Intent intent) {
//do stuff
ClassA.servicePromise.resolve("done with service!");
}
servicePromise is defined in classA as so :
public static Promise servicePromise = null;
The problem, if I am understanding it correctly, is that getCurrentActivity.startService(intent) does not execute properly. I am able to successfully return a promise inside startService after getCurrentActivity.startService(intent), so I know the problem is not with how I am calling startService. However, I am unable to return the promise from inside BackgroundService, which is what I want.
Inside the onHandleIntent, I tried calling ClassA.servicePromise.resolve("done with service!"); before executing any other code just to test if it works, but it doesn't.
In my manifest, I have added the service as follows:
<service android:name="com.smaplePakcage.name.BackgroundService"
android:exported="false">
</service>

Related

Firebase database not getting updated when updating it from intent service

I have created a background intent service to update data in the firebase database.
When my application is in foreground, the data is updated properly. But when my application is killed, the data is not updated in the firebase database.
Service declare in manifest file
<service
android:name=".service.MyIntentService"
android:enabled="true"
android:exported="true"></service>
The Intent service class that works properly when my app is in the foreground but not when the app is in the background.
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.softwebsolutions.datetime.DateTime;
import com.softwebsolutions.devicemanagement.bean.WifiStatus;
import com.softwebsolutions.devicemanagement.utils.Utility;
/**
* An {#link IntentService} subclass for handling asynchronous task requests in
* a service on a separate handler thread.
* <p>
* TODO: Customize class - update intent actions, extra parameters and static
* helper methods.
*/
public class MyIntentService extends IntentService {
// TODO: Rename actions, choose action names that describe tasks that this
// IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
private static final String ACTION_FOO =
"com.softwebsolutions.devicemanagement.service.action.FOO";
private static final String ACTION_BAZ =
"com.softwebsolutions.devicemanagement.service.action.BAZ";
// TODO: Rename parameters
private static final String EXTRA_PARAM1 =
"com.softwebsolutions.devicemanagement.service.extra.PARAM1";
private static final String EXTRA_PARAM2 =
"com.softwebsolutions.devicemanagement.service.extra.PARAM2";
private static final String EXTRA_PARAM3 =
"com.softwebsolutions.devicemanagement.service.extra.PARAM3";
private static final String TAG = MyIntentService.class.getSimpleName();
public MyIntentService() {
super("MyIntentService");
}
// TODO: Customize helper method
public static void startActionFoo(Context context, String param1, String param2, String param3) {
Intent intent = new Intent(context, MyIntentService.class);
intent.setAction(ACTION_FOO);
intent.putExtra(EXTRA_PARAM1, param1);
intent.putExtra(EXTRA_PARAM2, param2);
intent.putExtra(EXTRA_PARAM3, param3);
context.startService(intent);
}
#Override protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
final String wifiMac = intent.getStringExtra(EXTRA_PARAM1);
final String strSSID = intent.getStringExtra(EXTRA_PARAM2);
final String macAddress = intent.getStringExtra(EXTRA_PARAM3);
handleActionFoo(wifiMac, strSSID, macAddress, getApplicationContext());
}
}
private void handleActionFoo(final String wifiMac, final String strSSID,
final String macAddress, final Context context) {
Log.e(TAG, "onReceive.......service........");
DatabaseReference mDatabaseTmp =
FirebaseDatabase.getInstance().getReference("Android").child("wifiList").child(wifiMac);
mDatabaseTmp.addValueEventListener(new ValueEventListener() {
#Override public void onDataChange(DataSnapshot dataSnapshot) {
Log.e(TAG, "onReceive.......addValueEventListener");
if (dataSnapshot != null) {
Log.e(TAG, "onReceive.......dataSnapshot...NOT NULL");
String floorName = "Not detect";
if (dataSnapshot.getValue() != null) {
floorName = dataSnapshot.getValue().toString();
Log.e(TAG, "onReceive: ----------->" + floorName);
}
}
}
#Override public void onCancelled(DatabaseError databaseError) {
}
});
mDatabaseTmp.addListenerForSingleValueEvent(new ValueEventListener() {
#Override public void onDataChange(DataSnapshot dataSnapshot) {
Log.e(TAG, "onReceive.......dataSnapshot...");
if (dataSnapshot != null) {
Log.e(TAG, "onReceive.......dataSnapshot...NOT NULL");
String floorName = "Not detect";
if (dataSnapshot.getValue() != null) {
floorName = dataSnapshot.getValue().toString();
}
String currentDate =
DateTime.getInstance().getCurrentDateTime(" yyyy-MM-dd'T'HH:mm:ss.SSSS'Z'");
Log.e(TAG, "onReceive.......dataSnapshot..."
+ currentDate
+ " Floor Name -------->"
+ floorName);
String deviceId = Utility.getDeviceID(context);
WifiStatus wifiStatus = new WifiStatus();
wifiStatus.setDeviceId(deviceId);
wifiStatus.setName(strSSID);
wifiStatus.setMacAddress(macAddress);
wifiStatus.setDate(currentDate);
wifiStatus.setStatus(WifiStatus.STATUS_CONNECTED);
wifiStatus.setFloorName(floorName);
Utility.updateWifiStatus(context, wifiStatus);
} else {
Log.e(TAG, "onReceive.......dataSnapshot...NULL");
}
}
#Override public void onCancelled(DatabaseError databaseError) {
}
});
}
}
An IntentService only stays active for as long as it takes handleIntent() to service the next intent, and there are no more pending intents. You can think of each intent as a "command" to the service, and it will run for as long as it takes that command to complete. When the last command is done, it stops itself. As such, it does not typically stay running for very long. If you're expecting an IntentService to stay running for a long time, you probably don't want to be using an IntentService at all.
Also, Android Services don't care if the app is in the foreground (visible) or background (invisible). They can be started and stopped regardless. The process that hosts the app may stay running indefinitely.
You haven't really stated what you're trying to accomplish with this service, so it's impossible to say what you should be doing instead. If you want a listener to be active for as long as the service is "started", then IntentService is not the right tool. You should look into a custom implementation.

Android: Does Custom View have startService

I am having a Custom View which uploading image to the server when clicked.
I get the context using getContext and use it to call start the intent service. Somehow the service didn't get started when I make a checkpoint at the onHandleIntent or onStartCommand. I have placed a reference in the manifest.
This is the code call to service in which the code was inside the Custom View which extending the ImageView:
new GraphicUtilitiesV2.SimpleImageLoadingCallback() {
#Override
public void imageAvailable(Object sender, String data) {
if (_formCOC != null && _formType != null) {
Gson gson = new Gson();
String formCOC = gson.toJson(_formCOC);
UploadAttachmentService.startActionAttachmentDeclarative
(getContext(), formCOC, _formType.getValue(), data);
}
}
});
This is my demo code of the AttachmentUploadService class :
private static final String ACTION_DECLARATIVE = "blah.Service.action.DeclarativeAttachment";
private static final String EXTRA_FORM = "blah.CERTIFI.Service.extra.Form";
private static final String EXTRA_TYPE = "blah.Service.extra.FormType";
private static final String EXTRA_DATA = "blah.Service.extra.Data";
public static void startActionAttachmentDeclarative(Context context, String form, String type, String data) {
Intent intent = new Intent(context, UploadAttachmentService.class);
intent.setAction(ACTION_DECLARATIVE);
intent.putExtra(EXTRA_FORM, form);
intent.putExtra(EXTRA_TYPE, type);
intent.putExtra(EXTRA_DATA, data);
context.startService(intent);
}
public UploadAttachmentService() {
super("UploadService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_DECLARATIVE.equals(action)) {
final String param1 = intent.getStringExtra(EXTRA_FORM);
final String param2 = intent.getStringExtra(EXTRA_DATA);
handleActionAttachmentDeclarative(param1, param2);
}
}
}
public void handleActionAttachmentDeclarative(String form, String data) {
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
There are no error or force close as well.
This is my manifest part:
<service
android:name=".Service.UploadAttachmentService"
android:exported="false" >
</service>
The UploadAttachmentService file was stored in a Service folder.

Is possible to initiate an Intent Service from Thread?

I'm trying to implementing a parallel download using a Thread, but all my unzip process should be sequentially. As is known Intent Service enqueue all pending task so in the end of all my downloads I'm trying to start a intent service. The problem is that I'm getting the following error:
05-30 11:49:10.520: E/AndroidRuntime(18790): FATAL EXCEPTION: main
05-30 11:49:10.520: E/AndroidRuntime(18790): java.lang.RuntimeException: Unable to instantiate service br.com.facilit.target.app.android.util.UnzipService: java.lang.InstantiationException: can't instantiate class br.com.facilit.target.app.android.util.UnzipService; no empty constructor
My Download Thread:
public class DownloadService implements Runnable {
Activity controller;
boolean post;
String urlParent;
String filePath;
String destinationPath;
ResultReceiver mReceiver;
String typeDownload;
MetaDados metaDado;
int index;
boolean isResuming;
File jsonFile = new File(Constants.DEST_PATH_PARENT + Constants.JSON_FILES_PATH);
File jsonTempFile;
public DownloadService(Activity controller, boolean post, String urlParent, String filePath,
String destinationPath, ResultReceiver mReceiver, String typeDownload, int index, MetaDados metaDado,
boolean isResuming) {
this.controller = controller;
this.post = post;
this.urlParent = urlParent;
this.filePath = filePath;
this.destinationPath = destinationPath;
this.mReceiver = mReceiver;
this.typeDownload = typeDownload;
this.index = index;
this.metaDado = metaDado;
this.isResuming = isResuming;
}
#Override
public void run() {
Log.d(Constants.DOWNLOAD_AND_UNZIP_SERVICE, "Começando processo de download");
// ALL DOWNLOAD PROCESS
// THEN CALL INTENT FOR UNZIP
final Intent service = new Intent(controller.getApplicationContext(), UnzipService.class);
service.putExtra("post", false);
service.putExtra("filePath", filePath);
service.putExtra("destinationPath", destinationPath);
service.putExtra("receiver", mReceiver);
service.putExtra("typeDownload", Constants.HTML);
service.putExtra("metaDado", metaDado);
service.putExtra("isResuming", false);
controller.runOnUiThread(new Runnable() {
#Override
public void run() {
controller.startService(service);
}
});
}
}
My Unzip Intent Service:
public class UnzipService extends IntentService {
public UnzipService(String name) {
super("UnzipService");
}
#Override
protected void onHandleIntent(Intent intent) {
String filePath = intent.getStringExtra("filePath");
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
Log.d("UnzipService", "Simulando descompactação de arquivo " + filePath);
} catch (InterruptedException e) {
}
}
}
}
Manifest:
<service android:name="br.com.facilit.target.app.android.util.UnzipService"/>
as the exception reports you have no empty constructor Change it in:
public UnzipService() {
super("UnzipService");
}

Broadcast not received when intent contains parcelable extra

I have an IntentService that is making a network call and receiving back some JSON data. I package this response data in custom object that implements parcelable. If I add this parcelable object to an intent as an extra and then launch an activity using that intent, everything seems to work as expected, i.e. I can retrieve the parcelable from the intent in the newly created activity. However, if I create the intent from within the onHandleIntent() method of my IntentService and then use sendBroadcast(), the broadcast receiver's onReceive() method never fires. If I don't add the parcelable to the intent, though, the onReceive() method fires as expected. Following are some relevant code snippets:
Parcelable Object:
public class JsonResponse implements Parcelable {
private int responseCode;
private String responseMessage;
private String errorMessage;
public JsonResponse() {
}
/*
/ Property Methods
*/
public void setResponseCode(int code) {
this.responseCode = code;
}
public void setResponseMessage(String msg) {
this.responseMessage = msg;
}
public void setErrorMessage(String msg) {
this.errorMessage = msg;
}
/*
/ Parcelable Methods
*/
public static final Creator<JsonResponse> CREATOR = new Creator<JsonResponse>() {
#Override
public JsonResponse createFromParcel(Parcel parcel) {
return new JsonResponse(parcel);
}
#Override
public JsonResponse[] newArray(int i) {
return new JsonResponse[i];
}
};
private JsonResponse(Parcel parcel) {
responseCode = parcel.readInt();
responseMessage = parcel.readString();
errorMessage = parcel.readString();
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(responseCode);
parcel.writeString(responseMessage);
parcel.writeString(errorMessage);
}
#Override
public int describeContents() {
return 0;
}
}
onHandle() of IntentService:
protected void onHandleIntent(Intent intent) {
service = new LoginService();
service.login("whoever", "whatever");
JsonResponse response = new JsonResponse();
response.setResponseCode(service.responseCode);
response.setResponseMessage(service.responseMessage);
response.setErrorMessage(service.errorMessage);
Intent i = new Intent();
i.putExtra("jsonResponse", response);
i.setAction(ResultsReceiver.ACTION);
i.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(i);
}
Any ideas? Any insight would be greatly appreciated.
It appears that the problem has to do with the size of the object being added as an extra. When one of the string properties of the response object grows too large, the broadcast apparently fails. I have no sources to confirm this, only some trial and error in manipulating one of the strings while leaving all other variables of the equation constant.

how to pass data between service and it's application in the right way?

i'm a newbie in android. In my app i create a many-to-many chat, and need to update from server a list of Messages. In order to do so, i created a service that updates every second from the server.
My problem is that i don't know how to pass data back to the application. I know that I should do it using intent and broadcast receiver, but in that I stuck with Bundle object that i have to serialize in order to pass it to the app, and it does not make sense to me, since this operation is not that efficient.
For now i'm using the ref to my application (i think it's not that good but don't know why), and after every update from server in the service i activate the application function, and updates it's fields directly. Moreover i think maybe my code will do some good for beginners as well :)
public class UpdateChatService extends Service {
private static final long DELAY_FOR_CHAT_TASK = 0;
private static final long PERIOD_FOR_CHAT_TASK = 1;
private static final TimeUnit TIME_UNIT_CHAT_TASK = TimeUnit.SECONDS;
//private Task retryTask; TODO: check this out
private ScheduledExecutorService scheduler;
private boolean timerRunning = false;
private long RETRY_TIME = 200000;
private long START_TIME = 5000;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
scheduleChatUpdate();
}
private void scheduleChatUpdate() {
BiggerGameApp app = (BiggerGameApp) getApplication();
this.scheduler = Executors.newScheduledThreadPool(3);
this.scheduler.scheduleAtFixedRate(new UpdateChatTask(app),
DELAY_FOR_CHAT_TASK, PERIOD_FOR_CHAT_TASK,
TIME_UNIT_CHAT_TASK);
timerRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!timerRunning) {
scheduleChatUpdate();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
if (scheduler != null) {
scheduler.shutdown();
}
timerRunning = false;
}
}
Here is the code of the asynchronous task the runs in the service.
Please tell me what i'm doing wrong, and how should pass data from the service to the application.
public void run() {
try {
if (this.app.getLastMsgFromServer() == null) {
this.app.setLastMsgFromServer(new Message(new Player(DEFAULT_EMAIL), "", -1));
this.app.getLastMsgFromServer().setMessageId(-1);
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
.create();
ServerHandler serverHandler = new ServerHandler();
String jsonString = gson.toJson(this.app.getLastMsgFromServer());
// Sending player to servlet in server
String resultString = serverHandler.getResultFromServlet(jsonString, "GetListOfMessages");
if (resultString.contains("Error")) {
return;
}
// Parsing answer
JSONObject json = new JSONObject(resultString);
Status status = null;
String statusString = json.getString("status");
if (statusString == null || statusString.length() == 0)
return;
status = Status.valueOf(statusString);
if (Status.SUCCESS.equals(status)) {
ArrayList<Message> tempChat = null;
JSONArray jsonList = json.getJSONArray("data");
MyJsonParser jsonParser = new MyJsonParser();
tempChat = jsonParser.getListOfMessagesFromJson(jsonList.toString());
if (tempChat != null && tempChat.size() != 0) {
// After getting the chat from the server, it saves the last msg
// For next syncing with the server
this.app.setLastMsgFromServer(tempChat.get(LAST_MSG_INDEX));
tempChat.addAll(this.app.getChat());
if (tempChat.size() > SIZE_OF_USER_CHAT) {
tempChat = (ArrayList<Message>) tempChat.subList(0, SIZE_OF_USER_CHAT - 1);
}
this.app.setChat(tempChat);
this.app.updateViews(null);
}
}
return;
Is the Service local only (I'm going to assume "yes")?
Communication with a local-only service can be done by passing an instance of android.os.Binder back, as shown below:
public class UpdateChatService extends Service {
public static final class UpdateChat extends Binder {
UpdateChatService mInstance;
UpdateChat(UpdateChatService instance) {
mInstance = instance;
}
public static UpdateChat asUpdateChat(IBinder binder) {
if (binder instanceof UpdateChat) {
return (UpdateChat) binder;
}
return null;
}
public String pollMessage() {
// Takes a message from the list or returns null
// if the list is empty.
return mInstance.mMessages.poll();
}
public void registerDataSetObserver(DataSetObserver observer) {
mInstance.mObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mInstance.mObservable.unregisterObserver(observer);
}
}
private ScheduledExecutorService mScheduler;
private LinkedList<String> mMessages;
private DataSetObservable mObservable;
#Override
public IBinder onBind(Intent intent) {
return new UpdateChat(this);
}
#Override
public void onCreate() {
super.onCreate();
mObservable = new DataSetObservable();
mMessages = new LinkedList<String>();
mScheduler = Executors.newScheduledThreadPool(3);
mScheduler.scheduleAtFixedRate(new UpdateChatTask(), 0, 1, TimeUnit.SECONDS);
}
#Override
public void onDestroy() {
super.onDestroy();
mScheduler.shutdownNow();
mObservable.notifyInvalidated();
}
class UpdateChatTask implements Runnable {
int mN = 0;
public void run() {
// This example uses a list to keep all received messages, your requirements may vary.
mMessages.add("Message #" + (++mN));
mObservable.notifyChanged();
}
}
}
This example could be used to feed an Activity (in this case a ListActivity) like this:
public class ChattrActivity extends ListActivity implements ServiceConnection {
LinkedList<String> mMessages;
ArrayAdapter<String> mAdapter;
UpdateChat mUpdateChat;
DataSetObserver mObserver;
Runnable mNotify;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMessages = new LinkedList<String>();
mNotify = new Runnable() {
public void run() {
mAdapter.notifyDataSetChanged();
}
};
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mMessages);
getListView().setAdapter(mAdapter);
// Bind to the Service if you do not need it to persist when this Activity
// dies - otherwise you must call #startService(..) before!
bindService(new Intent(this, UpdateChatService.class), this, BIND_AUTO_CREATE);
}
/**
* #see android.app.ListActivity#onDestroy()
*/
#Override
protected void onDestroy() {
super.onDestroy();
if (mUpdateChat != null) {
mUpdateChat.unregisterDataSetObserver(mObserver);
unbindService(this);
}
}
public void onServiceConnected(ComponentName name, IBinder service) {
mUpdateChat = UpdateChat.asUpdateChat(service);
mObserver = new DataSetObserver() {
#Override
public void onChanged() {
String message;
while ((message = mUpdateChat.pollMessage()) != null) {
mMessages.add(message);
}
runOnUiThread(mNotify);
}
#Override
public void onInvalidated() {
// Service was killed - restart or handle this error somehow.
}
};
// We use a DataSetObserver to notify us when a message has been "received".
mUpdateChat.registerDataSetObserver(mObserver);
}
public void onServiceDisconnected(ComponentName name) {
mUpdateChat = null;
}
}
If you need to communicate across processes you should look into implementing an AIDL interface - but for "local" versions this pattern works just fine & doesn't involve abusing the global Application instance.
You can use a static memory shared between your service and rest of application (activities). If you do not plan to expose this service to external apps, then sharing static memory is better than serializing/deserializing data via bundles.
Bundles based approach is encouraged for components that are to be exposed to outside world. A typical app usually has just the primary activity exposed in app manifest file.
If your don't pulibc your service , the static memory and the callback function can do.
If not , you can send broadcast.

Categories

Resources