How can I build a dialog which is launched by a service? - android

I think my problem is easy to fix for you. I have a service running in the background and starting an Intent which starts an activity, which opens a dialog.
Her is my code from the service:
Intent todialog = new Intent();
todialog.setClass(myService.this, openDialogInSleep.class);
todialog.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(todialog);
and here is the activity:
import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
public class openDialogInSleep extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new AlertDialog.Builder(openDialogInSleep.this)
.setTitle("huhu")
.setNeutralButton("close", null);
}
}
Finally the android manifest:
<activity android:name=".openDialogInSleep" android:theme="#android:style/Theme.Dialog"></activity>
My Problem is, that there is not shown the dialog with the title "huhu" and the button "close". There is only shown a dialog in a strange form which simply shows a part of my activityname.
What did I forget?
Please help me.
mfg. Alex

You forget to chain in show() to actually show your dialog.
new AlertDialog.Builder(openDialogInSleep.this)
.setTitle("huhu")
.setNeutralButton("close", new OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
openDialogInSleep.this.finish();
}
})
.show();

One thing you have missed is to call show() on the dialog generated by the AlertBuilder.
UPDATE
If I understand you correctly you don't want the activity to take control of the screen but rather just show the dialog?
If that is the case I don't think it is possible, the only way you can create a similar effect is by using a Toast Message. This can be launched from your Service and you wouldn't require the activity at all.

Related

Clear password field in other activity on exit

I need to clear password field on exit of app,i am exiting the app in other activity and on exit it goes to mainActivity which has login details in which i need to clear password field,how will i do this in other activity ,i tried using setText("") but in vain.
public void backButtonHandler() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(
ReminderActivity.this);
// Setting Dialog Title
alertDialog.setTitle("Leave application?");
// Setting Dialog Message
alertDialog.setMessage("Are you sure you want to leave the application?");
// Setting Positive "Yes" Button
alertDialog.setPositiveButton("YES",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//I need to clear here all pwd data present in MainActivity in edittext
finish();
}
});
// Setting Negative "NO" Button
alertDialog.setNegativeButton("NO",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Write your code here to invoke NO event
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
}
In your MainActivity do like this:
#Override
public void onResume() {
super.onResume(); // Always call the superclass method first
editText.SetText("");
}
So, it will clear editText value, whenever your MainActivity will get resumed.
Or when you click the login button do
editText.SetText("");
Then it will be cleared before another activity starts
Using setText won't work and may even throw some type of NPE if your activity is no longer in memory.
There are a couple of ways you can do this depending on your requirements:
You can simply clear the text field in the activity/fragment's onStop or onDestroy overrides
If you absolutely have to set the text field from a different activity, then I suggest the following design:
In your Application class, create a nested class that implements ActivityLifeCycleCallbacks. This is a great class to implement as it allows you to monitor the state of all of your activities. It resolved a lot of problems for me
If you have a singleton model, or static String value that binds to your password TextView then you're almost there (other workarounds available if you give us more info).
So let's look at some code:
Design 1:
public void onStop()
{
super.onStop();
myTextField.setText("");
}
Your Application class:
public class MyApplication extends Application
{
...
private static final class MyActivityLifeCycleCallback implements ActivityLifecycleCallbacks
{
#Override
public void onActivityStopped(Activity activity)
{
//Here, I am assuming that your class name is MainActivity
Log.i(TAG, "onActivityStopped:" + activity.getLocalClassName());
if("MainActivity".isEqual(activity.getLocalClassName())
{
myDataModel.getInstance().setPassword("");
//or if your password String member is static
//((MainActivity)activity).myPasswordMember = "";
}
//Or if you want to only clear the password text when RAActivity stops, simply replace "MainActivity" with the RAActivity class name.
}
#Override
public void onActivityDestroyed(Activity activity,
Bundle savedInstanceState)
{
Log.i(TAG, "onActivityDestroyed:" + activity.getLocalClassName());
if(activity.getLocalClassName().contains("MySecondActivity"))
{
//reset your password here - implementation will depend on how you have your data model organized (private, singleton, static, etc.)
}
}
....
}
Remember that this design would work well with some type of a singleton or central data model (think MVC architecture) so that you can propagate the change in data to your components.
Hope it helps
EDIT:
I have added the code according to your comment. But to be honest, I think it's a better idea to simply call the setText("") method in the MainActivity's onStop function like I suggested. This is a simple problem and my second design might be a bit too much. Anyway, the code is updated, so if you like it, mark it as an answer :)
Here's another idea. IF RAActivity calls MainActivity again (probably not) using startActivity, you can simply pass a bundle value to MainActivity that tells it that it's coming from RAActivity. That way, MainActivity can clear the password if it was called from RAActivity. Lots of options.

Why won't dismissDialog, removeDialog, or dialog.dismiss work in onDestroy or onPause?

I can't for the life of me figure out how to manage dialogs without using configChanges to specify that you want to manually handle orientation changes.
So lets say you have this AndroidManifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testandroid"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Take this MainActivity.java:
package com.example.testandroid;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
private final static String TAG = "MainActivity";
Dialog mDialog = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setContentView(R.layout.activity_main);
}
public void doShowDialog(View b) {
Log.d(TAG, "doShowDialog");
showDialog(1);
}
private void tryDismiss() {
Log.d(TAG, "tryDismiss");
try {
dismissDialog(1);
removeDialog(1);
mDialog.dismiss();
} catch(IllegalArgumentException ex) {
Log.e(TAG, ex.getMessage());
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
protected void onPause() {
tryDismiss();
super.onPause();
Log.d(TAG, "onPause");
}
#Override
protected Dialog onCreateDialog(int dialog) {
Builder b = new AlertDialog.Builder(this);
b.setTitle("Hello").setMessage("Waiting..");
mDialog = b.create();
return mDialog;
}
}
and this layout (main.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Open Dialog"
android:onClick="doShowDialog"
/>
</LinearLayout>
It doesn't seem to matter if you call from onDestroy or onPause, the dialog shows back up after the orientation switches. But why? I told it to go away. If call removeDialog/dismissDialog it does nothing when called before the orientation changes. I can't figure out for the life of me why this is. The only way to get rid of this that I know of is to handle the orientation change yourself by using
android:configChanges="keyboardHidden|orientation"
I know the new way of working is to use the FragmentDialog stuff which I have not upgraded to yet and am not ready to rewrite my whole app for that. Just seems strange that this doesn't work.
This is just an example of a real world problem I'm having in my app where the user can request some data be pulled from a remote server (to update a spinner's data), and if they switch orientation the loading dialog will never go away and there seems to be no fix for this besides handling the orientation change with the android:configChanges option. Which I can do but it seems ridiculous to me to have to do that.
-- Update --
Removed the button to dismiss the dialog as it's not necessary and you can't click it anyways since the dialog is on top.
To reproduce just start the app, click the button that opens the dialog, and then rotate your phone.
Your dialog is saved in onSaveInstanceState, so you might try dismissing it before it's launched:
#Override
protected void onSaveInstanceState(Bundle state)
{
tryDismiss();
super.onSaveInstanceState(state);
}
Also I don't really understand why do you use Activity's onCreateDialog to manage dialogs. The reason it was designed was to handle orientation changes automatically. If you want to handle it manually, why don't you just use dialog's functions? Instead of using showDialog(id) and onCreateDialog(id) just launch it directly, it won't reappear after rotating the screen.
Builder b = new AlertDialog.Builder(this);
b.setTitle("Hello").setMessage("Waiting..");
Dialog mDialog = b.create();
mDialog.show(); // <-----
Sebastian got it but I'd like to explain a bit more about the situation and my findings on dialogs since it can be quite confusing:
As sebastian put it, you must call dismissDialog/removeDialog from
onSaveInstanceState if you want the dialog gone before the rotation.
While you can create a dialog from onCreate, if you don't dismiss it before the orientation
change you won't be able to dismiss in the onCreate method when the activity restarts. You must call dismissDialog from onPostCreate
Calling dismissDialog didn't work in onRestoreInstanceState after orientation change as well. I tried both before and after calling super.onRestoreInstanceState and neither worked (thought it would since dimissing happens in onSaveInstanceState)
Even more important than this is that I learned if you are doing some Asynchronous task, such as an HTTP call and you have an inner class which contains a callback function which will run when the task is complete, you need to be aware that that inner class method will contain a reference to the original instance of the outer Activity class if the screen is rotated. This was not at all obvious to me as and I wasn't actually using AsyncTask as many others have had issues with (I was using an asynchronous http library).
Taking a small example similar to my real code:
public class MyActivity extends Activity {
private static MyActivity sThis;
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
sThis = this;
doAsyncWork();
}
#Override
public void onDestroy() {
super.onDestroy();
sThis = null;
}
private void doAsyncWork() {
showDialog(LOADING_DIALOG);
ExampleAsyncWorker.work(new AsyncWorkerCallback() {
#Override
public void onWorkComplete() {
dismissDialog(LOADING_DIALOG); //doesn't work if orientation change happened.
}
});
}
}
The above code, through the CategoryManager, connects to an external server, downloads a list of categories, and once it is complete calls onCategoriesObtained and then onFetchComplete (also there are some error handling callback function removed for brevity). If an orientation change happens between the fetchCategories call and onFetchComplete then the call to dismissDialog in onFetchComplete will never work. The reason is that this inner class has an implicit reference to the original instance of the Activity class which was created before the orientation change. Thus, when you call dismissDialog you are calling it on the original instance not the new one, which will cause the dismissDialog to fail with the message: "no dialog with id 1 was ever shown via Activity#showDialog". I did figure out a way around this but its a bit of hack:
In your Activity class, include a static reference to the this reference and set it in onCreate, and null it in onDestroy, and use that reference from your inner class like so:
public class MyActivity extends Activity {
private static MyActivity sThis;
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
sThis = this;
doAsyncWork();
}
#Override
public void onDestroy() {
super.onDestroy();
sThis = null;
}
private void doAsyncWork() {
showDialog(LOADING_DIALOG);
ExampleAsyncWorker.work(new AsyncWorkerCallback() {
#Override
public void onWorkComplete() {
sThis.dismissDialog(LOADING_DIALOG);
}
});
}
}
Note that I'm not sure this is a great practice but it worked for me. I know there can be problems with inner classes in activities that refer to the outer class (leaking the context) so there may be better ways of solving this problem.
AFAIK , This window leaked can be handled in two ways.
#Override
public void onDestroy(){
super.onDestroy();
if ( Dialog!=null && Dialog.isShowing() ){
Dialog.dismiss();
}
}
Or
if(getActivity()!= null && !getActivity().isFinishing()){
Dialog.show();
}
Here Dailog is your progress /alert dailog
for creating your app without the savedinstace you can use super.onCreate(null);

Trying to call an activity, but having troubles with onClick

im trying to run this simple code (im a beginner :).
trying to run this. the // text is usually what i use for buttons. however, i saw this switch technique that i wanted to try, it seemed more efficient. however, i get errors related to the onClick (something about the ( ) and that 'void is an invalid type'). i have no idea what can cause this. just wanna access the buttons. can anyone please tell me why?
Thanks!
package com.experiment.fewops;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class FewOptions extends Activity {
/** Called when the activity is first created. */
final Button sexy = (Button) findViewById(R.id.buttonSexy);
final Button text = (Button) findViewById(R.id.buttonText);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// sexy.setOnClickListener(new View.OnClickListener() {
//
// #Override
// public void onClick(View v) {
// Intent intent = new Intent(this, SexyPage.class);
// startActivity(intent);
// }
// });
#Override
public void onClick(View v) {
switch(v.getId()){
case R.id.buttonSexy:
Intent intent = new Intent(this,SexyPage.class);
startActivity(intent);
break;
}
};
}
}
There are actually 2 problems here:
First, as #Saiesh said, if you want to implement the click listener at the class level, you need to change your class declaration to implment OnClickListener. So your declaration will look like
public class FewOptions extends Activity implements OnClickListener{
The second problem (and the reason you're getting the error about void being a bad type) is that you're declaring the onClick method in the body of your onCreate method. move the declaration of the onClick method outside the closing brace (}) of the onCreate method and that error should go away.
One more note: after you make the 2 fixes above, don't forget to add your class as the click listener for the button:
sexy.setOnClickListener(this);
You need to pass right context
Intent intent = new Intent(FewOptions.this,SexyPage.class);
FewOptions.this.startActivity(intent);
Well the solution is that to use this onClick() method your class needs to implement the onClickListener interface . Thus your class heading should be something like this
public class FewOptions extends Activity implements onClickListener
{
//Eclipse will automatically ask you to override the onClick() method
}
So thats the solution :)

passing this to an outer class and starting an activity from alertdialog's list on Android

I am developing an Android app, this app has a dozen of Activities, each one is for a corresponding screen. Now I have this common subtitle bar on top of the screens.
this subtitle bar has a button to display an alert dialog which shows link list to go to a different screen.
I could write a same function for each activity to call the alert dialog, but that would be tedious if I want to modify them, so I created this class:
public class MenuAlertDialog extends Activity {
/*
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
*/
public void createMenu(final Context context){
AlertDialog.Builder dlg = new AlertDialog.Builder(context);
dlg.setTitle("menu");
String[] items = {"pageA", "pageB", "pageC", "pageD", "pageE"};
dlg.setItems(items, new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which){
switch(which){
case 0:
Intent intent = new Intent(context, MainActivity.class);
startActivity(intent);
break;
default:
break;
}
}
});
dlg.show();
}
}
and call it from each activity, like this:
MenuAlertDialog menu = new MenuAlertDialog();
menu.createMenu(this);
from inside of onCreate.
It can display the alertDialog, but whenever I press pageA link, it fails with an unexpected error.
Logcat says its a nullpointererror and the cause seems
startActivity(intent);
What am I doing wrong?
Remove the code
extends Activity
as you have no need to extend your class that you are creating since it does not rely on any activity related functionality.
Where you call startActivity(intent); replace it with
context.startActivity(intent);
You should change the class to Extends Dialog and not activity.
Also for Try this:
Check out this tutorial on how to create a custom dialog. Custom Dialog
Also Here Another Tutorial
And Here

calling method in a separate class

I have my main class setup and a worker thread, one of my early requests that I make in run() is to call my second class called login. I do this like so:
login cLogin = new login();
cLogin.myLogin();
class login looks like this:
package timer.test;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.widget.Toast;
public class login extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.main);
}
public void myLogin() {
// prepare the alert box
AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
// set the message to display
alertbox.setMessage(this.getString(R.string.intro));
// add a neutral button to the alert box and assign a click listener
alertbox.setNeutralButton("Register New Account",
new DialogInterface.OnClickListener() {
// click listener on the alert box
public void onClick(DialogInterface arg0, int arg1) {
// the button was clicked
}
});
// add a neutral button to the alert box and assign a click listener
alertbox.setNegativeButton("Login",
new DialogInterface.OnClickListener() {
// click listener on the alert box
public void onClick(DialogInterface arg0, int arg1) {
// the button was clicked
}
});
// show it
alertbox.show();
}
10-01 14:33:33.028: ERROR/AndroidRuntime(440):
java.lang.RuntimeException: Unable to start activity ComponentInfo{timer.test/timer.test.menu}:
java.lang.IllegalStateException:
System services not available to Activities before onCreate()
I put onCreate in but still having the same problem. How can I fix this?
You have a couple of options:
1) Move your public void myLogin() {..} to your main activity. I recommend this solution since you don't need another activity for your purposes.
2) Call startActivity on your login class before calling the myLogin(). Since you inherite from Activity onCreate needs to be called before you call anything else. That's why you get the exception. startActivity is called like this:
Intent i = new Intent(this, login.class);
startActivity(i);
You cannot do it this way simply because you are using the context
AlertDialog.Builder alertbox = new AlertDialog.Builder(this); //this is the activity context passed in..
The context is not available until Activity onCreate is called via startActivity. and not by constructing an new instance of the login object, you can try passing in an context from the activity calling this method
public void myLogin(Context context) {
// prepare the alert box
AlertDialog.Builder alertbox = new AlertDialog.Builder(context);
//blah blah blah...
}
yes and never construct an activity instance via the constructor.. -.-

Categories

Resources