I was debugging my App and found while hovering on an ImageView
reference that, it is an AppCompatImageView
instead of an ImageView
. The same happened with a TextView
(with AppCompatTextView
).
While I don't particularly have a problem with this behavior because its AppCompat after all but when inspecting the code of fellow developers, I saw, extends Activity
instead of AppCompatActivity
and I almost marked it as a "bad practice".
On the other hand, while working on vector images, I was using an ImageView
and there was a problem because I hadn't used an AppCompatImageView
and using it was the solution:
ImageView not displaying correctly in the device
This inconsistent behavior has really confused me as to the practices I should follow. Should I just extend from an Activity from now on?
410. An Android support library that enables the use of the ActionBar and Material Design specific implementations such as Toolbar for older devices down to Android v2.
No, you should always use AppCompat. This ensures that your app is already consistent across all API levels and you have access to all new APIs (such as using the Colored buttons, which was only introduced in API 23). Many other libraries, such as the Design Support Library also require use of AppCompat.
Short answer to "Should I just extend from an Activity from now on?" is no, you should keep extending AppCompatActivity
as it provides backwards compatible features to older devices. In the case of AppCompatImageView
:
A ImageView which supports compatible features on older versions of the platform, including:
- Allows dynamic tint of its background via the background tint methods in ViewCompat.
- Allows setting of the background tint using backgroundTint and backgroundTintMode.
- Allows dynamic tint of its image via the image tint methods in ImageViewCompat.
- Allows setting of the image tint using tint and tintMode.
Also, it adds compatibility with vector drawables for older Android versions.
Explanation about the inconsistencies
As it is explained in AppCompatImageView
:
This will automatically be used when you use ImageView in your layouts and the top-level activity / dialog is provided by appcompat.
So, it's not unexpected.
How it works
AppCompatActivity
installs a LayoutInflater.Factory2
to intercept the inflation of certain views. The code of this inflater can be seen in AppCompatViewInflater.java.
The function responsible for creating the Views
is AppCompatViewInflater#createView(View, String, Context, AttributeSet, boolean, boolean, boolean, boolean)
, and as you can see here it checks for simple view names (without the package prefixing it), and creates the AppCompat*
version instead:
public final View createView(View parent, final String name, @NonNull Context context,
@NonNull AttributeSet attrs, boolean inheritContext,
boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) {
final Context originalContext = context;
// ...
View view = null;
// We need to 'inject' our tint aware Views in place of the standard framework versions
switch (name) {
case "TextView":
view = new AppCompatTextView(context, attrs);
break;
case "ImageView":
view = new AppCompatImageView(context, attrs);
break;
case "Button":
view = new AppCompatButton(context, attrs);
break;
case "EditText":
view = new AppCompatEditText(context, attrs);
break;
case "Spinner":
view = new AppCompatSpinner(context, attrs);
break;
case "ImageButton":
view = new AppCompatImageButton(context, attrs);
break;
case "CheckBox":
view = new AppCompatCheckBox(context, attrs);
break;
case "RadioButton":
view = new AppCompatRadioButton(context, attrs);
break;
case "CheckedTextView":
view = new AppCompatCheckedTextView(context, attrs);
break;
case "AutoCompleteTextView":
view = new AppCompatAutoCompleteTextView(context, attrs);
break;
case "MultiAutoCompleteTextView":
view = new AppCompatMultiAutoCompleteTextView(context, attrs);
break;
case "RatingBar":
view = new AppCompatRatingBar(context, attrs);
break;
case "SeekBar":
view = new AppCompatSeekBar(context, attrs);
break;
}
if (view == null && originalContext != context) {
// If the original context does not equal our themed context, then we need to manually
// inflate it using the name so that android:theme takes effect.
view = createViewFromTag(context, name, attrs);
}
// ...
return view;
}
Forcing the usage of non-AppCompat views
So, in order to force the creation of a regular ImageView
(no AppCompatImageView
) while still using AppCompatActivity
you need to specify the complete class name, for example:
<android.widget.ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/test"/>
For more information on how layout inflation works you can see the amazing talk "LayoutInflater: Friend or Foe?" by Chris Jenx, author of Calligraphy.
Should I just extend from an Activity from now on?
No.The difference between a normal component (Activity) or Compat Component (AppCompatActivity) is that Compat components are designed to support the latest UI components in legacy devices . That is it provides backward compatibility , so you will need it if you're supporting a large variety of devices.
While I don't particularly have a problem with this behavior because its AppCompat after all
yes you are right , when using an Image view from inside a AppCompatActivity , a normal image view will be converted as AppCompatImageView.
AppCompatImageView
Follow this link to read more about AppCompatImageView.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With