1 Introduction
2 Background: Android and its Presentation Layer
- Activities represent a screen in the app, which the end-user sees and interacts with.
- Fragments represent parts of an Activity and should indicate their corresponding layout feature. Fragments are used inside Activities.
- Adapters are used to populate the UI (User Interface) with collections of data.
- Listeners are Java interfaces that represent user events.
- Layout Resources are XML files used for the development of the UI structure of Android components. The development is done using a hierarchy of Views and ViewGroups. Views are text boxes, buttons, etc., while ViewGroups are a collection of Views with a definition of how these Views should be shown.
- String Resources are XMLs used to define sets of texts for internationalization.
- Style Resources are XMLs used to define styles to be applied in layout XMLs. Their goal is to separate code related to structure from code related to appearance and shape.
- Drawable Resources represent a general concept for a graphic that can be drawn on the screen, including traditional images or specific XML files.
2.1 Developing a Presentation Layer in Android: A Running Example
Activity
, and to override some inherited methods. We highlight the onCreate() method. One of its responsibilities is to configure the user interface. In Listing 1, we illustrate the code for creating an Activity. In line 5, we find the UI configuration, which indicates the layout “main_activity” feature.
3 Related Work
3.1 Traditional Code Smells
3.2 Domain-Specific Code Smells
3.3 Code Smells in Android Apps
4 Research Goals
5 A Catalog of Code Smells (RQ 1)
5.1 Methodology and Questionnaire
5.2 Participants
5.3 Data Analysis
Total of | |||
---|---|---|---|
# | Question | participants | Participants |
Q1 | Good practice / Activities | 36 (80%) | P1, P2, P4-P12, P14-P17, P19, P22, |
P23, P25-P32, P34-P37, P39-P43, P45 | |||
Q2 | Bad practice / Activities | 35 (78%) | P2, P4-P11, P14-P17, P19, P22, P23, |
P25-P32, P34-P37, P39-P45 | |||
Q3 | Good practice / Fragments | 33 (73%) | P4-P11, P14-P17, P19, P22, P23, P25- |
P28, P30-P32, P34-P37, P39-P45 | |||
Q4 | Bad practice / Fragments | 31 (69%) | P2, P4-P11, P14, P15, P17, P19, P22, |
P23, P25-P28, P31,P32, P34-P37, P39-P43, P45 | |||
Q5 | Good practice / Adapters | 30 (67%) | P2, P4-P11, P14, P15, P17-P19, P22, P23, |
P26, P28, P29, P31,P32, P34-P37, P39-P43, P45 | |||
Q6 | Bad practice / Adapters | 27 (60%) | P2, P4-P8, P10, P11, P14, P18, P19, P22, P23, P26, |
P28, P31, P34-P37, P39-P45 | |||
Q7 | Good practice / Listeners | 24 (53%) | P2, P4-P6, P8, P9, P11, P14, P22, P23, P26, P28, |
P29, P31, P32, P34, P36, P37, P39-P43, P45 | |||
Q8 | Bad practice / Listeners | 23 (51%) | P2, P4, P5, P8, P9, P11, P14, P19, P22, P23, P26, |
P28, P31, P32, P34, P36, P37, P39-P44 | |||
Q9 | Good practice / Layout | 28 (62%) | P4-P9, P11, P14, P19, P22, P23, P26-P29, P31, |
Resources | P32, P34-P37, P39-P45 | ||
Q10 | Bad practice / Layout | 23 (51%) | P4, P5, P7-P9, P11, P22, P23, P26, P28, P31, P32, |
Resources | P34-P37, P39-P45 | ||
Q11 | Good practice / Styles | 23 (51%) | P4-P9, P11, P18, P22, P23, P26, P28, P31, |
Resources | P32, P34-P37, P39-P43 | ||
Q12 | Bad practice / Styles | 22 (49%) | P4-P8, P11, P18, P22, P23, P26, P28, P31, P32, |
Resources | P34-P37, P39-P43 | ||
Q13 | Good practice / String | 28 (62%) | P4-P6, P8-P11, P14, P18, P22, P23, P26-P29, P31, |
Resources | P32, P34-P37, P39-P45 | ||
Q14 | Bad practice / String | 23 (51%) | P4-P6, P8, P9, P11, P14, P18, P22, P23, P26, P28, |
Resources | P31, P32, P34-P37, P40-P43, P45 | ||
Q15 | Good practice / Drawable | 24 (53%) | P4-P6, P8-P11, P14, P18, P22, P23, P26, P28, |
Resources | P31, P32, P34-P37, P39-P43 | ||
Q16 | Bad practice / Drawable | 21 (47%) | P4-P6, P8, P11, P14, P18, P22, P23, P26, P28, |
Resources | P31, P32, P34, P36, P37, P40-P44 | ||
Q17 | Other good practices | 22 (49%) | P2, P4, P8, P10, P11, P14, P18, P22, P23, P26, |
P28, P31, P32, P34, P36, P37, P39-P43, P45 | |||
Q18 | Other bad practices | 20 (44%) | P2, P4, P8, P10, P11, P18, P22, P23, P28, P31, |
P32, P34, P36, P37, P40-P45 |
5.4 Results
Name | Summary | |
---|---|---|
Component | Brain UI Component | UI components with business logic. |
smells | Coupled UI Component | UI components with concrete references to |
each other. | ||
Suspicious Behavior | Listener being implemented within an UI | |
component. | ||
Fool Adapter | Adapters that do not use the ViewHolder | |
pattern. | ||
Absence of an Architecture | Presentation layer without a known/clear | |
architecture. | ||
Excessive Use of Fragments | Use of fragments without an explicit need. | |
UI Component Doing I/O | UI components making access to I/O, e.g., | |
database. | ||
No Use of Fragments | The lack of Fragment s prevents UI with | |
behavior reuse. | ||
Flex Adapter | Adapters with any (business or view) logic. | |
Resource | No Naming Pattern | No naming pattern in Resources. |
smells | Magic Resource | Strings, numbers, or colors hardcoded. |
Deep Nested Layout | Layout resources with deep levels of nested | |
Views. | ||
Unnecessary Image | Images that could be transformed into a | |
graphic resource. | ||
Long or Repeated Layout | Layout resources that are too long or with | |
duplicated code snippets. | ||
Missing Image | Image without all standard resolutions. | |
God Style Resource | Long Style resources that contain too much | |
data. | ||
God String Resource | String resource without a clear naming | |
pattern. | ||
Duplicate Style Attributes | Repeated attributes in layout or style | |
resources. | ||
Inappropriate String Reuse | Strings being reused improperly within | |
resources. | ||
Hidden Listener | Listeners being configured inside of layout | |
resources. |
Code smell | Qty of codes | # of Participants |
---|---|---|
Brain UI Component | 60 | 21 (P2, P6-7, P9, P10-11, P16-17, |
P19, P23, P25, P27-28, P31, P34- | ||
37, P39-41) | ||
Coupled UI Component | 18 | 13 (P2, P4, P6, P10, P19, P23, |
P31, P36-37, P40, P44-45) | ||
Suspicious Behavior | 18 | 11 (P4, P6, P8-10, P32, P34, P37, |
P42-44) | ||
Fool Adapter | 13 | 12 (P4, P6-8, P11, P17, P31, P35- |
36, P39, P43, P45) | ||
Absence of an Architecture | 13 | 10 (P1, P4, P8, P12, P15, P26, |
P28, P31, P42, P45) | ||
Excessive Use of Fragments | 9 | 7 (P2, P4, P7, P11, P30, P39, P41) |
UI Component Doing I/O | 9 | 4 (P2, P26, P37, P41) |
No Use of Fragments | 8 | 7 (P9-10, P31, P14, P19, P34, P45) |
Flex Adapter | 6 | 6 (P2, P7, P23, P39, P40, P41) |
No Naming Pattern | 23 | 10 (P4, P6, P8, P11, P27, P29, |
P34, P37, P39, P43) | ||
Magic Resource | 23 | 14 (P14, P23, P26, P27, P29, P31- |
32, P34-36, P41, P43-45) | ||
Deep Nested Layout | 21 | 15 (P2, P4, P6-8, P14, P19, P26, |
P36-37, P39-41, P44-45) | ||
Unnecessary Image | 18 | 13 (P6, P8-9, P11, P14, P23, P28, |
P35-37, P40-42) | ||
Long or Repeated Layout | 15 | 13 (P4, P6, P7, P9, P23, P26, P28, |
P32, P34, P36, P40-42) | ||
Missing Image | 12 | 10 (P4, P8, P10, P11, P31, P34, |
P36, P40, P42, P44) | ||
God Style Resource | 8 | 5 (P7-8, P28, P40, P42) |
God String Resource | 8 | 6 (P8, P26, P28, P32, P41, P42) |
Duplicate Style Attributes | 8 | 8 (P4, P8, P28, P32, P34, P39-41) |
Inappropriate String Reuse | 6 | 5 (P4, P6, P9, P32, P40) |
Hidden Listener | 5 | 3 (P34, P39, P41) |
6 Importance and Frequency of the Code Smells (RQ 2)
6.1 Methodology and Survey
6.2 Participants
6.3 Results
Code smell | Importance | Frequency | ||||
---|---|---|---|---|---|---|
Median | Mode | Std | Median | Mode | Std | |
Dev | dev | |||||
Brain UI Component | 5 | 5 | 1.05 | 3 | 4 | 1.19 |
Magic Resource | 4 | 5 | 1.00 | 3 | 4 | 1.24 |
Unnecessary Image | 4 | 5 | 0.95 | 3 | 4 | 1.23 |
Long or Repeated Layout | 4 | 5 | 0.95 | 4 | 4 | 1.07 |
Missing Image | 5 | 5 | 0.95 | 3 | 4 | 1.25 |
Coupled UI Component | 4 | 5 | 1.02 | 3 | 3 | 1.15 |
UI Component Doing I/O | 5 | 5 | 1.03 | 3 | 3 | 1.29 |
Absence of an Architecture | 5 | 5 | 0.82 | 3 | 3 | 1.30 |
Flex Adapter | 4 | 5 | 0.91 | 3 | 3 | 1.15 |
No Naming Pattern | 5 | 5 | 0.88 | 3 | 3 | 1.24 |
Fool Adapter | 5 | 5 | 0.93 | 2 | 2 | 1.20 |
Hidden Listener | 4 | 5 | 1.23 | 2 | 2 | 1.29 |
God Style Resource | 4 | 4 | 1.06 | 4 | 5 | 1.18 |
God String Resource | 3 | 4 | 1.22 | 4 | 5 | 1.18 |
Suspicious Behavior | 3 | 4 | 1.19 | 3 | 4 | 1.19 |
Deep Nested Layout | 4 | 4 | 1.12 | 4 | 4 | 1.06 |
Long or Repeated Layout | 4 | 4 | 0.86 | 4 | 4 | 1.11 |
No Use of Fragments | 3 | 4 | 1.34 | 3 | 2 | 1.21 |
Inappropriate String Reuse | 3 | 3 | 1.29 | 4 | 4 | 1.12 |
Excessive Use of Fragments | 3 | 3 | 1.36 | 3 | 3 | 1.17 |
Average SD | 1.05 | 1.19 |
7 Prevalence of the Code Smells (RQ 3)
7.1 Code Smell Detection Strategies
7.1.1 Detection Strategies for the Component-Related Smells
Fragments
, Adapters
, and Listeners
, to be reused, should not have direct reference to who uses them. The detection strategy is as follows: we collect all Fragments
, Adapters
, and Activities
of the app. For each component, we check whether any of its fields is a direct reference to another Activity
or Fragment
. If so, we mark the component as smelly. Algorithm 1 depicts this detection strategy.
Activities
, Fragments
, and Adapters
should not be responsible for implementing event behavior. The detection strategy is as follows: we collect all Fragments
, Adapters
, and Activities
of the app. For each component, we verify whether it contains either an (i) inner class or (ii) an anonymous class (as inner and anonymous classes are how developers often implement event behavior). If a component possesses any of them, we mark it as smelly. Algorithm 2 presents this detection strategy.
Activities
, Fragments
, Adapters
, and Listeners
should only contain code responsible for presenting, interacting, and updating the UI. The detection strategy is as follows: we collect all Fragments
, Adapters
, and Activities
of the app. For each component, we measure its (McCabe) code complexity and identify whether it makes use of I/O operations, database access, or static fields. We use this heuristic as a proxy for business rules, as there is no clear and unambiguous way of deciding whether a piece of code has business logic. Algorithm 3 presents this detection strategy. Please note that α and β are thresholds and we describe how we calculate them in the next section.
Adapters
should be responsible for populating a view from a single object. The detection strategy is as follows: for each Adapter
in the app, we verify whether its complexity is below a specific threshold. We use complexity as a proxy, as highly complex Adapters
often deal with more than one object. Algorithm 4 presents this detection strategy.
Adapters
should use the View Holder pattern to reuse instances of the views that represent the fields that will be populated for each item of a collection. The detection strategy is as follows: for each Adapter (or any of its children, e.g., BaseAdapter
, ArrayAdapter
, and CursorAdapter
), we detect whether there is a call to findViewById()
inside its getView()
method. If so, we mark the class as smelly. Algorithm 5 illustrates this detection strategy.
Activities
, Fragments
, and Adapters
should not perform I/O operations, such as database and file access. The detection strategy is as follows: for each Activity
, Fragment
, and Adapter
, we check whether they make any call to I/O, database, or internet request APIs. We created the dataset of APIs by scraping the Android manual. Algorithm 6 depicts this detection strategy.
Fragments
are often used to accomplish this task. Thus, the non-use of Fragments
can represent a highly coupled UI. In practice, we can observe this smell when view components, e.g., EditTexts
, Spinners
, and TextViews
, are directly used by an Activity
, instead of small Fragments
. The detection strategy is similar to what we described above: for each Activity
of the app, we check whether it contains any view component (e.g., EditTexts
, TextViews
, Spinners
, etc.). If so, we mark the component as smelly. This detection strategy is depicted in Algorithm 7.
Fragments
is important for UI decoupling, these components should not be used without an explicit need. To automate the identification of this smell, we count the number of Fragments
in an app. If the number is higher than a pre-defined threshold, we mark the app as smelly. We define the threshold later in this paper. In Algorithm 8, we present the detection strategy, where α represents the threshold.
7.1.2 Detection Strategies for the Resource-Related Smells
onClick
,” directly in layout files. We detect this smell by searching for the usage of android:onClick
in any layout resource file (i.e., any XML file inside the “res/layout
” folder of the app). Algorithm 12 depicts this detection strategy.
android:text
and android:textColor
). If the marker has a hard-coded text or color (rather than referencing a resource file), we mark the resource as smelly. Algorithm 13 depicts this detection strategy.
Activities
and string resources (i.e., resource files that contain the string
element in the res/values
folder of the app). If they are different, we mark the app as smelly. Algorithm 14 depicts the detection strategy applied to this smell.
.png
, .jpg
, or .git
images. We detect this smell by checking whether all images of the app exist in all resolutions (i.e., that the same images exist in res/folders-hdmi
, res/folders-xhdpi
, res/folders-xxhdpi
, and res/folders-xxxhdpi
folders). We also verify whether the file sizes differ from each other. Algorithm 15 depicts this detection strategy.
7.2 Sample Dataset
Java
files and number of *.XML
files), and number of contributors, stars, forks, and issues of the selected repositories. For each metric, we report median, trimmed mean, median absolute deviation (MAD), and standard deviation (SD). On average, the apps have around 3,759 lines of java code and 1,363 lines of XML code. Most of the apps have up to 5 KLoC: 395 apps, which accounts for 59.6% of our sample. Approximately 40% of the analyzed apps have more than 5 KLoC (268 projects).
Overview of the selected mobile apps | ||||||||
---|---|---|---|---|---|---|---|---|
Line of Code | GitHub’s Metrics | |||||||
Java | XML | LI‡ | #CO | COn | ST | FO | IS | |
Max | 180,407 | 154,582 | 3,340 | 45,920 | 295 | 17,578 | 7,246 | 7,341 |
Min | 65 | 40 | 52 | 2 | 0 | 0 | 0 | 0 |
Trimmed mean | 5772.75 | 6009.73 | 1725.7 | 262.6 | 5.0 | 64.0 | 28.1 | 48.7 |
Median | 3759 | 1362 | 1786 | 129 | 3 | 32 | 15 | 22 |
Std Dev | 20910.95 | 24423.89 | 723.4 | 2390.4 | 21.2 | 854.5 | 379.5 | 579.8 |
MAD† | 4477.45 | 1622.70 | 668.6 | 163.1 | 2.9 | 40.0 | 19.2 | 29.6 |
Project | Java Files/LOC | XML Files/LOC | Category | |
---|---|---|---|---|
Largest | OsmAnd | 614/175,902 | 861/154,582 | Maps |
GreenBits Wallet | 602/180,407 | 93/7,290 | Finance | |
Open Explorer | 929/130,231 | 50/4,500 | Productivity | |
Smallest | IcsImport | 1/65 | 3/44 | Productivity |
FlashLight | 2/77 | 3/40 | Tools | |
BMI Calculator | 1/93 | 23/273 | Health |
7.3 Threshold Tuning
Smell | Threshold |
---|---|
God Style Resource | α = 11 |
Deep Nested Layout | α = 4 |
Excessive Use of Fragments | α = 10 |
Brain UI Component | α = 56 and β = 9 |
Flex Adapter | α = 56 |
7.4 Accuracy of the Detection Strategies
- Group 1 (Decidable): Some of our smells can be detected via decidable, unambiguous, rules. In our case, the smells No Use of Fragments, Duplicate Style Attributes, Hidden Listener, Magic Resource, God String Resource, and Missing Image can be detected via straightforward static analysis. For example, in the case of No Use of Fragments, our tool detects whether Fragments are present or not in the system.
- Group 2 (Decidable, threshold-based): Some smells can also be detected via decidable rules, but they depend on a threshold. This is the case for the God Style Resource, Deep Nested Layout, and Excessive Use of Fragments smells.
- Group 3 (Heuristic-based): Other smells do not have decidable rules and require a heuristic (i.e., an approximation) for the detection. This is the case for Brain UI Component, Coupled UI Component, Suspicious Behavior, Flex Adapter, Fool Adapter, and UI Component Doing I/O.
View
class as a parameter to another method, and then invoke the findViewById()
method (used in the detection strategy). Future work should systematically explore all the ways a developer might make use of the findViewById()
method, with the goal of refining the parsing strategy.Smell | Precision | Recall | F1 | TP | TN | FP | FN |
---|---|---|---|---|---|---|---|
Brain UI Component | 0.91 | 0.94 | 0.93 | 93 | 360 | 9 | 5 |
Coupled UI Component | 0.84 | 0.68 | 0.75 | 32 | 414 | 6 | 15 |
Suspicious Behavior | 0.57 | 0.95 | 0.71 | 65 | 350 | 49 | 3 |
Flex Adapter | 0.76 | 1.00 | 0.86 | 30 | 428 | 9 | 0 |
Fool Adapter | 1.00 | 0.26 | 0.42 | 4 | 452 | 0 | 11 |
UI Component Doing I/O | 0.94 | 0.6 | 0.73 | 18 | 436 | 1 | 12 |
7.5 Results
Smell | # of Java/XML files | % |
---|---|---|
Components | ||
Suspicious Behavior | 8,584 | ≈ 23% |
Brain UI Component | 6,697 | ≈ 18% |
Coupled UI Component | 1,906 | ≈ 5% |
UI Component Doing I/O | 810 | ≈ 2% |
No Use of Fragments | 292 | ≈ 0.78% |
Fool Adapter | 187 | ≈ 0.50% |
Excessive Use of Fragments | 87 | ≈ 0.23% |
Flex Adapter | 70 | ≈ 0.18% |
Total of affected components | 18,633 | |
Resources | ||
God String Resource | 8,581 | ≈ 26% |
God Style Resource | 8,528 | ≈ 25% |
Deep Nested Layout | 7,856 | ≈ 23% |
Magic Resource | 1,093 | ≈ 3% |
Duplicate Style Attributes | 208 | ≈ 0.63% |
Hidden Listener | 195 | ≈ 0.59% |
Missing Image | 48 | ≈ 0.14% |
Total of affected resources | 26,509 |
BUIC | UIC | SB | CUC | FAd | FA | |
---|---|---|---|---|---|---|
1st Qu. | 1 | 0 | 2 | 0 | 0 | 0 |
Median | 4 | 0 | 5 | 0 | 0 | 0 |
Mean | 11 | 1 | 14 | 3 | 0.3 | 0.11 |
3rd Qu. | 12 | 1 | 14 | 2 | 0 | 0 |
Max. | 153 | 33 | 279 | 78 | 11 | 6 |
DNL | DSA | GStR | HL | MR | GSR | |
---|---|---|---|---|---|---|
1st Qu. | 2 | 0 | 2 | 0 | 0 | 1 |
Median | 5 | 0 | 4 | 0 | 0 | 2 |
Mean | 13 | 0.33 | 14 | 0.31 | 2 | 14 |
3rd Qu. | 15 | 0 | 10 | 0 | 2 | 9 |
Max. | 219 | 13 | 446 | 11 | 48 | 454 |
8 Discussion
- Two security smells from Ghafari et al.’s catalog are related to the presentation layer of Android apps. More specifically, Broken WebView’s Sandbox, which is relevant to developers rendering web content in an unsafe manner, and SQL Injection, which commonly happens when user input goes straight to an SQL query. This result shows that issues in the presentation layer can also lead to security flaws. Therefore, as future work, we suggest researchers study the relationship between the presentation layer code smells and security vulnerabilities.
- Palomba et al. (2017)’s code smells catalog does not touch on any presentation layer code smells, and thus, our catalog is complementary to it. However, UI developers should be aware of the Leaking Thread code smell proposed in their catalog, as most of what happens in presentation layers occurs in threads (we discuss the life cycle of the components in Section 2).
- Linares-Vásquez et al. (2014) showed that UI-related APIs (GUI and image manipulation) represent around 40% of the energy greedy APIs in the Android platform. As actionable advice, authors suggest developers carefully design apps that make use of several views and to avoid refreshing views. We see their results as a complementary to ours. Our catalogue has several smells related to complex UIs (i.e., Brain UI Component, UI Component Doing I/O, Deep Nested Layout, and Unnecessary Image). Besides being harmful for maintenance, we conjecture that these smells also impact energy consumption, and therefore suggest developers consider not only the maintenance cost but also the energy costs of classes affected by these smells.
- While performance studies by Hecht et al. (2016), Linares-Vásquez et al. (2017) and Liu et al. (2014) lacked focus on the presentation layer, our smells can be related to performance issues. Linares-Vásquez et al.’s study, in particular, showed that unused strings (and other resources) can be costly to mobile apps. Our catalog indeed has smells related to how developers organize their resources in their software (i.e., God String Resource, Inappropriate String Reuse, Duplicate Style Attributes, God Style Resource, Long or Repeated Layout, Deep Nested Layout). Thus, we suggest developers also consider elements affected by resource-related smells as candidates for performance improvements. In future work, we suggest researchers investigate the relationship between our smells and performance issues.
- Companies and independent developers have been working on guides and best practices catalogs that go beyond “traditional smells,” such as Google’s Jetpack Best Practices (Google 2018a, 2018b) and Futurice, a software house which hosts a GitHub repository on Android best practices with around 17,000 stars (Futurice 2018). Our catalog complements this effort.
- In our research, we focused on smells related to the presentation layer of Android apps. Nevertheless, we noticed that many of our participants often mentioned “traditional” smells, such as Long Methods and God Classes (Lanza and Marinescu 2007; Fowler and Beck 1999) as problems they also face in this layer. As we show in the Related Work section, researchers have also investigated the role of traditional smells in Android apps. Therefore, when developing the presentation layer, we recommend developers be aware of both traditional and presentation layer-specific smells.
RecyclerView.Adapter
, which appeared in Android 5.1 Lollipop and facilitates the implementation of the ViewHolder pattern. Before that, developers had to implement the pattern themselves, which required previous knowledge about best practices. We hope that our results can inspire new tools, strategies, and modifications to the underlying technology to make the mitigation strategies easier to implement.