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.
Related
I am working on an Android application which requires constant listener of Internet connectivity. I am using Broadcast listener and successfully applied it. But my code only shows the Toast message.
I want to stop the current activity and show a default XML file which says "No Internet Connection". and whenever it connect the Internet, previous activity resumes.
ExampleBradcastReceiver.java
public class ExampleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
boolean noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false
);
if (noConnectivity) {
Toast.makeText(context, "Disconnected", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Connected", Toast.LENGTH_SHORT).show();
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
ExampleBroadcastReceiver exampleBroadcastReceiver = new ExampleBroadcastReceiver();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(exampleBroadcastReceiver, filter);
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(exampleBroadcastReceiver);
}
}
In the place of Toast Message, I want to show a default XML file whenever disconnected and resume activity whenever connected.
You can move ExampleBroadcastReceiver to MainActivity as an inner class. And since in Java inner classes have access to their parent classes' methods and fields, you can in onReceive method consider showing/hiding the Internet disconnected view.
public class MainActivity extends AppCompatActivity {
ExampleBroadcastReceiver exampleBroadcastReceiver = new ExampleBroadcastReceiver();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(exampleBroadcastReceiver, filter);
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(exampleBroadcastReceiver);
}
private void showInternetDisconnectedView(boolean disconnected){
// show or hide based on 'disconnected'
}
private class ExampleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
boolean noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
showInternetDisconnectedView(noConnectivity);
}
}
}
}
You need to move Broadcast receiver code into Activity and on receiving internet connection events you can stop current in progress activity and make internet failure layout visible there only as it is part of Activity class. If it is required through out the Application, then create Base activity and handle this there to avoid duplicating code on every screen.
I searched a lot but didn't find the solution to the following issue.
Context :
I use an AsyncHttpResponseHandler object to handle all my webservice
responses
If I get a particular error code from the WS, I want to show an alert dialog (whatever the activity currently displayed)
I came to think that using the LocalBroadcastManager would be a good solution as the HTTP handler is not aware of the currently displayed activity
Problem :
After implementation of all what seems to be needed to make it work, my intent sent from the async handler is not received.
Additional note :
the ApplicationContext is stored in my StaticItems
class which contains all the static data I need in my app.It is setup via a custom class which inherits from Application
If I broadcast the intent from an activity, the OnReceive event is triggered
I thank you in advance for any help you could provide.
Cheers !
Here are some pieces of my code :
The code in the http handler
public class AsyncResponseHandler extends AsyncHttpResponseHandler {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
if(response != null && response.length > 0) {
CrvData data = JsonHelper.getCrvData(new String(response));
String code = data.getErrorCode();
if (!TextUtils.isEmpty(code) && code.equals(StaticItems.C_WS_OBSOLETE_VERSION_ERROR)) {
Intent intent = new Intent();
intent.setAction(StaticItems.BROADCAST_INTENT_MESSAGE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse(data.getValue()));
LocalBroadcastManager.getInstance(StaticItems.applicationContext).sendBroadcast(intent);
}
}
}
The code of the root Activity I use for all my activities :
public class MainActivity extends Activity {
/**
* The local broadcast receiver
*/
protected MyBroadcastReceiver mMessageReceiver = new MyBroadcastReceiver();
#Override
protected void onResume() {
super.onResume();
// register
IntentFilter filter = new IntentFilter();
filter.addCategory(Intent.CATEGORY_DEFAULT);
filter.addAction(StaticItems.BROADCAST_INTENT_MESSAGE);
LocalBroadcastManager.getInstance(StaticItems.applicationContext).registerReceiver(mMessageReceiver, filter);
}
#Override
protected void onPause() {
super.onPause();
// Unregister
LocalBroadcastManager.getInstance(StaticItems.applicationContext).unregisterReceiver(mMessageReceiver);
}
}
The receiver
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setInverseBackgroundForced(true)
.setNegativeButton(context.getResources().getString(R.string.dlg_no), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setIcon(R.drawable.ic_dialog_alert_holo_light)
.setMessage(R.string.dlg_app_is_obsolete)
.setPositiveButton(context.getResources().getString(R.string.dlg_yes), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
context.startActivity(intent);
}
});
builder.show();
}
}
I had a similar problem, for some reason you can not setData(..) on Intent returned via LocalBroadcastManager, when I placed my URI in the extra data, it started to work.... possibly a bug?
My guess is that the context you are using is not an activity context and thus can't be used for creating dialogs.
Namely, the context that is passed to onReceive in this case should be your application context, StaticItems.applicationContext, which is not good for showing dialogs.
If this is the case, you should somehow rearrange your code to make sure to pass an activity context rather than the application one.
Remove addCategory() from your IntentFilter
was solved here
OK so... I figured out that the intent was not received because of this line :
intent.setData(Uri.parse(data.getValue()));
And as #mvai pointed, the dialog cannot be displayed from the application context. I managed to get the current activity by having a reference to it in my application class. (I checked out to be sure for not having any memory leak)
Is there a way to make an alert only appear when the app is opened? I'm creating an alert in onStart() in my MainActivity and whenever I go back to that activity in the app, it shows the alert again which can be annoying to the user. Or is there a way to create a "got it" button and then turn off the alert? Here is my code:
protected void onStart() {
super.onStart();
new AlertDialog.Builder(this)
.setTitle("Instructions")
.setMessage("Hello! To begin, select a map from the list to train with. Make sure" +
" you are on the correct floor.")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
})
.setIcon(R.drawable.ic_launcher)
.show();
}
This is because when another activity comes to foreground upon your MainActivity makes your activity goes to OnPause().
Then when you go back to your MainActivity. The system calls
onStart() again. See The activity life cycle
-First Solution
public class TestActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
showAlertDialog();
}
}
private void showAlertDialog() {
// code to show alert dialog.
}
}
-Second Solution
public class TestActivity extends ActionBarActivity {
private static boolean isAlertDialogShownBefore = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!isAlertDialogShownBefore) {
showAlertDialog();
isAlertDialogShownBefore = true;
}
}
private void showAlertDialog() {
// code to show alert dialog.
}
#Override
public void onBackPressed() {
isAlertDialogShownBefore = false;
super.onBackPressed();
}
}
Put that code in onCreate method of your activity. Check for saveInstanceState for null, if it is then show your alertDialog
I have problem with one of my games. This is time based puzzle game and I have problem with it. When user press on/off button on Android device game doesn`t stop, but timer goes on and on till game over. When user turn on screen again, he can see game over screen. But I want to make scenario when user press on/off button game will pause.
Any suggestions? I`m pretty new in programming so please explain me very basic method to do this.
Thanks all!
Edit. Timer code
private void initializeProgressBar() {
//initialize progressbar
progress = ApplicationConstants.GAME_TIME;
mProgress = (ProgressBarDetermininate) findViewById(R.id.progressDeterminate);
mProgress.setMax(progress);
mProgress.setProgress(progress );
timer = new Timer();
progressBarUpdateTask = new ProgressBarUpdateTask();
timer.schedule(progressBarUpdateTask, 20, 20);
}
class ProgressBarUpdateTask extends TimerTask {
#Override
public void run() {
runOnUiThread(new Runnable(){
#Override
public void run() {
progress-=1;
if(progress==0)
{
TimeOver();
}
mProgress.setProgress(progress);
}
});
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onPause() {
super.onPause();
this.timer.cancel();
}
Pause your game in onStop() or onPause() (depending on your need) in the Activity context your game is running in.
I am assuming you are using android's activity...
#Override
protected void onResume() {
super.onResume();
// Resume the timer or show a button for the user to press when ready
// !!! Also check if timer exits because onResume is called before onCreate!!!
}
#Override
protected void onPause() {
super.onPause();
// Pause the timer
}
When you press screen off or Power button onPause method of the application will be called and when you again press Power button, applications onResume method will be called, you should pause timer in onPause and resume it in onResume.
One way to do this is to detect the user presence, here's an example
At beginning of your game start the LockService
startService(new Intent(getApplicationContext(), LockService.class));
LockService.java
public class LockService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
final BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
return super.onStartCommand(intent, flags, startId);
}
public class LocalBinder extends Binder {
LockService getService() {
return LockService.this;
}
}
}
Then finally the BroadcastReceiver where you can stop your game.
ScreenReceiver.java
public class ScreenReceiver extends BroadcastReceiver {
public static boolean wasScreenOn = true;
#Override
public void onReceive(final Context context, final Intent intent) {
Log.e("LOB","onReceive");
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// do whatever you need to do here
wasScreenOn = false;
/* PAUSE THE GAME HERE*/
Log.e("LOB","wasScreenOn"+wasScreenOn);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// and do whatever you need to do here
wasScreenOn = true;
}else if(intent.getAction().equals(Intent.ACTION_USER_PRESENT)){
}
}
}
As correctly mentioned in other answers, you can also use the onPause() method
#Override
protected void onPause() {
super.onPause();
// stop the game
}
How can I prevent my dialogs from extending activities?
When I create it in my main activity it doesn't dismiss itself when I click "Okay", which creates a new activity. The new activity that is created extends from the MainActivity.
I am using shared preferences to determine where to send the user when they open the app. I'm not sure if that could be playing into this situation.
I want to prevent the dialogs from extending the MainActivity. It shouldn't be showing up on the other activities that I create.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SharedPreferences sharedPreferences = getSharedPreferences("version", 0);
int savedVersionCode = sharedPreferences.getInt("VersionCode", 0);
int appVershionCode = 0;
try { appVershionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode; }
catch (NameNotFoundException nnfe) { Log.w(TAG, "$ Exception because of appVershionCode : " + nnfe); }
if(savedVersionCode == appVershionCode){
// Returning user
Log.d(TAG, "$$ savedVersionCode == appVershionCode");
// Temporary Navigation
final Builder alertDialogBuilder = new Builder(this);
new AlertDialog.Builder(new ContextThemeWrapper(getBaseContext(), android.R.style.Theme_Dialog));
alertDialogBuilder.setTitle("Temporary Navigation");
alertDialogBuilder.setMessage("Go to the new activity.");
alertDialogBuilder.setPositiveButton("Okay", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Log.d(TAG, "$$ onClick");
Intent newactivity = new Intent(MAINACTIVITY.this,NEWACTIVITY.class);
startActivity(newactivity);
dialog.cancel();
}
});
alertDialogBuilder.show();
// End
} else {
// First time visitor
Log.d(TAG, "$$ savedVersionCode != appVershionCode");
// Hide graphics meant for returning users
((Button)findViewById(R.id.Button01)).setVisibility(View.INVISIBLE);
SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();
sharedPreferencesEditor.putInt("VersionCode", appVershionCode);
sharedPreferencesEditor.commit();
Builder alertDialogBuilder = new Builder(this);
alertDialogBuilder.setTitle("Welcome");
alertDialogBuilder.setMessage("Click Okay to continue.");
alertDialogBuilder.setNeutralButton("Okay", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Log.d(TAG, "$$ onClick");
Intent leagues = new Intent(MAINACTIVITY.this,NEWACTIVITY.class);
startActivity(leagues);
}
});
alertDialogBuilder.show();
}
}
Try dialog.dismiss() like such:
#Override
public void onClick(DialogInterface dialog, int which) {
Log.d(TAG, "$$ onClick");
Intent newactivity = new Intent(MAINACTIVITY.this,NEWACTIVITY.class);
startActivity(newactivity);
dialog.dismiss();
}
From a little understanding of your code, my suggestion would be keeping a check of when you want dialog to be shown and when you dont. e.g You can use a static boolean flag showDialog, set it true/false in your activity according to the use.
if(savedVersionCode == appVershionCode && showDialog)
if(savedVersionCode == appVershionCode && !showDialog)
Its more over over a programmatic problem with a programmatic solution. This is approach would be just a suggestion. As you are following a singleTon type of structure so you must be sure of methods you want to carry further.
Second approach could be, do not do it this way. The common method you want to implement in your activity is related to SharedPref checking, so why not :
Create a class which extends Activity.
Add your SharedPref related methods in it.
Now you can extend that class to all you activities.
public class commonMethod extends Activity{
public void my_sharedPrefMethod(){
// do some thing with prefs
}
#OverRide
public void onCreate(){
super.onCreate();
// common onCreate code for every activity. Recommend not to change this
// so that you can implement
}
// you can also write other methods onPause(), onDestroy() here too.
{
Now you can extend your classes with this class commonMethod. e.g
public class main extends commonMethod{
#overRide
public void oncreate(){
}
#overRide
public void my_sharedPrefMethod(){
}
public void showMyDialog(){
// this way dialog box would not be shown on every activity but just this one.
}
}