194

I want to force the main layout resource view to redraw / refresh, in say the Activity.onResume() method. How can I do this ?

By main layout view, I mean the one ('R.layout.mainscreen' below) that is called in my Activity.onCreate(), like this:-

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mainscreen);
}
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
MickeyR
  • 1,858
  • 2
  • 13
  • 24
  • Have you tried naming your enclosing Linear/Relative/WhateverLayout, calling findViewById on it, and then calling invalidate() on that? (I'd put this as an answer, but I don't know if invalidating parents also invalidates children and I'm not somewhere I can test it.) – Ben Williams May 13 '11 at 12:51
  • Thanks also ! I'm still struggling with this though. Can you take a look at what I've posted below. I need this code (or other ?) to cause my theme to refresh... – MickeyR May 13 '11 at 13:56

18 Answers18

160

To strictly answer the question: Use invalidate():

public void invalidate () Since: API Level 1

Invalidate the whole view. If the view is visible, onDraw(Canvas) will be called at some point in the future. This must be called from a UI thread. To call from a non-UI thread, call postInvalidate().

ViewGroup vg = findViewById (R.id.mainLayout);
vg.invalidate();

Now, when the Activity resumes, it makes every View to draw itself. No call to invalidate() should be needed. To apply the theme, make sure you do it before any View is drawn, i.e., before setContentView(R.layout.mainscreen);

public void setTheme (int resid) Since: API Level 1

Set the base theme for this context. Note that this should be called before any views are instantiated in the Context (for example before calling setContentView(View) or inflate(int, ViewGroup)).

The API doc reference is here: http://developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int%29

Since the onDraw() method works on already instantiated Views, setTheme will not work. I have no experience with themes myself, but two alternative options I can think are:

  1. call setTheme in onCreate() instead, or
  2. redo setContentView (R.layout.mainscreen); to force reinstantiate all the layout.
Aleadam
  • 40,203
  • 9
  • 86
  • 108
  • 1
    Thanks ! This runs okay, but I do not see what I expected. Just before running your code I run Activity.setTheme(newtheme) but this invalidate() call does not cause the theme to change (e.g. from Dark to Light). Should invalidate() be able to do that ? – MickeyR May 13 '11 at 13:52
  • @MickeyR no, it shouldn't. Check my updated answer. If those two options do not work, the you will need to restart your Activity. – Aleadam May 13 '11 at 14:18
  • Option (1) does work. My app will start with the correct theme, but if I change it whilst running, I have to re-start my app so that onCreate() is called again. – MickeyR May 13 '11 at 14:34
  • Option (2) is the route I wanted to take. So, when the theme is changed whilst running, I wanted onRestart() to do this:- setTheme(getPreferenceTheme()); and setContentView(R.layout.main); But this does not change my theme. I can't get this second option to work...?! – MickeyR May 13 '11 at 14:35
  • I understood that to get option (2) working I need to 're-inflate the view hierarchy'. I've tried different things to achieve this, but I'm not really sure what this means nor how to do this. – MickeyR May 13 '11 at 14:36
  • This works perfectly - worth noting that if you're forcing a redraw from a background thread, this won't do much unless you use `runOnUiThread(Runnable action)`. Works just as effectively in Monodroid, too. – Richard K. Oct 13 '12 at 23:18
  • 1
    Try this workaround for the theming problem: @Override public void onBackPressed() { NavUtils.navigateUpTo(this, new Intent(this, MyNeedToBeRefreshed.class)); } – Krilivye Feb 26 '13 at 20:18
44

Try getWindow().getDecorView().findViewById(android.R.id.content).invalidate();

Ben Weiss
  • 17,182
  • 6
  • 67
  • 87
  • 3
    Thanks ! Same answer I posted above to Aleadam. This invalidate() does not cause the activity theme to refresh which is what I need. – MickeyR May 13 '11 at 13:53
43

Try recreate() it will cause this Activity to be recreated.

AskNilesh
  • 67,701
  • 16
  • 123
  • 163
M.Khouli
  • 3,992
  • 1
  • 23
  • 26
  • 5
    I tried all the options in this thread, and this is the only one that worked with the least undesired side-effects. – swooby Apr 17 '15 at 21:28
  • 2
    What if i need this to do in `onResume` method. This give me infinte loop :/ – Kamil Witkowski Aug 18 '16 at 09:23
  • 1
    Well I don't recommend using it until u really need. You can save some flag in the shared preferences to avoid the infinite loop. – M.Khouli Aug 18 '16 at 10:34
  • this works but I would not recommend using it in real production mode app. I only needed it for debug mode so the side effect of the whole UI refreshing is not critical. – drorsun Feb 18 '18 at 08:20
36

Solution:

Guys I tried all of your Solutions but they did not worked for me, I have to set setVisibility of EditText to VISIBLE and this EditText should be visible then in ScrollView, but I was unable to refresh root view to take effect. I solved my problem, when I need to refresh the view so I changed the ScrollView visibility to GONE and then again set it to VISIBLE to take effect and it worked for me. This is not the exact solution but it only worked.

 private void refreshView(){
    mScrollView.setVisibility(View.GONE);
    mScrollView.setVisibility(View.VISIBLE);
}
Naveed Ahmad
  • 6,627
  • 2
  • 58
  • 83
  • 2
    wow.. I also tried all proposed sollutions but this seems to be the only one working, but it's kind of horrible... – Rik van Velzen May 28 '18 at 13:47
  • 1
    @NaveedAhmad Thank you! After 4 hours of doing all I could, this was the only solution that worked. – Codelicious Apr 05 '20 at 10:29
  • 2
    this solution works because setting visibility calls `requestLayout()` on view. See [docs](https://developer.android.com/reference/android/view/View#requestLayout()). – cici Oct 24 '20 at 21:34
12

Calling invalidate() or postInvalidate() on the root layout apparently does NOT guarantee that children views will be redrawn. In my specific case, my root layout was a TableLayout and had several children of class TableRow and TextView. Calling postInvalidate(), or requestLayout() or even forceLayout() on the root TableLayout object did not cause any TextViews in the layout to be redrawn.

So, what I ended up doing was recursively parsing the layout looking for those TextViews and then calling postInvalidate() on each of those TextView objects.

The code can be found on GitHub: https://github.com/jkincali/Android-LinearLayout-Parser

Mohamad Shiralizadeh
  • 8,329
  • 6
  • 58
  • 93
jkincali
  • 995
  • 1
  • 9
  • 10
9

Otherwise you can try this also-

ViewGroup vg = (ViewGroup) findViewById (R.id.videoTitleTxtView);
 vg.removeAllViews();
 vg.refreshDrawableState();
Datta Kunde
  • 467
  • 6
  • 14
  • 5
    Thanks for this ! But, this removed all the Views I had (TextView, Buttons etc) but did not re-draw them - my screen remained blank... – MickeyR May 13 '11 at 13:54
  • you need to refresh your view right, then you need to call the draw function again. after cleaning the previous view. – Datta Kunde May 16 '11 at 08:50
6

Try this

view.requestLayout();
Milind Chaudhary
  • 1,632
  • 1
  • 17
  • 16
5

Just set your content view in onresume

setContentView(R.layout.yourview) inside onResume..

Example:

@Override
public void onResume(){
super.onResume();
setContentView(R.layout.activity_main); 
postIncomeTotals();
}
Beyond4D
  • 655
  • 1
  • 5
  • 7
Farhan
  • 3,206
  • 14
  • 49
  • 62
4

Try this workaround for the theming problem:

@Override
public void onBackPressed() {
    NavUtils.navigateUpTo(this, new Intent(this,
            MyNeedToBeRefreshed.class));
}
Krilivye
  • 547
  • 4
  • 8
4
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);

This allows you to reload with theme changes and hides the animations.

Codeversed
  • 9,287
  • 3
  • 43
  • 42
3

I was having this problem as well but following Farhan's lead of using setContentView() I did just that. using setContentView() by itself was not enough however. I found that I had to repopulate all of my views with information. To fix this I just pulled all of that code out to another method (I called it build) and in my onCreate method I just call that build. Now whenever my event occurs that I want my activity to "refresh" I just call build, give it the new information (which I pass in as parameters to build) and I have a refreshed activity.

Kenly
  • 24,317
  • 7
  • 44
  • 60
2

This appears to be a known bug.

Ben Williams
  • 6,027
  • 2
  • 30
  • 54
  • setTheme works find when I restart my activity (call finish() and then startActivity()). I just can't get it to refresh the theme without restarting my activity... – MickeyR May 13 '11 at 14:08
0

I don't know if this is safe or not but it worked for me. I kinda ran into this problem myself and tried invalidate() and requestLayout() but to no avail. So I just called my onCreate(null) all over again and it worked. If this is unsafe please do let me know. Hope this helps someone out there.

Cai
  • 5,063
  • 3
  • 18
  • 23
  • You are setting the savedInstanceState to null which could cause unexpected behaviour. For more information: http://stackoverflow.com/questions/15115975/calling-super-oncreate-with-null-parameter – PhilipB Feb 01 '17 at 13:00
0

This is how i used to Refresh my layout

Intent intent = getIntent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);
sivaBE35
  • 1,876
  • 18
  • 23
0

If you are going to create a custom view, make sure it is extending SurfaceView then, you can redraw it with method getHolder().lockCanvas(). Here is an example:

Canvas c = getHolder().lockCanvas();
c.drawText("Text", x, y, paint);
getHolder().unlockCanvasAndPost(c);
mindrex
  • 239
  • 2
  • 2
0

parent.invalidate() won't work without parent.requestLayout(). so, use

parent.invalidate()
container.requestLayout()
waseem
  • 116
  • 1
  • 13
-1

Not sure if it's good approach but I just call this each time:

setContentView(R.layout.mainscreen);
Sam
  • 86,580
  • 20
  • 181
  • 179
Krzysztof Tkacz
  • 488
  • 2
  • 5
  • 15
-13

Just call the activity again itself using the intent. For example to refresh the layout of MainActivity, do like this:

startActivity(new Intent(MainActivity.this, MainActivity.class));
  • 2
    That's ugly! When you do this, you just add a new activity on stack, so, when you press the back button, you gonna back to the same activity. – Daniel Beltrami May 06 '19 at 14:08