I want to develop Text-To-Speech (TTS) feature in my app. It must be implemented inside Service, because user may leave "details" Activity and get back to "main" Activity or even leave my app, and it should still speak out loud text. Since Oreo introduced some background limitations for services and I must support 4.0+ I have to use JobIntentService
Problem is that TTS have async implementation and JobIntentService gets killed just after onHandleWork finishes its job, even when I use startForeground (in my code showSpeakingNotification)
Funny part is that when I but a breakpoint inside onHandleWork after 'speakOut' method or just uncomment Thread.sleep service is working and reading my text (and foreground notification is present).
Question is how to prevent "auto-killing" my service when it is actually running, but using asynchronous feature inside?
#Override
protected void onHandleWork(#NonNull Intent intent) {
if (ACTION_SPEAK.equals(intent.getAction()) && intent.hasExtra(EXTRA_TEXT_ARRAY)) {
ArrayList<String> textArr = intent.getStringArrayListExtra(EXTRA_TEXT_ARRAY);
showSpeakingNotification(textArr.get(0));
if (ttsInitialized)
speakOut(textArr);
else if (ttsInitListener != null)
ttsInitListener.setPendingText(textArr);
} else if (ACTION_STOP_SPEAKING.equals(intent.getAction())) {
if (ttsInitialized && tts.isSpeaking())
tts.stop();
}
try {
//Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
just uncomment Thread.sleep service is working and reading my text
When you add Thread.sleep(10000); it blocks the current thread as a result, it doesn't respond to your speech. When you comment it current thread is free to read your data
Question is how to prevent "auto-killing" my service when it is
actually running, but using asynchronous feature inside?
Note possible. Your requirements can be fulfilled using Foreground Service. Refer to this SO for implementing the Foreground Service
Related
I have created an app. It starts a service(onStartCommand type).
It creates a thread that keeps on monitor the clipboard:
private class MonitorTask extends Thread {
#Override
public void run() {
mKeepRunning = true;
while (true) {
doTask(); //-this function uses the toast to show the string in clipboard
try {
Thread.sleep(300);
} catch (InterruptedException ignored) {
}
if (!mKeepRunning) {
break;
}
}
}
I found that the after some time passed, the service was still there (according to running service manager), but the thread disappeared. How can I keep the thread running forever until user closes the app.
I guess that may be InterruptedException, how can I use that catch to restart the Thread?
Some old threads mentioned using AlarmManager to "startup the service and do something, close the service" at regular interval, but i dont think it is a good idea?
Please let me know if there is a typical way to do so or any good idea? thanks in advance.
Update
in fact, i know there is ClipboardManager, but i know this one is not compatible to android 2.3.4. Besides, I would like to know if I want to create a thread in service, how can i reset it if it was killed? thanks
The best way to accomplish what you are trying to do is by using the ClipboardManager class, always try to avoid doing you own "Monitoring" functionality specially when it already exist in the OS and make sure if the OS itself already provides a BroadcastReceiver triggering an action with whatever you are expecting, take a look at the documentation for this class:
http://developer.android.com/reference/android/content/ClipboardManager.html
Instead of having a thread running doing nothing, draining battery and performance, why dont you create a BroadcastReceiver waitting for Clipboard actions, make use of the method:
ClipboardManager.addPrimaryClipChangedListener(ClipboardManager.OnPrimaryClipChangedListener what)
to be notified of any changes...
Regards!
inside this : http://developer.android.com/guide/components/services.html , Extending the Service class will help you !
Is there a way to implement timeout feature in the following scenarios?
A web application with html pages and native screens.
1.When the application is in the background for 5 min -> destroy the application.
2.When the application is in the foreground but not receiving any user interaction for 5 min ->destroy the application.
I think you can use this.
ApplicationConstants.TIMEOUT_IN_MS will be 300000 //5 min
private void timeout() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
System.exit(0);//close aplication
}
}, ApplicationConstants.TIMEOUT_IN_MS);
}
#Override
protected void onPause() {
super.onPause();
timeout();
}
Cheers,
Regarding background state:
There is no need to kill the app's process manually by default. The Android OS does this by itself if there is a need to free up resources for the other applications.
See this guide for a reference.
Though if you need to perform some background work during this "idle time", you may start a Service to perform those operations and then stop it from code.
Regarding foreground state:
I think the best approach to use here is to send Messages to a Handler of the Main thread of your application, since you do not know if the user will interact with the UI again after they leave. When the user comes back to the UI, you may clear the message queue, using Handler's removeMessages method.
I do not recommend you to finish the process with System.exit(0) in Android.
I'm writing an app that plays an audio file and I want it to continue doing so while minimized. I've done this, but I want the audio playback to be on a separate thread, because according to the Android developer website, CPU-heavy services work better on a separate thread.
First I tried using IntentService (this was the perfect solution). However, for some stupid reason, the service destroys itself once the code executed - which is immediately after it starts playing the file. I couldn't prevent this.
Then I created a Thread that runs the Service. However, I don't know how to make the Thread stop the service when needed - the best thing I could do is this:
serviceThread = new Thread() {
public void run() {
while (true) {
if (playAudio) {
startService(new Intent(getApplicationContext(),
MusicService.class));
playAudio = false;
}
if (stopAudio) {
stopService(new Intent(getApplicationContext(),
MusicService.class));
stopAudio = false;
}
}
}
};
Evidently, after that I set startService to true to start the service and I set stopService to true to stop it. However, I believe the Thread has to keep doing the check all the time, thus doing a lot of useless work all the time. I'm not even sure why is the app working, isn't it doing like million checks every second?
How can I properly do this?
Assuming you can't block the thread that the service runs in, you can add a java.lang.Thread.Sleep at the end of the loop if you're worried about doing too much work.
You might also want to read up thread scheduling and time slicing to understand why your app is still working (but probably using a lot more CPU than necessary).
I'm developing an application which I need to start to background services when the application is started.
Initially I added the startup procedure of the first service on the Application.onCreate() method.
Afterward, I realize that I need to re-start the service if for any reason the user stopped the background thread. Therefore I moved service startup code from the Application.onCreate() to the main Activivity.onResume().
According to the documentation, calling startService() on a already running service has no problem.
Until then, everything was fine. My first background service was implemented just fine. When it starts, it creates a new thread to run the background processing without no major issue.
After implementing the first service, I moved to second one. No problems here. But after implementing it and added the service start call on the Activity.onResume() method.
private void startServices() {
startTrackingService();
startBacklogService();
}
private void startTrackingService() {
if (Z10.DEBUG) {
Log.i(LOG_TAG, "REQUESTING TRACKING SERVICE START");
}
Intent serviceLauncher = new Intent(Main.this, TrackingService.class);
startService(serviceLauncher);
if (Z10.DEBUG) {
Log.i(LOG_TAG, "TRACKING SERVICE START REQUESTED");
}
}
private void startBacklogService() {
if (Z10.DEBUG) {
Log.i(LOG_TAG, "REQUESTING BACKLOG SERVICE START");
}
Intent serviceLauncher = new Intent(Main.this, BacklogService.class);
startService(serviceLauncher);
if (Z10.DEBUG) {
Log.i(LOG_TAG, "BACKLOG SERVICE START REQUESTED");
}
}
This code, blocks the main method and the application must be killed.
Trying to debug the application (it is quite difficult without the android source code!!!), I realized that the startService does not really start the service, it simply adds the operation on the Looper queue to be processed.
If, I execute the two startService operation in sequence, the main thread blocks, but if after doing other stuff (UI-related) on the main thread and just then start the second service, it works just fine.
The problem is that I really would need to start both services on the application startup, or restart any of them on the Main activity resume.
I want to start a Service from an Activity.
First I tried it with a LocalBinder. This works, but the service was bound to the activity. I don't want to stop the service when the activity is gone. I found no solution with the LocalBinder so I removed it and tried this:
use a singleton instance in the service
call the startService methode in a new thread and waits until the instance is available:
final Intent recordService = new Intent(RecordActivity.this, RecordService.class);
Runnable r = new Runnable() {
#Override
public void run() {
startService(recordService);
}
};
new Thread(r).start();
Log.i(MMLF.T, "service instance: "+serviceInstance);
final ProgressDialog mProgressDialog = ProgressDialog.show(
RecordActivity.this, "Waiting", "wait until record service is loaded",
true);
while (serviceInstance == null) {
serviceInstance = RecordService.get();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(MMLF.T, "could not sleep", e);
}
}
mProgressDialog.dismiss();
But this doesn't work, too. It stucked in the waiting loop. If I remove this waiting stuff and the new new Thread(r).start() line is the last, the activity and service start fine.
How to start a service independent from an activity? I also let them to communicate with each other. The activity should call two methods (start and stop recording) and the service should send messages. For the second I can use LocalBroadcast.
Your question is a little confusing, because Services already live independently of Activities. Note, however, that Services run in the main thread by default. If you want to run the Service in a different thread (and in this case it looks like you do), you will have to set up a Messenger object and send messages between your worker thread and your UI thread. You can also look into using AIDL (on top of which Messenger is really built anyway). Your communication, if you don't use a Messenger, could use intents. If this is the case, you should look into IntentService. However, this only works when you are sending messages to the Service, not back and forth. If you want back and forth communication, you will have to use some sort of Messenger or similar pattern.
By the way, using an IntentService for things like 'stop' and 'start' is pretty common. Typically there is also a background thread, which communicates with the Service using a Messenger or something similar, and then sends / receives messages to instruct the worker thread as to what should be done.
You might also look into AsyncTask, as it makes this kind of thing much simpler.