Launch a Toast in a static method of a non-activity class - java

I want to launch a toast message in a static method of a non-Activity class.
I read a loto of threads about that, but my situation is a bit more complicated, in particular:
I have a service and in OnStartCommand I call with fixed interval a static method of another class, in this called method I want to show in some particular cases a toast message.
I try also to create a support class that extends Application in which I have the application context to get when I need, but nothing to do.
This is the method in the Service class that calls the static method AllInterfacesActived:
public int onStartCommand(Intent intent, int flags, int startId) {
//flag variable that indicates if service is scanning
isScanning = true;
final int result;
turnGPSOn();
/*GET WIFI DATA, we use a thread and with scheduleAtFixedRate we run it repeatedly with the wifi scan interval*/
Wifitimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime());
//we are in wifi case, we set umts string result to "" because we don't perform a umts scansion
String resultUMTS = "";
//call the SCANWIFI METHOD to scan the networks and to obtain their data
String resultScan = scanWifi();
Intent mIntent = new Intent();
mIntent.setAction(INTENT_ACTION);
//put information on wifi and umts in the intent
mIntent.putExtra(INTENT_EXTRA_WIFI, "Waiting for umts scansion...\nWIFI SCAN PERFOMED"+resultScan+"\nUMTS\n"+resultUMTS);
//broadcast of data
Bundle xtra = new Bundle();
sendBroadcast(mIntent);
/*
* when all interfaces are actived we call AllInterfacesActived() of OracoloBrain.java
*/
if(getUseOracolo())
if(isAPNEnabled(getApplicationContext()) && isGpsEnable() && isWifiEnabled()){
OracoloBrain.AllInterfacesActived();
}
}
}, 0,MainActivity.getWifiInterval());
//other code of the onStartCommand method...
In the OracoloBrain class (non activity class) I have the static method AllInterfacesActived.
I leave out the code about this method, but in a particular case I want to show a Toast.
I try to create a another class called MyApplication.java:
public class MyApplication extends Application {
private static Context context;
public void onCreate(){
super.onCreate();
MyApplication.context = getApplicationContext();
}
public static Context getAppContext() {
return MyApplication.context;
}
}
So I try to launch toast using this context but nothing to do.

You could create a handler object on the main thread and then you could use it later to show your toast. Below is a sample code that will help you out.
class MyService extends Service{
Handler handler ;
onStartCommand(intent int , int flags,int startId){
handler = new Handler(); // this will get instantiated on the main thread;
new Thread(new Runnable() {
#Override
public void run() {
dispatchMessage("this is a toast");
}
}).start();
}
public void dispatchMessage(final String message) {
handler.post(new Runnable() {
#Override
public void run() {
System.out.println(message);
Toast.makeText(MyService.this, message, Toast.LENGTH_SHORT).show();
}
});
}
}
You can read more on Handlers to understand what I have done to show Toast on other threads apart from main thread.

You can send context of application to your class:
In your non-activity class:
private static Context c;
public static Context getAndSetMyContext(Context c) {
this.c = c;
}
after that you can:
Toast.makeText (c, "YOUR TEXT", Toast.LENGTH_LONG).show();
And in your activity class:
YourClass.getAndSetMyContext(getBaseContext());

What is the super class of your service? If it's IntentService than Toast is not being showed because you're not posting it on main UI thread. You have to do this in this way:
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable {
#Override
public void run() {
Toast.makeText(context/*Use app context here from your Application subclass*/, "", Toast.SHORT);
});

Related

Getting a IllegalStateException when trying to use Toast.hide on background thread [duplicate]

Consider the following code. In Service.onStart() method i have created and started a thread that should show Toast message but it is not working!
public class MyService extends Service{
private static final String TAG = "MyService";
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public void onCreate()
{
Toast.makeText(this, "My Service Created", Toast.LENGTH_SHORT).show();
}
#Override
public void onDestroy()
{
Toast.makeText(this, "My Service Stopped", Toast.LENGTH_SHORT).show();
}
#Override
public void onStart(Intent intent, int startid)
{
Toast.makeText(this, "My Service Started", Toast.LENGTH_SHORT).show();
DBIteratorThread dbThread=new DBIteratorThread();
dbThread.myService=this;
Thread t1 = new Thread(dbThread);
t1.start();
}
}
class DBIteratorThread implements Runnable
{
MyService myService;
public void run()
{
// Toast.makeText(myService, "Thread is Running", Toast.LENGTH_SHORT).show();
}
}
Do UI stuffs in main/UI thread. Try this:
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
//Your UI code here
}
});
I have written a class for showing Toasts from background processes. Can be used everywhere, e.g. in an AsyncTask. You only have to create an instance of this class like
ToastHandler mToastHandler = new ToastHandler(yourContext);
and then call showToast() with your text or resource id and the Toast's duration like you normally would with makeToast().
Here is the code or the direct download link:
import android.content.Context;
import android.os.Handler;
import android.widget.Toast;
/**
* A class for showing a <code>Toast</code> from background processes using a
* <code>Handler</code>.
*
* #author kaolick
*/
public class ToastHandler
{
// General attributes
private Context mContext;
private Handler mHandler;
/**
* Class constructor.
*
* #param _context
* The <code>Context</code> for showing the <code>Toast</code>
*/
public ToastHandler(Context _context)
{
this.mContext = _context;
this.mHandler = new Handler();
}
/**
* Runs the <code>Runnable</code> in a separate <code>Thread</code>.
*
* #param _runnable
* The <code>Runnable</code> containing the <code>Toast</code>
*/
private void runRunnable(final Runnable _runnable)
{
Thread thread = new Thread()
{
public void run()
{
mHandler.post(_runnable);
}
};
thread.start();
thread.interrupt();
thread = null;
}
/**
* Shows a <code>Toast</code> using a <code>Handler</code>. Can be used in
* background processes.
*
* #param _resID
* The resource id of the string resource to use. Can be
* formatted text.
* #param _duration
* How long to display the message. Only use LENGTH_LONG or
* LENGTH_SHORT from <code>Toast</code>.
*/
public void showToast(final int _resID, final int _duration)
{
final Runnable runnable = new Runnable()
{
#Override
public void run()
{
// Get the text for the given resource ID
String text = mContext.getResources().getString(_resID);
Toast.makeText(mContext, text, _duration).show();
}
};
runRunnable(runnable);
}
/**
* Shows a <code>Toast</code> using a <code>Handler</code>. Can be used in
* background processes.
*
* #param _text
* The text to show. Can be formatted text.
* #param _duration
* How long to display the message. Only use LENGTH_LONG or
* LENGTH_SHORT from <code>Toast</code>.
*/
public void showToast(final CharSequence _text, final int _duration)
{
final Runnable runnable = new Runnable()
{
#Override
public void run()
{
Toast.makeText(mContext, _text, _duration).show();
}
};
runRunnable(runnable);
}
}
You should be able to use the getApplicationContext() method to get the context with which to show the Toast.
See getApplication() vs. getApplicationContext() for some nice discussion on this.
Substitute this with getBaseContext().
You can't show a Toast on a thread that is not the activity's ui thread.
you can only run it somewhere else if you use runOnUiThread method so that it runs on the ui thread
Look at this question
Android: Toast in a thread
We use handler for this purpose because it is easy... :)
Steps:
declare a handler in the main activity (onCreate)
a class which is to be run in the background in that create a parameterized constructor . Taking the Context a perimeter .
now create a thread from the main activity and pass the Context of that activity.
now Post to the handler from that another thread (from whichever thread u want to send)
now use this context in the Toast, instead of using getApplicationContext()
It runs well.
mhandler.post(new Runnable() {
public void run() {
Toast.makeText(context,"Run ends",Toast.LENGTH_LONG).show();
}
});
replace word this with getApplicationContext() The message will then appear
Toast.makeText(this, "My Service Created", Toast.LENGTH_SHORT).show();
the correct :
Toast.makeText(getApplicationContext(), "My Service Created", Toast.LENGTH_SHORT).show();

Which Thread executes the "#override" Method called by an Interface listener in a Separate Thread?

I start a Thread in a Fragment and use an Interface call, to #Override a method in the Fragment starting the thread. This #Override stops a ProgressDialog and changes the Text of a TextView in the Fragment.
When I do the same in an Activity, there is no Problem but now when using a Fragment I got the "only Thread that creates a View can touch it's views" - Error. So I used getActivity().runOnUiThread(runnable) and posted the code to the MainThread, but why do I need to do this, since it works in a Activity without this? Did I made a mistake?
The Thread
//interface
private ConnectToDevice connectToDevice;
//C-Tor
public Thread_ConnectToDevice(BluetoothDevice device, ConnectToDevice connectToDevice ) {
this.mBluetoothDevice = device;
this.connectToDevice = connectToDevice;
}
//call
connectToDevice.connectionSuccess(false, null);
Fragment
//make Thread
thread_connectToDevice = new Thread_ConnectToDevice(mBluetoothDevice, Fragment_RoutineStartConnection_setPassword.this);
thread_connectToDevice.start();
//CallBack
//Thread Connect Success
#Override
public void connectionSuccess(final Boolean bSuccess,final BluetoothSocket mSocket) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if(bSuccess){
mProgessDialog.setTitle(R.string.tv_Fragmentsetpassword_Connected_CheckPW);
if(thread_connectedToDevice != null){
if(thread_connectedToDevice.isAlive()){
thread_connectedToDevice.interrupt();
}
}
thread_connectedToDevice = new Thread_ConnectedToDevice(mSocket, sTryingDonglePassword);
thread_connectedToDevice.start();
}else{
mProgessDialog.dismiss();
tv_Fragmentsetpassword_userhint
.setTextColor(getResources().getColor(R.color.Mercedes_RED, null));
tv_Fragmentsetpassword_userhint.setText(R.string.tv_Fragmentsetpassword_ConnectionFailed);
}
}
});
}
I have the feeling that I passed the wrong listener Instance to the Thread.
As asked this is the callback realized the same way but in a Activity:
Thread
//listener
private Finished_AskingForInformation listener;
//C-Tor
public Td_AskForInformation(
Finished_AskingForInformation listener) {
this.listener = listener;
}
//call
listener.AskingFinished();
Activity
//Create and start thread
td_askForInformation = new Td_AskForInformation(this);
td_askForInformation.start();
//CallBack
#Override
public void AskingFinished() {
mProgressDialog.dismiss();
}

Show alert dialog from background process in any activity

How to get result of background process in any Activity?
I'm working with OTA update. App handle that in background with handler. When update is done I have to show alert dialog to the user. I can show it in SettingsActivity where I start with OTA but user can be in any other Activity.
private void checkIsUpdated() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mDevice.getDevice().read(GattUUID.LS_DEVICE_INFORMATION, GattUUID.LC_FIRMWARE, new
BleDevice.ReadWriteListener() {
#Override
public void onEvent(ReadWriteEvent e) {
if (e.wasSuccess()) {
if (firmwareVersion.equals(e.data_string())) {
showAlertDialog("OTA update failed", "Device is not updated");
} else {
showAlertDialog("OTA update is successful.\nDevice is updated to new " +
"firmware!", "Device is updated");
}
Log.i("OTA", "Read firmware is new success");
} else {
Log.e("OTA", "Read firmware is new success");
}
}
});
}
}, 30000);
}
AlertDialog code
private void showAlertDialog(String message, String title) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext, R.style.SwipeDialogLight);
builder.setTitle(title)
.setMessage(message)
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
if (!alert.isShowing()) {
alert.show();
}
}
As #W4R10CK stated, I thought that too. The BroadcastReceiver might not a very good idea. But later, I gave a thought about it and if you call checkIsUpdated function inside a Service and send the Broadcast from it, it might be a feasible solution.
So basically you need a BaseActivity class and in which you need to have a BroadcastReceiver. You need to register it onResume and again unregister it onPause.
And you need to have an abstract method to be overriden in each of your Activity too.
So your BaseActivity may look like this..
public abstract class BaseActivity extends AppCompatActivity {
private final Context context;
public BaseActivity() {
this.context = setContext();
}
protected abstract Context setContext();
#Override
public void onResume() {
super.onResume();
registerBroadcastReceiver();
}
#Override
public void onPause() {
super.onPause();
unRegisterBroadcastReceiver();
}
// Declare your BroadcastReceiver here
private class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
showAlertDialog(context);
}
}
}
As #rogerwar suggested in the comments, the correct approach is a broadcast receiver.
Vogella has a nice tutorial
Since you want to have it in all activities, you can make a base class for all your activities and in this base class you can register the receiver in the onStart and unregister it in the onStop.

Where to put in Android code to communicate with server over http

The question is how to communicate with an Android phone to a server, so that if the Activity is left and the call in the Activity was not successful to repeat the transaction once again automatically. Just now I use the AsyncTask of Android to communicate with the server:
new AsyncTask<String, Void, List<String>>() {
#Override
protected void onPreExecute(
showWaitDialog();
}
#Override
protected void onPostExecute(List<String> msgList) {
//here I put the handling after the POST ie. error and success handling
hideWaitDialog();
if (msgList.isEmpty() {
//success handling --> starting an new Activity
} else {
errorView.setText (...);
errorLayout.setVisibility (View.VISIBLE);
}
}
#Override
protected List<String> doInBackground(String... params) {
List<String> msgs = new ArrayList<String>();
try{
//for example submitting an JSONObject
JSONObject result = HttpUtils.sendHttpPost(
AppConstants.WEB_URL, jsonObject);
//error handling on the result
boolean hasErrors = JsonResult.isOk(result);
if (hasErrors) {
// adding errors to msgs list
String[] errorMessages = JsonResult.getErrorMessages (result,...);
fillList (msgs, errorMessages);
return msgs;
}
} catch (CommunicationError er) {
msgs.add (er...);
}
return msgs;
}
}
The problem with this approach is, that if I don't have a successful transmission of the data I must stay in the same Activity. Until now I show an error message to the user and he is in charge to submit by a button again the results to the server.
What I'm looking for is some Activity that remains persistent in the memory which runs later in the case that the transmission wasn't made.
As an application case I use this to dynamically upload pictures for a Waypoint in a map if I pressed that waypoint. In some case it can happens that the connection to the mobile service provider isn't available (mountains, forest, far apart from antenna). Then I want to leave the map Activity and switch to the detail view of this waypoint. In the success case I put the picture into my model classes and make an serialization. If the user clicks again on the same waypoint the picture is not loaded again. In the non success case I don't want to wait that the user clicks against on the waypoint to retrieve the image. In fact I need a background task, some sort of a queue that pictures of waypoints that are already visited on couldn't be retrieved are loaded until the communication part gives back a positive result and the image can be written into the model. The next time the user is pressing the Waypoint the picture will be then present.
Are there any best practices for making such a code implementation?
Is there any example around?
Is there a better way of doing this?
Yes, you need to Implement Intent Service for this requirement
According to the developers website
The IntentService class provides a straightforward structure for running an operation on a single background thread.
For complete details and working source code, Go through the Android Docs
Thanks to the answer of David.
I just read after the suggestion the tutorial at
[1] http://code.tutsplus.com/tutorials/android-fundamentals-intentservice-basics--mobile-6183
After my tests I prefered a Service (not an IntentService)
and created a service: SubmissionService
public class SubmissionIntentService extends Service {
private List<PendingMessage> pMsgList = new CopyOnWriteArrayList<PendingMessage>();
private Handler handler = new Handler();
private boolean hasAppStopped = false;
private Runnable runner;
public SubmissionIntentService() {
super();
Log.d (TAG, "Service created...");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
PendingMessage pMessage = (PendingMessage) intent.getParcelableExtra(AppConstants.MESSAGE_OBJECT);
synchronized (pMsgList) {
pMsgList.add(pMessage);
}
if (runner == null) {
handler.postDelayed(runner = initializeRunnable(), 500);
}
return Service.START_NOT_STICKY;
}
private void runAsLongAppIsActive (Runnable runner) {
if (!hasAppStopped) {
handler.postDelayed (runner, SOME_INTERVAL_CONSTANT);
}
}
private Runnable initializeRunnable() {
Runnable result;
result = new Runnable() {
#Override
public void run() {
if (pMsgList.isEmpty()) {
runAsLongAppIsActive (this);
return;
}
PendingMessage[] pMArray = null;
synchronized(pMsgList) {
pMArray = pMsgList.toArray (new PendingMessage[pMsgList.size()]);
}
if (pMArray==null || pMArray.length==0) {
runAsLongAppIsActive (this);
return;
}
Log.d (TAG, "Message List size is actually :"+pMArray.length);
for (PendingMessage pM: pMArray) {
try {
JSONObject jsonMess = JSONSendMessage.buildOutput (pM);
JSONObject result = HttupUtils.sendHttpPost (WEB_URL, jsonMess);
boolean hasErrors = JSONResult.isOk (result);
if (hasErrors) {
//TODO: error handling in case of transmission
//don't remove the message from the queue
runAsLongAppIsActive(this);
return;
}
//remove pending transmission of the queue if success
synchronized (pMsgList) {
pMsgList.remove (pM);
}
//inform over receiver if activity is shown
Intent broadcastIntent = new Intent();
//put data in intent
sendBroadcast (intent);
//more important
WayPointModel model = ModelInstance.getWayPointModel();
model.addToModel (pM, result);
model.store();
} catch (Exception e) {
continue; //try to send other messages
}
}
runAsLongAppIsActive (this);
}
};
return result;
}
}
#Override
public void onDestroy() {
hasAppStopped = true;
handler.removeCallbacks (runner);
super.onDestroy();
}
}
Further I added a ResponseReceiver:
public class ResponseReceiver extends BroadcastReceiver {
public static final String ACTION_RESP = "MESSAGE_PROCESSED";
#Override
public void onReceive(Context context, Intent intent) {
//work in progress...
}
}
and in the Activity where I want to be informed about events:
public class SomeActivity extends Activity {
private ResponseReceiver receiver;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new ResponseReceiver();
registerReceiver(receiver, filter);
...
}
}
and finally to send messages over Http:
Intent msgIntent = new Intent(this, SubmissionIntentService.class);
msgIntent.putExtra(...);
startService(msgIntent);
don't forget to declare the service in your manifest:
<service android:name="ch.xxx.app.service.SubmissionIntentService" />
Observations:
- I called the method startService(...) from different Activities. The constructor is only called once.
==> I have just on instance of the service for all Activities (exactly what I need).
What I don't get until now:
- Putting back data to the Activity. What is if the Activity is at the moment no shown?

Android - find out which context/activity user is currently in?

My application has a few activities, and a background service. My question is, if I have the context variable in the service, how can I tell which activity is currently open? I need to do this to direct the next action my service takes. For example,
if (context is activity_1) {
//take this action
} else if (context is activity_2) {
//do this instead...
}
That's the basic gist of what I'm trying to do.
Help much appreciated.
You could set a SharedPreferences entry in each onResume() method of your activities and read that value from the service. To keep it clean you could write an Activity that does that and then extend all your activities from it:
public class MyActivity extends Activity {
private static final String PREFS_NAME = "MyPrefsFile";
#Override
protected void onResume() {
getContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
.edit()
.putInt("activtiyIdRunning", getActivityId() )
.commit();
super.onResume();
}
abstract protected int getActivityId();
}
public class MyConcreteActivity1 extends MyActivity {
#Override
protected int getActivityId() {
return 1;
}
// your normal code
}
in your service than just call:
int currentActivity = getContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
.getInt("activityIdRunning",-1);

Categories