Android custom view drawing twice - android

In my activity A, this view called twice, but in my activity B, there is no problem.
Activity A is very simple layout with a few linearLayout. I'm about to go crazy, what can be the problem?
Here is I have my AdBannerView:
public class AdBannerView extends LinearLayout {
public ImageView adIcon, adInstall;
public TextView_ adTitle, adDesc;
public ProgressBar adProgress;
RelativeLayout adWrapperLay;
private boolean impSent, adLoaded = false;
public AdBannerView(Context context) {
super(context);
}
public AdBannerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AdBannerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View wrapper = inflater.inflate(R.layout.view_ad_banner, this, true);
adIcon = (ImageView) wrapper.findViewById(R.id.adIcon);
adInstall = (ImageView) wrapper.findViewById(R.id.adInstall);
adTitle = (TextView_) wrapper.findViewById(R.id.adTitle);
adDesc = (TextView_) wrapper.findViewById(R.id.adDesc);
adProgress = (ProgressBar) wrapper.findViewById(R.id.adProgress);
adWrapperLay = (RelativeLayout) wrapper.findViewById(R.id.adWrapperLay);
Log.d("AdBannerView", "before loadAd()");
if(NativeAdManager.getInstance().isAdEnabled)
loadAd();
}
public void loadAd(){
if(adLoaded)
return;
adLoaded = true;
Log.d("AdBannerView", "loadAd() request");
NativeAdManager.getInstance().getAd(getContext(), new NativeAdManager.AdListener() {
#Override
public void adLoaded(final NativeAdResponse.Ads[] ads) {
/* load img */
Picasso
.with(getContext())
.load(ads[0].adIc)
.into(adIcon);
/* load title */
adTitle.setText(""+ads[0].adTit);
adDesc.setText(""+ads[0].adDesc);
/* click listener */
adInstall.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
App app = (App) getContext().getApplicationContext();
app.getUiController().loadUrlWithoutAdBlocker(ads[0].adClk);
}
});
/* show this layout */
showAd(ads[0].adBeacons);
Log.d("AdBannerView", "loaded with size = " + ads.length);
}
});
}
private void showAd(final NativeAdResponse.adBeacons[] adBeacons) {
adProgress.setVisibility(GONE);
adIcon.setVisibility(VISIBLE);
}
}
I'm including to layout like this:
<.... AdBannerView match_parent etc />
Logs that proves drawing twice:
10-29 20:28:19.219 6698-6698/pack D/AdBannerView﹕ before loadAd()
10-29 20:28:19.219 6698-6698/pack D/AdBannerView﹕ loadAd() request
10-29 20:28:19.295 6698-6698/pack D/AdBannerView﹕ before loadAd()
10-29 20:28:19.295 6698-6698/pack D/AdBannerView﹕ loadAd() request
10-29 20:28:19.636 6698-6698/pack D/AdBannerView﹕ loaded with size = 1
10-29 20:28:19.852 6698-6698/pack D/AdBannerView﹕ loaded with size = 1
Problematic activity A:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<package.AdManager.AdBannerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="40dp"
/>
</RelativeLayout>
Activity A.java (I deleted everything in layout and class except of AdBannerView but still same):
package package.Activity;
public class NewsRead extends Base {
ToolBarView toolBarView;
RelativeLayout backgroundLayForMainBgColor;
ImageView imageView;
TextView_ titleText, contentText, sourceText;
LinearLayout wrapperLay /* for homeViewRowBg */, relatedNewsLay;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResourceId());
/*
this.toolBarView = (ToolBarView) findViewById(R.id.toolBarView);
this.backgroundLayForMainBgColor = (RelativeLayout) findViewById(R.id.backgroundLayForMainBgColor);
this.imageView = (ImageView) findViewById(R.id.imageView);
this.titleText = (TextView_) findViewById(R.id.titleText);
this.contentText = (TextView_) findViewById(R.id.contentText);
this.sourceText = (TextView_) findViewById(R.id.sourceText);
this.wrapperLay = (LinearLayout) findViewById(R.id.wrapperLay);
changeTheme();
toolBarView.hideDeleteButton().setToolBarClickListener(new ToolBarView.ToolBarClickListener() {
#Override
public void backButtonClick() {
finish();
}
#Override
public void deleteButtonClick() {
}
});
Intent intent = getIntent();
if(intent == null)
return;
loadNewsDetail(intent);
*/
}
private void loadNewsDetail(Intent intent) {
String neTi = intent.getStringExtra("neTi");
String neCo = intent.getStringExtra("neCo");
String neSi = intent.getStringExtra("neSi");
String neIm = intent.getStringExtra("neIm");
String neUr = intent.getStringExtra("neUr");
/**/
Picasso
.with(this)
.load(neIm)
//.placeholder(R.drawable.icon_placeholder)
.into(imageView);
titleText.setText(neTi);
contentText.setText(neCo);
sourceText.setText("Source: "+ Html.fromHtml("<u>"+neSi+"</u>"));
}
private void changeTheme() {
ThemeModel curTheme = ThemeController.getInstance().getCurrentTheme();
if(curTheme.hasBgImage()) {
backgroundLayForMainBgColor.setBackground(curTheme.mainBgDrawable);
} else {
backgroundLayForMainBgColor.setBackgroundColor(Color.parseColor(ThemeController.getInstance().getCurrentTheme().mainBgColor));
}
wrapperLay.setBackgroundColor(Color.parseColor(curTheme.homeViewRowBg));
}
protected int getLayoutResourceId() {
return R.layout.activity_news_read;
}
#Override
protected void onSoftInputShown() {
}
#Override
protected void onSoftInputHidden() {
}
#Override
protected String getActivityName() {
return "news_read";
}
#Override
public void onBackPressed(){
super.onBackPressed();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
}
Base:
public abstract class Base extends Activity {
private boolean isKeyboardOpened;
#Override
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(getLayoutResourceId());
keyBoardListener();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
TrackingController.onActivityOpen(getActivityName());
}
}, 50);
}
#Override
public void onDestroy() {
super.onDestroy();
}
protected abstract int getLayoutResourceId();
public void Toast(String str) {
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
}
public void Log(String str) {
Log.d("act_name:"+getActivityName(), str);
}
private void keyBoardListener(){
final View activityRootView = getWindow().getDecorView().findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > 100 ) { // 99% of the time the height diff will be due to a keyboard.
if(isKeyboardOpened == false){
onSoftInputShown();
}
isKeyboardOpened = true;
}else if(isKeyboardOpened == true){
onSoftInputHidden();
isKeyboardOpened = false;
}
}
});
}
public String getString_(int resId){
return getResources().getString(resId);
}
protected abstract void onSoftInputShown();
protected abstract void onSoftInputHidden();
protected abstract String getActivityName();
}

Here's your bug :) Hopefully
You have in your base a call to setContentView and then in your deriving class you have call to super create (which calls the setContentView [which creates the adElement]) but after that you call again setContentView(getLayoutResourceId()); (this time from your derived class which overrides the layout but even if it didn't it's calling actually the same content I imagine so that's why it looks normal :)
So the fix should be easy - remove the setContentView(getLayoutResourceId()) from your activity A because it's already called from the base activity

Related

how to synchronise Between class controller contains AsyncTask and fragment

I am very very tired
I can't change visibility or an object in the fragment from the class controller
exmple addIteamsAutomatic.progressBar.setVisibility(View.GONE); return nullpointer
FragmentAddIteamsAutomatic :
public class FragmentAddIteamsAutomatic extends Fragment {
private EditText ssid, paswd;
public TextView afichage;
public Button parainage;
public Button validation;
public ProgressBar progressBar ;
public LinearLayout linearLayoutParm;
public static String sSSID,pWD;
private ControllerAddIteam controleAdd=null;
public FragmentAddIteamsAutomatic()
{
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.add_iteams_automatic, container, false);
controleAdd.getInstance(getActivity());
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
ssid = (EditText) view.findViewById(R.id.ssid);
paswd = (EditText) view.findViewById(R.id.password);
parainage = (Button) view.findViewById(R.id.btnParainage);
validation = (Button) view.findViewById(R.id.btnValid);
afichage = (TextView) view.findViewById(R.id.affichage);
linearLayoutParm = (LinearLayout) view.findViewById(R.id.linearLayParam);
progressBar.setVisibility(View.GONE);
afichage.setVisibility(View.GONE);
validation.setVisibility(View.GONE);
parainage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sSSID = ssid.getText().toString();
pWD = paswd.getText().toString();
if (sSSID.equals(""))
Toast.makeText(getActivity(), "Vous Dever Remplir Tous les champs", Toast.LENGTH_LONG).show();
else
parainer();
}
});
validation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
controleAdd.addSwitchToBase();
Intent intent = new Intent(getActivity(), MainActivity.class);
startActivity(intent);
ControllerAddIteam.accesDistant.send("getIteams", new JSONArray());
// finish();
}
});
return view;
}
private void parainer(){
controleAdd.getInstanceExecuteHandle();
}
}
ControllerAddIteam :
public class ControllerAddIteam {
private static ControllerAddIteam instanceAdd = null;
private static Context context;
private static WifiUtils wifiUtils;
public static String SSID = null;
public static AccesDistant accesDistant;
public static Handler mHandler;
public static final ControllerAddIteam getInstance(Context context) {
if (context != null)
ControllerAddIteam.context = context;
if (ControllerAddIteam.instanceAdd == null) {
ControllerAddIteam.instanceAdd = new ControllerAddIteam();
accesDistant = new AccesDistant();
}
return ControllerAddIteam.instanceAdd;
}
public static void getInstanceExecuteHandle() {
new ParainageHandle().execute();
}
static class ParainageHandle extends AsyncTask<String, String, String> {
FragmentAddIteamsAutomatic addIteamsAutomatic=new FragmentAddIteamsAutomatic();
#Override
protected void onPreExecute() {
super.onPreExecute();
addIteamsAutomatic.progressBar.setVisibility(View.GONE);
addIteamsAutomatic.afichage.setVisibility(View.GONE);
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
addIteamsAutomatic.progressBar.setVisibility(View.GONE);
if(s.equals("valid"))
{
addIteamsAutomatic.linearLayoutParm.setVisibility(View.GONE);
addIteamsAutomatic.validation.setVisibility(View.VISIBLE);
addIteamsAutomatic.parainage.setVisibility(View.GONE);
}
else if(s.equals("notvalid"))
{
addIteamsAutomatic.parainage.setVisibility(View.VISIBLE);
}
}
#Override
protected void onProgressUpdate(String... values) {
addIteamsAutomatic.afichage.setVisibility(View.VISIBLE);
addIteamsAutomatic.progressBar.setVisibility(View.VISIBLE);
if (values[0].equals("actwifi")) {
if (values[1].equals("true"))
addIteamsAutomatic.afichage.setText("WIFI DEJA ACTIVEE");
else
addIteamsAutomatic.afichage.setText("ACTIVATION WIFI EN COURS...");
} else if (values[0].equals("scan"))
addIteamsAutomatic.afichage.setText("START SCAN FOR Iteams STiTo ... Please Wait");
else if (values[0].equals("find"))
addIteamsAutomatic.afichage.setText("STiTo : "+getTypeFromSsid(SSID)+" DETECTEE : "+SSID);
else if (values[0].equals("connect"))
addIteamsAutomatic.afichage.setText("CONNECTION WITH " + SSID + "En cours ...");
else if (values[0].equals("connectOk"))
addIteamsAutomatic.afichage.setText("CONNECTION WITH " + SSID + "ETABLISHED");
else if (values[0].equals("connectKo"))
addIteamsAutomatic.afichage.setText("PROBLEM OF CONNECTION WITH " + SSID);
else if (values[0].equals("config")) {
addIteamsAutomatic.afichage.setText("SENDING OF CONFIGURATION TO: "+getTypeFromSsid(SSID)+"AND SAVING DATA");
accesDistant.sendConfig(addIteamsAutomatic.sSSID,addIteamsAutomatic.pWD);
....
You declare fragment in AsyncTask and doesn't call replace or add, it mean this fragment never show and it not call onCreateView
FragmentAddIteamsAutomatic addIteamsAutomatic=new FragmentAddIteamsAutomatic();
Maybe you should pass reference addIteamsAutomatic to class ControllerAddIteam. but please make sure it will be call on MainThread, because AsyncTask has method doInBackground in background Thread. best practice is wrap fragment reference by WeakReference
public class AddIteamActivity extends AppCompatActivity {
ViewPager pager;
TabLayout tab;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_iteam);
pager = findViewById(R.id.pager);
tab = findViewById(R.id.tab);
AddIteamsAdapter viewPagerAdapter = new AddIteamsAdapter(getSupportFragmentManager());
pager.setAdapter(viewPagerAdapter);
tab.setupWithViewPager(pager);
}
}

how should use getApplication method in PagerAdapter

I have a problem when I want to use getApplication() for this class, error is take plaaaaaaace...what should I use instead of getApplication() (Becaus I want to use the method of TestClass is named setNamePermit) or how I should setNamePermit() method of test class.
public class CustomSwipeAdapter01 extends PagerAdapter{
private int[] image_Resources = {R.drawable.sample_01,R.drawable.sample_02,R.drawable.sample_03,R.drawable.sample_04,R.drawable.sample_05,R.drawable.sample_06,R.drawable.sample_07};
private Context ctx;
private LayoutInflater layoutInflater;
public TestClass app;
public CustomSwipeAdapter01(Context ctx) {
this.ctx = ctx;
}
#Override
public int getCount() {
return image_Resources.length;
}
#Override
public boolean isViewFromObject(View view, Object o) {
return (view == (RelativeLayout) o);
}
#Override
public Object instantiateItem(final ViewGroup container, final int position) {
layoutInflater=(LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View item_view=layoutInflater.inflate(R.layout.activity_story01,container,false);
ImageView imageView=(ImageView)item_view.findViewById(R.id.image_view);
TextView textView=(TextView)item_view.findViewById(R.id.image_count);
Button btn_back_story01 = (Button) item_view.findViewById(R.id.btn_back_story01);
imageView.setImageResource(image_Resources[position]);
int itemNo=position+1;
textView.setText(itemNo + "/" + getCount());
container.addView(item_view);
//what should use instead of getApplication() in below line:
app = (TestClass)getApplication();
btn_back_story01.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((Activity) ctx).finish();
app.setNewPermit(false);
ctx.startActivity(new Intent(ctx, MainStory01.class));
}
});
return item_view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((RelativeLayout)object);
}
}
Test Class is:
public class TestClass extends Application {
public Boolean getMedia_state() {
return media_state;
}
public void setMedia_state(Boolean media_state) {
this.media_state = media_state;
}
Boolean media_state;
Boolean checkPlaying;
public Boolean getNewPermit() {
return newPermit;
}
public void setNewPermit(Boolean newPermit) {
this.newPermit = newPermit;
}
Boolean newPermit;
MediaPlayer media;
#Override
public void onCreate() {
super.onCreate();
setMedia_state(true);
setNewPermit(true);
media = new MediaPlayer();
media = MediaPlayer.create(getApplicationContext(), R.raw.music);
}
public void musicRestart() {
media = MediaPlayer.create(getApplicationContext(), R.raw.music);
media.start();
media.setLooping(true);
}
public void musicPlay() {
media.start();
media.setLooping(true);
}
public boolean checkPlaying() {
if (media.isPlaying()) {
checkPlaying = true;
} else {
checkPlaying = false;
}
return checkPlaying;
}
public void musicStop() {
media.stop();
}
}
TestClass tc = new TestClass();
Accessing methods in TestClass:
tc.setNewPermit(false);
UPDATE: in your pager adapter, you can now pass any of those values around. For example, change your btn_back_story01 onClick() to:
btn_back_story01.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(CustomSwipeAdapter01.this, MainStory01.class);
intent.putExtra("is_new_permit", tc.getNewPermit());
startActivity(intent);
}
});
In MainStory01 activity's onCreate() you can now get the extras passed in your Intent, via Bundle...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getIntent().getExtras();
if(bundle != null) {
boolean isNewPermit = bundle.getBoolean("is_new_permit");
}
}
There may be some errors in the code, I am not at my work computer at the moment, but this should give you an idea of how to proceed.

How to update a textview in a dialog fragment from an activity?

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.

Inheritance issues with Android annotations and OnClickListener

This is the inheritance that I'm using
GenericActivity -> GraphGenericActivity -> NormalActivity
I have an options menu with contains a help button which show a help view over the current one and this works fine however it's the close button that doesn't work, with #Click I doesn't work on any of the views and if I register a onClickListener the old fashionned way It only workds on Activities that extend directly from "GenericActivity
GENERIC ACTIVITY
#EActivity
#OptionsMenu(R.menu.menu_generic)
public abstract class GenericActivity extends Activity{
public static final String TAG = "GenericActivity";
protected Context context;
protected LayoutInflater vi;
protected View helpView;
#ViewById
protected RelativeLayout rootLayout;
#ViewById
protected Button closeHelpButton;
protected abstract int getHelpLayoutInt();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
getActionBar().setDisplayHomeAsUpEnabled(true);
}
#AfterViews
protected void afterViews() {
vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
helpView = vi.inflate(this.getHelpLayoutInt(), null);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
helpView.setVisibility(View.GONE);
if (helpView != null) {
rootLayout.addView(helpView, layoutParams);
}
final Button button = (Button) findViewById(R.id.closeHelpButton);
button.setOnClickListener(new View.OnClickListener() {
#Override
#Trace
public void onClick(View v) {
Toast.makeText(context, "close help", Toast.LENGTH_SHORT).show();
if (helpView != null) {
helpView.setVisibility(View.GONE);
}
}
});
}
#OptionsItem
protected boolean menuHelp() {
if (helpView != null) {
if (helpView.getVisibility() == View.GONE) {
helpView.setVisibility(View.VISIBLE);
} else {
helpView.setVisibility(View.GONE);
}
}
return true;
}
}
CHILD ACTIVITY
#EActivity(R.layout.activity_start_screen)
public class StartScreen extends GenericActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(false);
CALog.i("onCreateFinished");
}
#Trace
#Override
protected void onDestroy() {
domboxTouchServiceManager.unbindFromDomboxService();
super.onDestroy();
}
#Override
protected int getHelpLayoutInt() {
return R.layout.layout_start_screen_help;
}
}

The value of the variable has been suddenly set to 0

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.

Categories

Resources