How to get screen dimensions as pixels in Android

1,197,811

Solution 1

If you want the display dimensions in pixels you can use getSize:

Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;

If you're not in an Activity you can get the default Display via WINDOW_SERVICE:

WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();

If you are in a fragment and want to acomplish this just use Activity.WindowManager (in Xamarin.Android) or getActivity().getWindowManager() (in java).

Before getSize was introduced (in API level 13), you could use the getWidth and getHeight methods that are now deprecated:

Display display = getWindowManager().getDefaultDisplay(); 
int width = display.getWidth();  // deprecated
int height = display.getHeight();  // deprecated

For the use case, you're describing, however, a margin/padding in the layout seems more appropriate.

Another way is: DisplayMetrics

A structure describing general information about a display, such as its size, density, and font scaling. To access the DisplayMetrics members, initialize an object like this:

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

We can use widthPixels to get information for:

"The absolute width of the display in pixels."

Example:

Log.d("ApplicationTagName", "Display width in px is " + metrics.widthPixels);

API level 30 update

final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
 // Gets all excluding insets
 final WindowInsets windowInsets = metrics.getWindowInsets();
 Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
         | WindowInsets.Type.displayCutout());

 int insetsWidth = insets.right + insets.left;
 int insetsHeight = insets.top + insets.bottom;

 // Legacy size that Display#getSize reports
 final Rect bounds = metrics.getBounds();
 final Size legacySize = new Size(bounds.width() - insetsWidth,
         bounds.height() - insetsHeight);

Solution 2

One way is:

Display display = getWindowManager().getDefaultDisplay(); 
int width = display.getWidth();
int height = display.getHeight();

It is deprecated, and you should try the following code instead. The first two lines of code gives you the DisplayMetrics objecs. This objects contains the fields like heightPixels, widthPixels.

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
      
int height = metrics.heightPixels;
int width = metrics.widthPixels;

Api level 30 update

final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
 // Gets all excluding insets
 final WindowInsets windowInsets = metrics.getWindowInsets();
 Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
         | WindowInsets.Type.displayCutout());

 int insetsWidth = insets.right + insets.left;
 int insetsHeight = insets.top + insets.bottom;

 // Legacy size that Display#getSize reports
 final Rect bounds = metrics.getBounds();
 final Size legacySize = new Size(bounds.width() - insetsWidth,
         bounds.height() - insetsHeight);

Solution 3

It may not answer your question, but it could be useful to know (I was looking for it myself when I came to this question) that if you need a View's dimension but your code is being executed when its layout has not been laid out yet (for example in onCreate() ) you can setup a ViewTreeObserver.OnGlobalLayoutListener with View.getViewTreeObserver().addOnGlobalLayoutListener() and put the relevant code that needs the view's dimension there. The listener's callback will be called when the layout will have been laid out.

Solution 4

(2012 answer, may be out of date) If you want to support pre Honeycomb, you will need to put in backward compatibility prior to API 13. Something like:

int measuredWidth = 0;
int measuredHeight = 0;
WindowManager w = getWindowManager();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
    Point size = new Point();
    w.getDefaultDisplay().getSize(size);
    measuredWidth = size.x;
    measuredHeight = size.y;
} else {
    Display d = w.getDefaultDisplay();
    measuredWidth = d.getWidth();
    measuredHeight = d.getHeight();
}

Of course the deprecated methods will eventually be taken out of the the most recent SDKs, but while we still rely on most of our users having Android 2.1, 2.2 and 2.3, this is what we are left with.

Solution 5

I have tried all possible "solutions" unsuccessfully and I noticed that Elliott Hughes' "Dalvik Explorer" app always shows correct dimension on any Android device/OS version. I ended up looking at his open source project that can be found here: https://code.google.com/p/enh/

Here's all the relevant code:

WindowManager w = activity.getWindowManager();
Display d = w.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
d.getMetrics(metrics);
// since SDK_INT = 1;
widthPixels = metrics.widthPixels;
heightPixels = metrics.heightPixels;
try {
    // used when 17 > SDK_INT >= 14; includes window decorations (statusbar bar/menu bar)
    widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);
    heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);
} catch (Exception ignored) {
}
try {
    // used when SDK_INT >= 17; includes window decorations (statusbar bar/menu bar)
    Point realSize = new Point();
    Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
    widthPixels = realSize.x;
    heightPixels = realSize.y;
} catch (Exception ignored) {
}

EDIT: slightly improved version (avoid firing exceptions on non-supported OS version):

WindowManager w = activity.getWindowManager();
Display d = w.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
d.getMetrics(metrics);
// since SDK_INT = 1;
widthPixels = metrics.widthPixels;
heightPixels = metrics.heightPixels;
// includes window decorations (statusbar bar/menu bar)
if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17)
try {
    widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);
    heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);
} catch (Exception ignored) {
}
// includes window decorations (statusbar bar/menu bar)
if (Build.VERSION.SDK_INT >= 17)
try {
    Point realSize = new Point();
    Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
    widthPixels = realSize.x;
    heightPixels = realSize.y;
} catch (Exception ignored) {
}
Share:
1,197,811
Niko Gamulin
Author by

Niko Gamulin

Engineer/Researcher, working in the field of Machine Learning.

Updated on March 15, 2022

Comments

  • Niko Gamulin
    Niko Gamulin about 2 years

    I created some custom elements, and I want to programmatically place them to the upper right corner (n pixels from the top edge and m pixels from the right edge). Therefore I need to get the screen width and screen height and then set position:

    int px = screenWidth - m;
    int py = screenHeight - n;
    

    How do I get screenWidth and screenHeight in the main Activity?

    • Zar E Ahmer
      Zar E Ahmer about 10 years
      Use dp instead of px. because it will distort your layout with other devices..
    • jmaculate
      jmaculate almost 10 years
      Don't forget to multiply by getResources().getDisplayMetrics().density to account for display scaling
    • Armfoot
      Armfoot over 9 years
      This proves the most up-voted answer is not always the best (& lots of people repeat answers for rep). Instead of getSize and deprecated getWidth/getHeight combo (ignoring errors), try Balaji.K's getMetrics. Nik's comment in his answer even explains getDisplayMetrics to consider the system/status bar size. Also you may use density as jmaculate and LoungeKatt explained to have the EXACT value:DisplayMetrics dm = getResources().getDisplayMetrics(); float fwidth = dm.density * dm.widthPixels; Tested in Android v2.2 (API 8) and v4.0 with good results and no errors/warnings.
    • Azahar
      Azahar about 9 years
      DisplayMetrics displaymetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displaymet‌​rics); int height = displaymetrics.heightPixels; int width = displaymetrics.widthPixels;
    • Täg
      Täg over 5 years
      another way to get the DisplayMetrics : Resources.getSystem().getDisplayMetrics(). You won't need a Context to get them.
  • gcb
    gcb over 13 years
    This is actually how the documentation tells you to do it... but it's kinda pointless if you are NOT using a view. you may be using something else, e.g. mglsurfaceview.
  • Dori
    Dori about 13 years
    this is better as the parent view may not be the size of the display. But make sure that this is done at a point where the view you are querying the size of has already been layed out, which will not usually be inside onCreate(). You can use a custom callback from onWindowFocusChanged(boolean hasFocus) which will be called after all the views have been measured and so on, ensuring you will not receive incorrect dimensions for the view you are interested it...
  • Abhishek Susarla
    Abhishek Susarla about 13 years
    No way u can do it in the XML?
  • MR Mido
    MR Mido almost 13 years
    @ Abhishek Susarla : XML usage is general used in a static way you should expect anything to be done dynamically, hope this helps you figure out ur problem.
  • ajacian81
    ajacian81 over 12 years
    well explained MR Mido. A lot of people who are new to Android don't understand the purpose of the XML files.
  • Tony Chan
    Tony Chan over 12 years
    Note that the metrics (width, height) change depending on the rotation of the device.
  • Guy
    Guy over 12 years
    Metrics will return the size of the display, but HoneyComb and up, your activity will have less space than what's returned due to the system bar.
  • Josef Pfleger
    Josef Pfleger over 12 years
    Thanks @jcfrei ! - I refactored the answer appropriately.
  • pzulw
    pzulw over 12 years
    If you use display.getWidth() be sure to set your minSdkVersion to at least 4 in AndroidManifest.xml or you will get incorrect results on some devices.
  • Someone Somewhere
    Someone Somewhere over 12 years
    Interesting discovery: in the emulator (Android 8) I've specified "Abstracted LCD density" as 150, but when I look at DisplayMetrics.densityDpi it shows 160.
  • Hagai L
    Hagai L about 12 years
    @Guy it depends on your implementation. You can hide the status bar: requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLS‌​CREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
  • Carol
    Carol about 12 years
    getWidth() or getSize()? What would I use if I need my app to run on API <13 as well as API >13?
  • Arnaud
    Arnaud about 12 years
    try { display.getSize(size); width = size.x; height = size.y; } catch (NoSuchMethodError e) { width = display.getWidth(); height = display.getHeight(); }
  • Nik
    Nik almost 12 years
    Also exists this way: getContext().getResources().getDisplayMetrics().widthPixels
  • Norbert
    Norbert almost 12 years
    Cool but the is one scary thing about this method in the sourcecode: this comment
  • ArtOfWarfare
    ArtOfWarfare over 11 years
    @Arnaud Wouldn't it be a better idea to flip flop the try and catch until getWidth() and getHeight() are actually removed from the SDK? It seems to me your code will end up slowing down devices running API < 13 while giving no speed boost for devices running API >= 13? (BTW Carol, your comment is missing the case API == 13.)
  • Arnaud
    Arnaud over 11 years
    Good point! I'd bet the majority of devices running API>=13 would less suffer of this than devices running API<13 in terms of performance. Also this would still work until the getWidth is really removed and not just deprecated. Any Android guy to confirm this?
  • Patrik
    Patrik over 11 years
    I don't see why you want to use try/catch for such a check? Why not simply use if (android.os.Build.VERSION.SDK_INT >= 13) without any thrown exception at all? I think of try/catch in a normal app-flow as bad practice.
  • A-Live
    A-Live over 11 years
    @CipherCom at least because it might become deprecated as well.
  • Patrik
    Patrik over 11 years
    @A-Live then the app would break as well (but not crashing). We developers must pre-check a new os version nevertheless and this maybe just conceal a problem. Also with this argument one could/should surround every few code lines with try/catch, which in my opinion is bad practice as mentioned already.
  • A-Live
    A-Live over 11 years
    @CipherCom as a developer, you must understand the difference of the general and device dependent code, the latter is always better to use with try/catch at Android world in my opinion. And by try/catch I don't mean spamming exceptions at log but preparing a fallback functionality like using default values.
  • Parth Mehrotra
    Parth Mehrotra about 11 years
    @Josef How do the software buttons affect these methods?
  • WildBill
    WildBill about 11 years
    what is 'ctx' in the above code? Is that a reference to something not defined in the code snippet?
  • tom_mai78101
    tom_mai78101 about 11 years
    @WildBill ctx is a Context variable.
  • android developer
    android developer about 11 years
    what if you want to get the screen size excluding the navigation bar and/or notification bar
  • Steve Waring
    Steve Waring about 11 years
    Obviously, you can also pass back the height in the bundle too.
  • Andy Cochrane
    Andy Cochrane almost 11 years
    This is the only post here that takes into account the window decorations (statusbar/menu bar). worked great for me.
  • Erik B
    Erik B almost 11 years
    Awesome, however you should never have expected business logic fire exceptions. Exception firing(even when caught) is horrible for performance. Plus you are doing more work than needed if the SDK_INT is > 13. Instead, you should just add some ifs on the Build.VERSION.SDK_INT.
  • Dragan Marjanović
    Dragan Marjanović almost 11 years
    @Erik B, I agree. I added improved version. Still I left the part "since SDK 1" just in case something goes wrong in try/catch (I've seen many bad things in Android especially when you think it's impossible something to go wrong so I like to keep it safe :)). Anyway there shouldn't be too mouch overhead since this calculation should be done only once (e.g. values could be kept in some static attributes).
  • TalkLittle
    TalkLittle almost 11 years
    Note that this code is licensed under GPL v3 which has implications for using in production apps.
  • Lukas Hanacek
    Lukas Hanacek over 10 years
    or just write view.post
  • Steven L
    Steven L over 10 years
    It's not subtracting space for on-screen controls (such as on Tablets or Nexus devices). Also, I get a different value (750 vs 800) on my 10" Tablet, depending on whether the Activity is active when the calculation is done. But for my purposes, this is more than fine. Thank you!
  • Adil Malik
    Adil Malik over 10 years
    You need to add @SuppressLint("NewApi") just above the function signature in order to be able to compile.
  • Abandoned Cart
    Abandoned Cart over 10 years
    final float scale = getResources().getDisplayMetrics().density; int width = (int) (metrics.widthPixels * scale + 0.5f); - You have to account for device density when doing it that way.
  • marsbear
    marsbear over 10 years
    view.post is not guaranteed to work though. It is just a workaround.
  • Tony Chan
    Tony Chan about 10 years
    @marsbear where does it say View.post() isn't guaranteed to work? I'm curious because I also rely on this method for getting a View's size after layout and was unaware it unreliable.
  • marsbear
    marsbear about 10 years
    @Turbo I say that :p We used that workaround before and it turned out to be unreliable. That workaround is based on the assumption, that the initially layouting is done within the same UIThread turn as the initialization. Hence you could schedule your code to run before the next UI turn via post() and be fine. It turned out that the layouting might take even longer under certain circumstances and the view was still not layouted when the posted code ran. What I do now is add the ViewTreeObserver in onCreate and remove it after the first onLayout. Init your stuff during that first onLayout.
  • Eric Platon
    Eric Platon about 10 years
    If this answer gets you wrong screen sizes, see this related question for an extra necessary step.
  • Tony Chan
    Tony Chan about 10 years
    @marsbear does it matter which View you get the ViewTreeObserver from? Or do they all share the same one?
  • marsbear
    marsbear about 10 years
    @Turbo They should all share the same but the instance you get from getViewTreeObserver might not be valid forever hence you have to check if it is still alive (isAlive()). What I currently do is: getWindow().getDecorView().addOnLayoutChangeListener(). During the first call of the listener I remove it again and call a method in my BaseActivity: afterFirstLayout(). That's where we do calculations that need an initial complete layout cycle
  • Tony Chan
    Tony Chan about 10 years
    @marsbear and this method you use always executes at the right time even with the situation you describe about certain views not finishing their layout when View.post() finally executes?
  • marsbear
    marsbear about 10 years
    @Turbo so far: yes. But with all the different custom Androids out there it might fail one day :) The most secure way is to do your work in onLayout within your own View class but that is not always feasible if you want to 'just' put a view off the screen in onCreate for animation purposes.
  • milosmns
    milosmns over 9 years
    @androiddeveloper Navigation, notification and action bars are always the same height, dependent on the system. Check out Android docs to see how many y-pixels
  • android developer
    android developer over 9 years
    @milosmns They aren't always being visible. it depends on the device - some tablets have the navigation bar with the notifications inside it (I think on Honeycomb, maybe even later), and also, some devices don't have a navigation bar at all, since they have real buttons
  • Armfoot
    Armfoot over 9 years
    @LoungeKatt why do you add 0.5f? Multiplying by scale gives me the right value, adding that 0.5f gets me (e.g.) 800.5...
  • jww
    jww over 9 years
    This crashes on a emulator running Android 4.0 (API 14).
  • auracool
    auracool over 9 years
    This should be the accepted answer as it is Platform independent.
  • Abandoned Cart
    Abandoned Cart over 9 years
    @Armfoot to sway rounding without a lot of excess code.
  • Muzikant
    Muzikant over 9 years
    To handle API Level correctly (Pre/Post API 13) use this code: Point windowSize = new Point(); Display defaultDisplay = getActivity().getWindowManager().getDefaultDisplay(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { defaultDisplay.getSize(windowSize); } else { windowSize.x = defaultDisplay.getWidth(); windowSize.y = defaultDisplay.getHeight(); }
  • Sam
    Sam about 9 years
    I think it's better to get the height and width in one go rather than in separate calls to the APIs because otherwise they could be out of sync. This could happen if the screen orientation is changing while your code is running.
  • digiphd
    digiphd almost 9 years
    Yeah, this was back in 2012.
  • sudocoder
    sudocoder almost 9 years
    sorry, allow me to clarify what I meant. It is highly unlikely that anyone would support API <14 as of 6/22/2015
  • Michel
    Michel over 8 years
    Just what i needed! getResources().getDisplayMetrics().heightPixels + result gives actual fullscreen height. Dragan Marjanović's answer also works but I prefer this much shorter and simpler solution.
  • Michel
    Michel over 8 years
    GPL and depending on reflection to call methods which might not be present in future Android versions. Mhhh
  • Jan Heinrich Reimer
    Jan Heinrich Reimer over 8 years
    This approach is outdated as of Android Marshmallow. Status bar height can change from device or Android version. Better use OnApplyWindowInsetsListener.
  • santaclos
    santaclos about 8 years
    Use getDefaultDisplay().getRealMetrics(metrics) in order to include screen buttons
  • worked
    worked about 8 years
    getActivity().getResources().getDisplayMetrics().widthPixels‌​; from within a fragment.
  • Paul Woitaschek
    Paul Woitaschek almost 7 years
    You should use the WindowManager form activity.getWindwoManager(). Else when entering multi window, you will receive the size of your app in full width mode.
  • android developer
    android developer over 6 years
    Why reflection, if the function is actually available for API 17 : developer.android.com/reference/android/view/… ? Anyway, this doesn't take into account the current orientation, so it will switch according to it. Here's a solution that will work the same no matter is the orientation: stackoverflow.com/a/47684256/878126 . However, the question of the thread is about the normal sizes, so it doesn't need the real resolution. Just the part that can be used.
  • forlayo
    forlayo about 5 years
    If using getRealMetricts() you're going to get the full size with windows decorations and these things; just in case someone is wondering how to do this without reflection.
  • Sourav Bagchi
    Sourav Bagchi almost 4 years
    Is there any support library for backward compatibility?
  • Krishna Meena
    Krishna Meena almost 4 years
    I think no you will have to use earlier method for API level below 30 and this new method for API level 30 and above
  • Federico Navarrete
    Federico Navarrete over 2 years
    This seems to be deprecated.