How to create toast from IntentService? It gets stuck on the screen - android

I'm trying to have my IntentService show a Toast message,
but when sending it from the onHandleIntent message, the toast shows but gets stuck and the screen and never leaved.
I'm guessing its because the onHandleIntent method does not happen on the main service thread, but how can I move it?
Has anyone has this issue and solved it?

in onCreate() initialize a Handler and then post to it from your thread.
private class DisplayToast implements Runnable{
String mText;
public DisplayToast(String text){
mText = text;
}
public void run(){
Toast.makeText(mContext, mText, Toast.LENGTH_SHORT).show();
}
}
protected void onHandleIntent(Intent intent){
...
mHandler.post(new DisplayToast("did something"));
}

Here is the full IntentService Class code demonstrating Toasts that helped me:
package mypackage;
import android.app.IntentService;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;
public class MyService extends IntentService {
public MyService() { super("MyService"); }
public void showToast(String message) {
final String msg = message;
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
});
}
#Override
protected void onHandleIntent(Intent intent) {
showToast("MyService is handling intent.");
}
}

Use the Handle to post a Runnable which content your operation
protected void onHandleIntent(Intent intent){
Handler handler=new Handler(Looper.getMainLooper());
handler.post(new Runnable(){
public void run(){
//your operation...
Toast.makeText(getApplicationContext(), "hello world", Toast.LENGTH_SHORT).show();
}
});

Related

android: with delay in thread

i'm new in android.
i made an app with service and thread to show a Toast every 5 seconds:
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class MyService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
Handler mHandler = new Handler();
#Override
public void onCreate() {
super.onCreate();
final Runnable RunnableUpdateResults = new Runnable() {
public void run() {
Toast.makeText(getBaseContext(), "Hello", Toast.LENGTH_SHORT).show();
}
};
new Thread() {
public void run() {
try {
mHandler.postDelayed(RunnableUpdateResults);
sleep(5000);
} catch (InterruptedException e) {e.printStackTrace();}
}
}.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return START_STICKY;
}
public void onStart(final Context context,Intent intent, int startId)
{
}
}
but my Toast shown only once. with no crash.
i used Handler's postDelayed function for this purpose. It will run your code with specified delay on the main UI thread, so you will be able to update UI controls but it dose not work too.
any solution to do a task repetitively ?
call Thread.sleep inside while loop as:
boolean isThreadRunning=true;
new Thread() {
public void run() {
try {
while(isThreadRunning){
mHandler.postDelayed(RunnableUpdateResults);
sleep(5000);
}
} catch (InterruptedException e) {e.printStackTrace();}
}
}.start();
To stop Thread make isThreadRunning=false;
You can achieve same using handler.postDelayed
mHandler.postDelayed(RunnableUpdateResults,5000);
and in RunnableUpdateResults call mHandler.postDelayed :
final Runnable RunnableUpdateResults = new Runnable() {
public void run() {
mHandler.postDelayed(RunnableUpdateResults,5000);
Toast.makeText(getBaseContext(),
"Hello", Toast.LENGTH_SHORT).show();
}
};
To stop Handler call removeCallbacks method:
mHandler.removeCallbacks(RunnableUpdateResults);
Use a Timer with a TimerTask
new Timer().schedule(new TimerTask() {
#Override
public void run() {
mHandler.post(RunnableUpdateResults);
}
}, 0, 5000);

Android Thread in Service

I need to write thread in service . But I'm not sure how to do this exactly. There must be more than one thread.
Can you help me please.
You start a thread in a service the same way you start a thread in anything. Either use Java threads, timers, or async task.
Java threads are usually started like so:
private Thread yourThread;
private NewRunnable yourRunnable;
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
... code...
yourThread = new Thread(yourRunnable);
... code...
}
private final class NewRunnable extends Runnable
{
#Override
public void run()
{
... Code here will be run in new thread....
}
}
This way works great.
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class Servicio extends Service {
#Override
public void onCreate() {
super.onCreate();
initialize();
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
public void initialize(){
Thread th = new Thread(new Runnable() {
#Override
public void run() {
//Your code ......
}
});
th.start();
}
}
Just get The context in the Service and Use AsyncTask to create another Thread... Or you can also do
new Thrad(){
public void Run(){
//your implementation..
}
}

IntentService won't show Toast

This IntentService I created will show Toasts in onStartCommand() and in onDestroy(), but not in onHandleIntent(). Am I missing something about the limitations of an IntentService?
public class MyService extends IntentService {
private static final String TAG = "MyService";
public MyService(){
super("MyService");
}
#Override
protected void onHandleIntent(Intent intent) {
cycle();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); //This happens!
return super.onStartCommand(intent,flags,startId);
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
Toast.makeText(this, "service stopping", Toast.LENGTH_SHORT).show(); //This happens!
super.onDestroy();
}
private void cycle(){
Toast.makeText(this, "cycle done", Toast.LENGTH_SHORT).show(); //This DOESN'T happen!
Log.d(TAG,"cycle completed"); //This happens!
}
}
The accepted answer is not correct.
Here is how you can show toast from onHandleIntent():
Create a DisplayToast class:
public class DisplayToast implements Runnable {
private final Context mContext;
String mText;
public DisplayToast(Context mContext, String text){
this.mContext = mContext;
mText = text;
}
public void run(){
Toast.makeText(mContext, mText, Toast.LENGTH_SHORT).show();
}
}
Instantiate a Handler in your service's constructor and call the post method with a DisplayToast object inside.
public class MyService extends IntentService {
Handler mHandler;
public MyService(){
super("MyService");
mHandler = new Handler();
}
#Override
protected void onHandleIntent(Intent intent) {
mHandler.post(new DisplayToast(this, "Hello World!"));
}
}
You should start the Toast on the main thread:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
});
This is because otherwise the thread of the IntentService quits before the toast can be send out, causing a IllegalStateException:
java.lang.IllegalStateException: Handler (android.os.Handler) {12345678} sending message to a Handler on a dead thread
onHandleIntent() is called from a background thread (that is what IntentService is all about), so you shouldn't do UI from there.
Another option is RxJava, e.g.:
private void showToast(final String text) {
Observable.just(text)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
#Override
public void call(String s) {
Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
}
});
}
Caveat: I'm new to Android.

Android Timer within a service

I am having problems running a timer in a service I have created. The task that the timer calls simply isn't called. I know that the service starts as I have put toasts within it and they are called, but not when they are within the timer. Help appreciated.
service class:
public class LocalService extends Service
{
private static Timer timer = new Timer();
private Context ctx;
public IBinder onBind(Intent arg0)
{
return null;
}
public void onCreate()
{
super.onCreate();
ctx = this;
startService();
}
private void startService()
{
timer.scheduleAtFixedRate(new mainTask(), 0, 5000);
}
private class mainTask extends TimerTask
{
public void run()
{
Toast.makeText(ctx, "test", Toast.LENGTH_SHORT).show();
}
}
public void onDestroy()
{
super.onDestroy();
Toast.makeText(this, "Service Stopped ...", Toast.LENGTH_SHORT).show();
}
}
Main class:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startService(new Intent(RingerSchedule.this, LocalService.class));
}
Android does not allow UI events like Toasts from outside the main thread. The run is getting called, but the Toast is being ignored.
To create the Toast on the UI thread, you can use a Handler and an empty Message like so:
public class LocalService extends Service
{
private static Timer timer = new Timer();
private Context ctx;
public IBinder onBind(Intent arg0)
{
return null;
}
public void onCreate()
{
super.onCreate();
ctx = this;
startService();
}
private void startService()
{
timer.scheduleAtFixedRate(new mainTask(), 0, 5000);
}
private class mainTask extends TimerTask
{
public void run()
{
toastHandler.sendEmptyMessage(0);
}
}
public void onDestroy()
{
super.onDestroy();
Toast.makeText(this, "Service Stopped ...", Toast.LENGTH_SHORT).show();
}
private final Handler toastHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
Toast.makeText(getApplicationContext(), "test", Toast.LENGTH_SHORT).show();
}
};
}
Thanks, I also needed to cancel the timer ..
public void onDestroy() {
timer.cancel();
Toast.makeText(this, "ServiceTalkGeology stopped.",
Toast.LENGTH_SHORT).show();
super.onDestroy();
}

Toast created in an IntentService never goes away

I have an IntentService that downloads some files. The problem is that I create a Toast inside the IntentService like this
Toast.makeText(getApplicationContext(), "some message", Toast.LENGTH_SHORT).show();
The Toast will never disappear event if I exit the app. The only way to destroy it is to kill the process.
What am I doing wrong?
The problem is that IntentService is not running on the main application thread. you need to obtain a Handler for the main thread (in onCreate()) and post the Toast to it as a Runnable.
the following code should do the trick:
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler();
}
#Override
protected void onHandleIntent(Intent intent) {
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(MyIntentService.this, "Hello Toast!", Toast.LENGTH_LONG).show();
}
});
}
This works for me:
public void ShowToastInIntentService(final String sText) {
final Context MyContext = this;
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast toast1 = Toast.makeText(MyContext, sText, Toast.LENGTH_LONG);
toast1.show();
}
});
};
IntentService will create a thread to handle the new intent, and terminated it immediately once the task has done. So, the Toast will be out of controlled by a dead thread.
You should see some exceptions in the console when the toast showing on the screen.
For people developing in Xamarin studio, this is how its done there:
Handler handler = new Handler ();
handler.Post (() => {
Toast.MakeText (_Context, "Your text here.", ToastLength.Short).Show ();
});
To show a toast when the user is in one of the application activity.
Just need a reference of the current activity, and call it with this sample code:
public void showToast(final String msg) {
final Activity a = currentActivity;
if (a != null ) {
a.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(a, msg, Toast.LENGTH_SHORT).show();
}
});
}
}
There is a lot of options to get the current activity, check this question:
How to get current foreground activity context in android?
But I use this approach:
The application must have:
private Activity currentActivity = null;
public Activity getCurrentActivity() {
return currentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity) {
this.currentActivity = mCurrentActivity;
}
Each activity must have:
#Override
protected void onResume() {
super.onResume();
((MyApplication) getApplication()).setCurrentActivity(this);
}
#Override
protected void onPause() {
super.onPause();
((MyApplication) getApplication()).setCurrentActivity(null);
}
You shouldn't create Toasts from a Service. You should use a Notification instead.

Categories

Resources