0

I have an ImageButton and I want its image to change every time that onResume() or onCreate() is called.

I have a method which changes the image, called mUpdateBackground, but I'm having trouble working out how to structure the hierarchy so that the mUpdateBackground, (containing the ImageButton) can be called from onResume() and onCreate().

If backgroundPic is true, and image will be selected randomly, if false then R.drawable.bg0 will be used instead.

There is a separate settings activity which manages whether the backgroundPic variable is set to true or false.

Here's my code so far:

1 public class MainActivity extends Activity {
2   public static ImageButton mGetClickTime;
3 @Override
4   protected void onResume() {
5        super.onResume();
6       //Get shared preferences
7               mSharedPreferences = getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE);
8           dp = mSharedPreferences.getInt("DecimalPlaces", 0);
9               length_setting = mSharedPreferences.getInt("MSSelector", 1);
10              backgroundPic = mSharedPreferences.getBoolean("BackgroundPic", true);
11              //mUpdateBackground();  
12          }
12  @Override
13  protected void onCreate(Bundle savedInstanceState) {
14      super.onCreate(savedInstanceState);
15      setContentView(R.layout.activity_main);
16
17      //Get shared preferences
18      mSharedPreferences = getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE);
19      dp = mSharedPreferences.getInt("DecimalPlaces", 0);
20      length_setting = mSharedPreferences.getInt("MSSelector", 5);
21      mUpdateBackground();
22          mGetClickTime.setOnClickListener(new View.OnClickListener() {
23      mUpdateBackground();
24          }
25     }
26 }
27  public void mUpdateBackground() {
28      if (backgroundPic) {
29          int[] imageIds = { 
30                  R.drawable.bg1,
31                  R.drawable.bg2,
32                  R.drawable.bg3,
33                  R.drawable.bg4,
34
35          };
36          Random generator = new Random();
37          randomImageId = imageIds[generator.nextInt(imageIds.length)];
38          Log.d("1", "backgroundPic: "+randomImageId);
39      }
40      else {
41          randomImageId = R.drawable.bg0;
42          Log.d("1", "backgroundPic: "+randomImageId);
43      }
44      mGetClickTime = (ImageButton) findViewById(R.id.clicker);
45      mGetClickTime.setImageResource(randomImageId);
46  }

The problem I have with this is that if I uncomment line 11 I get a NullPointerException. Is there a better way I should organise this code?

CRUSADER
  • 5,486
  • 3
  • 28
  • 64
Dicky Moore
  • 956
  • 3
  • 10
  • 32
  • Your mGetClickTime is static! This is wrong since it depends on the activity. What line in the mUpdateBackground method is throwing the NPE? – Bartek Filipowicz May 19 '13 at 12:41
  • Also in standard convention methods are not named with m in the beginning. m states that an object is a member variable i.e. it is bound to the instance of this class. s is for static, so if you have a static variable it should be named sVariable. – Bartek Filipowicz May 19 '13 at 12:42

3 Answers3

1

you should check your code for if anything is null before using it. you don't check if imageIds[] is null before use and also (Its been awhile) you want to make sure mGetClickTime was assigned something by findViewById. In onresume it always seems possible that stuff can have gone out of memory. I typically check everything to see if i need to re-initialize a variable in on resume when i've done android in the past. I'm suggesting this as a way to debug and be more robust.

LanternMike
  • 664
  • 1
  • 5
  • 16
  • Thanks, I'll try that. How do I check if the method mUpdateBackground is null? Or did you mean the contents of the method, like mGetClickTime? – Dicky Moore May 19 '13 at 17:20
  • i meant the contents i.e. any variables that are null for some reason. – LanternMike May 19 '13 at 17:22
  • I'm trying to do that, but the null pointer exception seems to occur when the method is called on line 11. Even if I comment out the entire contents of mUpdateBackground, the null pointer exception still occurs. So I guess I should infer that it's the mUpdateBackground object itself which is being lost from memory? – Dicky Moore May 19 '13 at 20:24
  • I don't think calling a method would result in a null pointer if it has nothing in the method (commented out), but maybe thats a new one for me. But the work of the method not being done can sometimes trigger null pointers. Also the other answer that you can do all your work of oncreate in onresume is actually true. This forces you to consider for every variable do i need to create or do i have a non null variable. – LanternMike May 19 '13 at 20:31
  • This is really useful advice. This helped me fix the issue. It does seem to be that the button gets forgotten about, so if that happens I reassign it. Here's the code: – Dicky Moore May 19 '13 at 21:24
  • if (mGetClickTime != null) { Log.d("mGetClickTime: ", "is not null"); mGetClickTime.setImageResource(randomImageId); } else { mGetClickTime = (ImageButton) findViewById(R.id.clicker); mGetClickTime.setImageResource(randomImageId); Log.d("mUpdateBackground", " was null"); } – Dicky Moore May 19 '13 at 21:25
1

This is how your hierarchy might look like: in onCreate() bind do setContentView and assign the button with the OnClickListener.

The logic that should be done in both onCreate() and in onResume() can be done in the onResume() only! The onResume() is always called after the onCreate(), but onCreate() is not always called before the onResume(). If your activity is put activate back from the background it will not be recreated, but the onResume() will be called.

One more thing is that your ImageButton variable is static, which it should never be! This is instance specific field, and should be stored in an instance (member) variable.

The other thing (as I mentioned in the comments) is that your method should not be named with mMethod convention. This is reserved for member variables.

Bartek Filipowicz
  • 1,235
  • 7
  • 9
  • Actually, I noticed that onResume was listed before onCreate in the code. Could that have caused the problem? If so then this post helped me find the answer aswell as the other one. – Dicky Moore May 19 '13 at 21:33
  • The order of declaring/overriding methods in the code does not matter. Check out this article about Activity and its lifecycle to get to know how it works exactly :) http://developer.android.com/reference/android/app/Activity.html – Bartek Filipowicz May 20 '13 at 06:51
0

I got the answer from this thread: Android: What's the best hierarchy for this app?

The key was learning the concept of checking if an object is null before calling it.

The code I used was this:

if (mGetClickTime != null) {
    Log.d("mGetClickTime: ", "is not null");
    mGetClickTime.setImageResource(randomImageId);
}
else {
    mGetClickTime = (ImageButton) findViewById(R.id.clicker);
    mGetClickTime.setImageResource(randomImageId);
    Log.d("mUpdateBackground", " was null");
}
Community
  • 1
  • 1
Dicky Moore
  • 956
  • 3
  • 10
  • 32