I created an AlertDialog :
public class MessageDialogView extends AlertDialog {
private Context ctxt;
private View contenu, titleBar;
#SuppressLint("NewApi")
public MessageDialogView(Context context, LayoutInflater inflater) {
super(context);
ctxt = context;
contenu = inflater.inflate(R.layout.msg_dialog, null);
titleBar = inflater.inflate(R.layout.custom_dialog_title, null);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setCustomTitle(titleBar);
setView(contenu, 0, 0, 0, 0);
setButton(DialogInterface.BUTTON_POSITIVE, ctxt.getResources().getString(R.string.button_ok), new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
}
public void setTitre(String titre) {
if (titre != null)
((TextView)titleBar.findViewById(R.id.titre)).setText(titre);
}
public void setMsg(String text){
if (text != null)
((TextView)contenu.findViewById(R.id.msgText)).setText(text);
}
}
The xml layout are very simple ( not necessary to copy their code here :) )
When I try to show the AlertDialog then nothing is showing : just the screen is darkened !
public class SyncActivity extends Activity {
private RadioButton webVersMobile = null;
private MessageDialogView dlg = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.syncro);
webVersMobile = (RadioButton) findViewById(R.id.webMobile);
dlg = new MessageDialogView(SyncActivity.this, getLayoutInflater());
}
...
public void displayError(String msg) {
dlg.setTitre(getString(R.string.titreErrMsgBox));
dlg.setMsg(msg);
dlg.show();
}
...
}
I call the dialog like this :
private class RequestTask extends AsyncTask<String, Void, String> {
...
#Override
protected String doInBackground(String... s_url) {
...
}
#Override
protected void onPostExecute(String result) {
if (error) {
displayError(result);
} else {
}
}
private void displayError(String msg) {
dlg.setTitre(getString(R.string.titreErrMsgBox));
dlg.setMsg(msg);
dlg.show();
}
}
So what is wrong in my code ?
You forgot to call show() method to display the dialog.
dlg = new MessageDialogView(SyncActivity.this, getLayoutInflater());
After this line write dlg.show(); in onCreate() method.
Ok , I found that the reason of my error is that I implemented the onCreate method. When I removed the implementation then the Dialog is shown :)
public class MessageDialogView extends AlertDialog {
private View contenu, titleBar;
#SuppressLint("InlinedApi")
public MessageDialogView(Context context, LayoutInflater inflater) {
super(context, AlertDialog.THEME_HOLO_DARK);
contenu = inflater.inflate(R.layout.msg_dialog, null);
titleBar = inflater.inflate(R.layout.custom_dialog_title, null);
setCustomTitle(titleBar);
setView(contenu, 0, 0, 0, 0);
setButton(DialogInterface.BUTTON_POSITIVE, context.getResources().getString(R.string.button_ok), new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
}
public void setTitre(String titre) {
if (titre != null)
((TextView)titleBar.findViewById(R.id.titre)).setText(titre);
}
public void setMsg(String text){
if (text != null)
((TextView)contenu.findViewById(R.id.msgText)).setText(text);
}
}
Related
my onAttach() method assigns the context to the listener, however, my listener is null somehow. How can I fix this problem properly? I hope you can provide me the code with some instructions?
ChooseScreen class which initializes the dialog (In this case nameDialog):
public class ChooseScreen extends AppCompatActivity {
private Button vsFriend;
private Button vsAndroid;
private NameDialog.NameDialogListener listener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_choose_screen);
vsFriend = findViewById(R.id.vsF);
vsAndroid = findViewById(R.id.vsA);
vsFriend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openDialog();
}
});
}
public void openDialog() {
NameDialog nameDialog = new NameDialog();
nameDialog.show(getSupportFragmentManager(), "example");
}
}
NameDialog class with getTexts interface:
public class NameDialog extends AppCompatDialogFragment {
private EditText firstPlayer;
private EditText secondPlayer;
private NameDialogListener listener;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
final View view = inflater.inflate(R.layout.layout_dialog, null);
firstPlayer = view.findViewById(R.id.edit_player1);
secondPlayer = view.findViewById(R.id.edit_player2);
builder.setView(view)
.setTitle("Names")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
String player1 = firstPlayer.getText().toString();
String player2 = secondPlayer.getText().toString();
listener.getTexts(player1, player2);
// Intent intent = new Intent(NameDialog.this.getActivity(), Game.class);
// startActivity(intent);
}
});
return builder.create();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
listener = (NameDialogListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + "must implement");
}
}
public interface NameDialogListener {
void getTexts(String player1, String player2);
}
}
Game class which implements NameDialogListener and overrides the interface method(getTexts):
public class Game extends AppCompatActivity implements
NameDialog.NameDialogListener {
private TextView player1Name;
private TextView player2Name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
player1Name = findViewById(R.id.player1TextView);
player2Name = findViewById(R.id.player2TextView);
}
#Override
public void getTexts(String player1, String player2) {
player1Name.setText(player1);
player2Name.setText(player2);
}
}
Error: If I don't use try-catch block, the error will be NullPointerException because listener is null!
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.user.tictactoe, PID: 30462
java.lang.ClassCastException: com.example.user.tictactoe.ChooseScreen#1a0a489must implement
at com.example.user.tictactoe.NameDialog.onAttach(NameDialog.java:62)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1372)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:797)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2596)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2383)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2338)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2245)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:703)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1518)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
When you attach your Fragment you attempt to get a Listener from your ChoooseScreen Activity. That Activity does not implement NameDialogListener, so you get a ClassCastException. In your examples you show another Activity, Game that does implement the listener, however any activity you add your Fragment in will need to implement the listener to work with your onAttach() code.
Short answer: if you want to show the Fragment in ChooseScreen, your code requires ChooseScreen to implement NameDialogListener.
onAttach will get the context of your parent activity. when you open your Dialog from ChooseScreen activity, the parent is ChooseScreen. The interface callback will be given to ChooseScreen itself. Then what you need to do is to call Intent with player1Name and player2Name.
Anyways I will share the code for you.
Your ChooseScreen
public class ChooseScreen extends AppCompatActivity implements NameDialog.NameDialogListener {
private Button vsFriend;
private Button vsAndroid;
private NameDialog.NameDialogListener listener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_choose_screen);
vsFriend = findViewById(R.id.vsF);
vsAndroid = findViewById(R.id.vsA);
vsFriend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openDialog();
}
});
}
public void openDialog() {
NameDialog nameDialog = new NameDialog();
nameDialog.show(getSupportFragmentManager(), "example");
}
#Override
public void getTexts(String player1, String player2) {
Intent intent = new Intent(this, Game.class);
intent.putExtra("PLAYER_ONE", player1);
intent.putExtra("PLAYER_TWO", player2);
startActivity(intent);
}
}
Your NameDialog
public class NameDialog extends AppCompatDialogFragment {
private EditText firstPlayer;
private EditText secondPlayer;
private NameDialogListener listener;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
final View view = inflater.inflate(R.layout.layout_dialog, null);
firstPlayer = view.findViewById(R.id.edit_player1);
secondPlayer = view.findViewById(R.id.edit_player2);
builder.setView(view)
.setTitle("Names")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
String player1 = firstPlayer.getText().toString();
String player2 = secondPlayer.getText().toString();
listener.getTexts(player1, player2);
//TODO you can simply use below code and comment listener.getTexts();
// Intent intent = new Intent(NameDialog.this.getActivity(), Game.class);
// intent.putExtra("PLAYER_ONE", player1);
// intent.putExtra("PLAYER_TWO", player2);
// startActivity(intent);
}
});
return builder.create();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listener = (NameDialogListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + "must implement");
}
}
public interface NameDialogListener {
void getTexts(String player1, String player2);
}
}
Your Game
public class Game extends AppCompatActivity
/* implements NameDialog.NameDialogListener*/ {
private TextView player1Name;
private TextView player2Name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
player1Name = findViewById(R.id.player1TextView);
player2Name = findViewById(R.id.player2TextView);
player1Name.setText(
getIntent().getStringExtra("PLAYER_ONE"));
player2Name.setText(
getIntent().getStringExtra("PLAYER_TWO"));
}
// #Override
// public void getTexts(String player1, String player2) {
// }
}
Try this and let me know...
I am working on an app and I am using a custom dialog which extends DialogFragment. This dialog will contain certain field that I want to pass to the parent activity. I tried implementing OnDismissListener but the parameter is a Dialog Interface.
Any Idea?
parent Activity:
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
BreakCreator mDialog = new BreakCreator();
mDialog.show(getSupportFragmentManager(), "start break Creator");
}
});
listener:
#Override
public void onDismiss(DialogInterface dialog) {
Log.d("debug", "in onDismiss");
BreakCreator mBreakCreator = BreakCreator.class.cast(dialog);// This MIGHT not work
//TODO cast and shit
if(!mBreakCreator.isCancelled() ){
int startMinute = mBreakCreator.getStartMinute();
int startHour = mBreakCreator.getStartHour();
int endMinute = mBreakCreator.getEndMinute();
int endHour = mBreakCreator.getEndHour();
String day = mBreakCreator.getDay();
Break mBreak = new Break(new ultramirinc.champs_mood.Time(startHour, startMinute),
new ultramirinc.champs_mood.Time(endHour, endMinute), day);
breakList.add(mBreak);
Log.d("created", "break added");
recyclerView.invalidate();
}else{
Log.d("debug", "is not cancelled");
}
}
Dialog Class:
public void onDismiss(final DialogInterface dialog) {
super.onDismiss(dialog);
final Activity activity = getActivity();
if (activity instanceof DialogInterface.OnDismissListener) {
((DialogInterface.OnDismissListener) activity).onDismiss(dialog);
}
}
Use a custom listener, below is an example on how this could be implemented. This is also explained in the Android Developer Guide.
public class CustomDialog extends DialogFragment {
public interface CustomListener{
void onMyCustomAction(CustomObject co);
}
private CustomListener mListener;
public void setMyCustomListener(CustomListener listener){
mListener = listener;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
Code to create dialog
...
}
#Override
public void onDismiss(DialogInterface dialog) {
if(mListener != null){
CustomObject o = new CustomObject();
mListener.onMyCustomAction(o);
}
super.onDismiss();
}
}
And when the custom dialog is created, set the listener.
CustomDialog awesomeDialog = new CustomDialog();
awesomeDialog.setMyCustomListener(new CustomDialog.CustomListener() {
#Override
public void onMyCustomAction(CustomObject o){
Log.i("TAG",o.toString());
}
});
It may be a silly question but I didn't find a good way to update a dialogfragment's textview from an activity in my android app.
What I'd like to do is to update the textview every second with a counter value and once the time elapsed, a Runnable closes the dialog fragment.
The dialog is closed once the time is elapsed, no problem but I cannot update the textview I want.
Here's my code for the dialog:
public class AlertDialog extends DialogFragment {
private String message = null;
private String title = null;
private ImageView imgV = null;
private TextView msgTv = null;
private TextView counterTv = null;
private Button okBtn = null;
private int imageId = 0;
public static int AUTOMATIC_CLOSE = 100001;
private AlertDialogListener mDialogListener;
public void setImage(int i){
imageId = i;
}
public void setContent(String ttl, String msg){
message = msg;
title = ttl;
}
public boolean hasContent(){
return message != null && title != null;
}
public AlertDialog(){
}
public void performClick(){
okBtn.performClick();
}
public void updateField(String text){
counterTv.setText(text);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dialog, container);
msgTv = (TextView)v.findViewById(R.id.textDialog);
imgV = (ImageView)v.findViewById(R.id.imageDialog);
counterTv = (TextView)v.findViewById(R.id.timeCounterDialog);
if(imageId != 0)
imgV.setImageResource(imageId);
else
imgV.setImageResource(R.drawable.error_icon);
if(hasContent()){
msgTv.setText(message);
getDialog().setTitle(title);
}
else{
getDialog().setTitle("ERROR");
msgTv.setText("An unexcepted error occured");
}
okBtn = (Button)v.findViewById(R.id.validateButton);
okBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mDialogListener != null){
mDialogListener.onFinishedDialog();
}
}
});
return v;
}
#Override
public void onStart() {
mDialogListener.onStartedDialog();
super.onStart();
}
#Override
public void onAttach(Activity activity) {
mDialogListener = (AlertDialogListener) activity;
super.onAttach(activity);
}
#Override
public void onDetach() {
mDialogListener = null;
super.onDetach();
}
public interface AlertDialogListener{
void onStartedDialog();
void onFinishedDialog();
}
}
And this is how I launch it:
class myActivity extends Activity implements AlertDialogListener{
protected void onCreate(Bundle savedInstanceState){
"""some init stuff"""
button.setOnClickListener(new View.OnClickListener() {
showAlertDialog();
}
}
#Override
public void onStartedDialog() {
AutoCloseRunnable mAutoClose = new AutoCloseRunnable();
mHandler.postDelayed(mAutoClose, 1000);
}
#Override
public void onFinishedDialog() {
this.finish();
}
private void showAlertDialog(){
FragmentManager fm = getFragmentManager();
mAlertDialog = new AlertDialog();
mAlertDialog.setContent("No Connection available", "Please enable your internet connection.");
mAlertDialog.setImage(R.drawable.error_icon);
mAlertDialog.show(fm, "fragment_alert");
}
private void updateAlertDialog(String text){
mAlertDialog.updateField(text);
}
private void autoCloseAlertDialog(){
mAlertDialog.performClick();
}
public class AutoCloseRunnable implements Runnable{
#Override
public void run() {
int closeCpt = 10;
while(closeCpt >= 0){
try {
Thread.sleep(1000);
updateAlertDialog("Will close automatically in " + closeCpt + " seconds.");
closeCpt--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
autoCloseAlertDialog();
}
}
}
Does anyone know how to proceed?
I solved it, simply use asynctask it's easier to handle UI updates like this.
I'm doing an activity to measure how long it takes a person to do an exercise, but it has a bug that I couldn't resolve yet...
The TrainingFragment shows a list of exercises that the user can click and then my ExerciseActivity is launched and runs until the variable "remainingsSets" is setted to 0.
When I click in the first time at any exercise, everything works fine, the ExerciseActivity works correctly end return to the TrainingFragment. But then, if I try to click in another exercise, the ExerciseActivity is just closed.
In my debug, I could see that the variable "remainingSets" comes with it's right value (remainingSets = getIntent().getIntExtra("remaining_sets", 3)), but when the startButton is clicked, I don't know why the variable "remainingSets" is setted to 0 and then the activity is closed because this condition: if (remainingSets > 0){...}.
Here is my TrainingFragment:
public class TrainingFragment extends Fragment {
private final static int START_EXERCISE = 1;
private Training training;
private String lastItemClicked;
private String[] values;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Bundle bundle = getArguments();
if (bundle != null) {
training = bundle.getParcelable("training");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return (ScrollView) inflater.inflate(R.layout.template_exercises, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LinearLayout exercisesContainer = (LinearLayout) getView().findViewById(R.id.exercises);
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
List<Exercise> exercises = training.getExercises();
values = new String[exercises.size()];
if (savedInstanceState != null) {
values = savedInstanceState.getStringArray("values");
}
for (int i = 0; i < exercises.size(); i++) {
final View exerciseView = inflater.inflate(R.layout.template_exercise, null);
exerciseView.setTag(String.valueOf(i));
TextView remainingSets = (TextView) exerciseView.findViewById(R.id.remaining_sets);
if (savedInstanceState != null) {
remainingSets.setText(values[i]);
} else {
String sets = exercises.get(i).getSets();
remainingSets.setText(sets);
values[i] = sets;
}
exerciseView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), ExerciseActivity.class);
intent.putExtra("remaining_sets",
Integer.valueOf(((TextView) v.findViewById(R.id.remaining_sets)).getText().toString()));
lastItemClicked = v.getTag().toString();
startActivityForResult(intent, START_EXERCISE);
}
});
exercisesContainer.addView(exerciseView);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putStringArray("values", values);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
View view = ((LinearLayout) getView().findViewById(R.id.exercises)).findViewWithTag(lastItemClicked);
if (requestCode == START_EXERCISE) {
if (resultCode == Activity.RESULT_OK) { // the exercise had been
// finished.
((TextView) view.findViewById(R.id.remaining_sets)).setText("0");
view.setClickable(false);
values[Integer.valueOf(lastItemClicked)] = "0";
} else if (resultCode == Activity.RESULT_CANCELED) {
String remainingSets = data.getStringExtra("remaining_sets");
((TextView) view.findViewById(R.id.remaining_sets)).setText(remainingSets);
values[Integer.valueOf(lastItemClicked)] = remainingSets;
}
}
}
}
My ExerciseActivity:
public class ExerciseActivity extends Activity {
private Chronometer chronometer;
private TextView timer;
private Button startButton;
private Button endButton;
private int remainingSets;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise);
ExerciseEvents.addExerciseListener(new PopupExerciseListener());
chronometer = (Chronometer) findViewById(R.id.exercise_doing_timer);
timer = (TextView) findViewById(R.id.timer);
startButton = (Button) findViewById(R.id.start_exercise);
startButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ExerciseEvents.onExerciseBegin();
}
});
endButton = (Button) findViewById(R.id.end_exercise);
endButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ExerciseEvents.onExerciseRest();
}
});
}
#Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("remaining_sets", String.valueOf(remainingSets));
setResult(RESULT_CANCELED, intent);
super.onBackPressed();
}
public class PopupExerciseListener implements ExerciseListener {
public PopupExerciseListener() {
remainingSets = getIntent().getIntExtra("remaining_sets", 3);
}
#Override
public void onExerciseBegin() {
if (remainingSets > 0) {
chronometer.setVisibility(View.VISIBLE);
timer.setVisibility(View.GONE);
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.start();
startButton.setVisibility(View.GONE);
endButton.setVisibility(View.VISIBLE);
} else {
ExerciseEvents.onExerciseFinish();
}
}
#Override
public void onExerciseFinish() {
setResult(RESULT_OK);
finish();
}
#Override
public void onExerciseRest() {
chronometer.setVisibility(View.GONE);
endButton.setVisibility(View.GONE);
timer.setVisibility(View.VISIBLE);
long restTime = getIntent().getLongExtra("time_to_rest", 60) * 1000;
new CountDownTimer(restTime, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timer.setText(String.valueOf(millisUntilFinished / 1000));
}
#Override
public void onFinish() {
ExerciseEvents.onExerciseBegin();
}
}.start();
remainingSets--;
}
}
}
And my ExerciseEvents:
public class ExerciseEvents {
private static LinkedList<ExerciseListener> mExerciseListeners = new LinkedList<ExerciseListener>();
public static void addExerciseListener(ExerciseListener listener) {
mExerciseListeners.add(listener);
}
public static void removeExerciseListener(String listener) {
mExerciseListeners.remove(listener);
}
public static void onExerciseBegin() {
for (ExerciseListener l : mExerciseListeners) {
l.onExerciseBegin();
}
}
public static void onExerciseRest() {
for (ExerciseListener l : mExerciseListeners) {
l.onExerciseRest();
}
}
public static void onExerciseFinish() {
for (ExerciseListener l : mExerciseListeners) {
l.onExerciseFinish();
}
}
public static interface ExerciseListener {
public void onExerciseBegin();
public void onExerciseRest();
public void onExerciseFinish();
}
}
Could anyone give me any help?
After you updated your code, I see you have a big memory leak in your code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise);
ExerciseEvents.addExerciseListener(new PopupExerciseListener());
....
}
The call ExerciseEvents.addExerciseListener(new PopupExerciseListener()) adds a new PopupExerciseListener to a static/global list: ExcerciseEvents.mExerciseListeners. Since the class PopupExerciseListener is an inner-class, it implicitly holds a reference to its enclosing ExcerciseActivity. This mean your code is holding on to each instance of ExcerciseActivity forever. Not good.
This may also explain the weird behavior you see. When one of the onExcersizeXXX() methods is called, it will call all ExcerciseListeners in the linked-list, the ones from previous screens and the current one.
Try this in your ExcerciseActivity.java:
....
ExerciseListener mExerciseListener;
....
#Override
protected void onCreate(Bundle savedInstanceState) {
....
....
mExerciseListener = new PopupExerciseListener()
ExerciseEvents.addExerciseListener(mExerciseListener);
....
....
}
#Override
protected void onDestroy() {
ExerciseEvents.removeExerciseListener(mExerciseListener);
super.onDestroy();
}
....
In onDestroy, you deregister your listener, preventing a memory leak and preventing odd multiple callbacks to PopupExerciseListeners that are attached to activities that no longer exist.
I got a method in which server-client communication is done "onClick" therefor i create a anonymous OnClickListener, and I want to publish a toast if the communication was successfull or not.
To do this I need the Acitivity in which context to publish the toast, and as I externalized the method, it must be given as a "this" argument to the Activity. But as I am inside an anonymous inner class I cannot access the this pointer of the Acitivity, and even though I stored it in a local final variable
private final Activity activity = this;
#Override
public void onCreate(Bundle savedInstanceState) {
lastResult = null;
super.onCreate(savedInstanceState);
setLayout(R.layout.main);
qrscan = (Button) findViewById(R.id.qrcodescan);
qrscan.setOnClickListener( new View.OnClickListener() {
public void onClick(View view) {
initiateScan(activity);
}
}
);
}
private AlertDialog initiateSend(Activity activity) {
if(lastResult != null) {
String[] arr = lastResult.content.split("/");
AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
String[] args = Util.filterString(arr,this);
downloadDialog.setTitle(args[0]);
downloadDialog.setMessage("Auftragsnummer:" + args[1]);
downloadDialog.setPositiveButton(getString(R.string.ja), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
try {
String send = lastResult.content;
send += "/uid/" + R.id.username + "/cid/" + R.id.password;
String result = Util.send(send);
//toaster(send);
Util.toaster(result,activity);
if(!(result.equals("OK") || result.equals("ok") || result.equals("Ok")))
throw new Exception("Bad Server Answer");
Util.toaster("Communication erfolgreich",activity);
} catch(Exception ex) {
ex.printStackTrace();
Util.toaster("Communication nicht erfolgreich",activity);
}
}
});
downloadDialog.setNegativeButton(getString(R.string.nein), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {}
});
return downloadDialog.show();
}
return null;
}
Any clue what i messed up?
declare variable before onCreate() like this
public class HelloAndroid extends Activity {
Activity activity = this; // declare here
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
EDITED
Activity mainActivity;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setLayout(R.layout.main);
mainActivity = this;
lastResult = null;
qrscan = (Button) findViewById(R.id.qrcodescan);
qrscan.setOnClickListener( new View.OnClickListener() {
public void onClick(View view) {
initiateScan(mainActivity);
}
}
);
}
private AlertDialog initiateSend(final Activity activity) {
if(lastResult != null) {
String[] arr = lastResult.content.split("/");
AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
String[] args = Util.filterString(arr,this);
downloadDialog.setTitle(args[0]);
downloadDialog.setMessage("Auftragsnummer:" + args[1]);
downloadDialog.setPositiveButton(getString(R.string.ja), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
try {
String send = lastResult.content;
send += "/uid/" + R.id.username + "/cid/" + R.id.password;
String result = Util.send(send);
//toaster(send);
Util.toaster(result,activity);
if(!(result.equals("OK") || result.equals("ok") || result.equals("Ok")))
throw new Exception("Bad Server Answer");
Util.toaster("Communication erfolgreich",activity);
} catch(Exception ex) {
ex.printStackTrace();
Util.toaster("Communication nicht erfolgreich",activity);
}
}
});
downloadDialog.setNegativeButton(getString(R.string.nein), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {}
});
return downloadDialog.show();
}
return null;
}