Thursday, June 17, 2010

Using Themes in Android Applications

As a developer, I understand how developers think when going about creating an application.  We start with an idea, with an end goal in mind, and start putting together pieces from the bottom-up until we reach our goal.  Like any engineer, we enjoy playing with the individual parts, tinkering with building blocks, until we have put them together to create something fantastic that works.  As much fun as this may be, experience shows that throwing together these building blocks without using a proper framework to build them is leads to bad designs, and applications which are difficult to maintain and change later on.

When it comes to design, we don't think in the same manner as a more artistically inclined designer would.  We work from the bottom up, and they work from the top down.  They will work with the entire endeavor as a whole, seeing the final product working without bothering with the individual nuances of the sum of its parts.  In their mind, those parts just work; in the engineer's mind, we think of how we can get those parts to work.  I believe this could be said about many types of work involving engineers and artists, like websites and buildings.

If we, the software developer, use too many individual parts to create our app that have been molded on their own, without concern for the other parts they will be fitting into, it is much harder to make them fit in the first place, and especially to later make changes to them. Besides, the less moving parts the better; as a software developer, it is simply good design to create your user interface with building blocks which conform together instead of changing numbers, colors, etc. here and there to force everything to eventually look good.

What I am dealing with here is UI; the graphical representation of your app. More specifically, UI design in Android applications.

Use Styles in UI

In the above screenshots from the sample application, you can see the exact same layout rendered differently by applying different themes.

In Android, you use Views to design your Activities.  An Activity is the central class which handles a specific, well, activity, in your application.  The class which handles the visual representation of activities is View. The Views themselves can be created programmatically within the Activity, but one should only do so in rare circumstances.  The better way to define them is using XML layout files.

The Android SDK for Eclipse gives us a nice visual editor to design views, which directly manipulates the XML for us.  The layout editor does not, unfortunately, give an easy way to customize the look and feel of the application.  By look and feel I mean the colors, the margins, the fonts, and any attributes that contribute to how all of the views display.

Remember in your beginner computer science classes learning about constants, and why you should use them?  One reason was that if you use a constant, you can reuse it in many places, but only have to change it one place.  In the same manner, we should be using constants to define the way our application looks, so we can easily change it from one central place, in order to change the entire application.  (On a side note, if you've ever dealt with creating web pages, you probably have realized that it is far better to use CSS than to change the attributes of individual elements of your HTML pages).

Creating Themes

Finally, onto the real meat of how to use themes!  What I will show you here is how to define a theme in your resources in an XML file, how to define attributes of the theme, how to apply those to your layout files, and finally how to dynamically change the theme of an activity.

Create a file themes.xml in res/values/.  Here you will create the name of your theme, and any customizable attributes you would like for your theme to define.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    
<style name="Theme" parent="android:Theme">
        <item name="android:windowTitleSize">20dip</item>
    
</style>
    
</resources>

Above you see I have created a theme called Theme, whose parent is the default Android theme. There is a custom attribute called pageMargin, and also a default OS attribute android:windowTitleSize which has been overridden. I recommend you set the theme's parent to the default Android OS theme, in order to inherit all of the system attributes. Otherwise, unless you only use your own custom views, the system views such as ListView will be missing attributes which are defined in the system theme which are not defined in your own theme. This will cause funny layout issues at best, but at worst it will cause exceptions due to attributes that the views could not find. Remember, not all Android devices are built the same.

Setting the Theme

We can set the theme of either our application or individual activities in the manifest file.  If you don't need to have more than one theme at all in your application, just set the theme of the activity.  Otherwise, you can define themes specific to an activity.

<application
    
android:icon="@drawable/icon"
    
android:label="@string/app_name"
   
 android:theme="@style/Theme">

You can also set the theme of an activity programmatically.  This is done by calling setTheme() in the activity's onCreate() method, before any call to setContentView().  Note that this approach should typically be avoided, especially from the main activities of your application, because the theme you set here may not be used for any animations the system uses to show the activity (which is done before your activity starts).  The exception to this rule is if you want to set your themes dynamically, such as in the case where the application can have more than one theme.

Custom Attributes

Although it is nice to be able to override the default system properties in some cases, what we'd really like to do is define custom properties of our own in our application's layouts.  Say we wanted the margins of all of our activities to be a certain dimension.  If we define it in one place, we can change it all at once. Below is an example of a custom attribute added to our custom theme in themes.xml which we can use to define a property called pageMargin:

        <item name="pageMargin">2sp</item>

If you simply copy the above text into your new file themes.xml, you will get a build error Error: No resource found that matches the given name: attr 'pageMargin'.  This is because we have not defined what pageMargin is to the build system.  android:windowTitleSize is OK, because it is already defined in the Android SDK.

Create a file called attrs.xml in res/values/.  Here you will create your style attributes, which are any customizable attributes you would like for your theme to define.  Below, I have created a new attribute called pageMargin, which I will use to define margins.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    
<attr name="pageMargin" format="reference|dimension" />
</resources>

Now, the build system will not throw an error anymore because pageMargin is now defined. The format attribute indicates what type of values I can define for pageMargin; in this case, either a reference to another attribute, or a dimension such as 2sp or 4px.  Other examples of possible formats are color, boolean, integer, and float.

Now, I could set the margins in my views by referencing a single constant, instead of putting the same value piecemeal around the code:

<TextView
    
android:layout_width="fill_parent"
    
android:layout_height="wrap_content"
    
android:text="Hello"
    
android:layout_margin="?pageMargin"/>

I can change pageMargin in one place and all of the margins in my views which reference this attribute will be changed.  Unfortunately, this method of defining your view's styles has some issues.  If you open this view in the Eclipse layout editor, you will see an error: Unable to resolve dimension value "?pageMargin" in attribute "layout_margin".  In order to make any use of these attributes, we need to apply the theme to our activities, and this doesn't work in the layout editor.
If you'd like to see some more examples, you can look at the Android OS source code default res directory, in particular themes.xmlstyles.xml, and attrs.xml.

Styles

A more sophisticated method to setting the properties of your views in the layout is give a view a style, which is a group of attributes, instead of defining the values of individual attributes. For example, you could set the styles of all of your title TextViews to have the style textTitle.  This style could have custom text color, font, and margin properties. In addition, the layouts can be safely edited in the Eclipse layout editor, because the style attribute is not needed to render the views.

    <TextView
        
android:layout_width="fill_parent"
        
android:layout_height="wrap_content"
        
android:text="@string/title_text"
        
style="?textTitle"/>

Now this TextView has a custom style. You can assign multiple attributes to the textTitle style, such as android:textColor and android:textSize.

When using the style attribute in your layout files, the views will appear plain when using the Eclipse layout editor.  However, when the theme is applied in your application, your custom styles will be applied.

Dynamic Themes

If you want your application to have a customizable look and feel, then you will want to create multiple styles. An example of this is given in the sample application below. To have multiple themes, you will want to create multiple theme definitions in themes.xml.

    <style name="Theme.White">
      
<item name="textTitle">@style/text_title_wh</item>
      
<item name="textSubheader">@style/text_subheader_wh</item>
    
</style>

    <style name="Theme.Blue">
      
<item name="textTitle">@style/text_title_bl</item>
      
<item name="textSubheader">@style/text_subheader_bl</item>
    
</style>

To set the theme dynamically at runtime, call setTheme() in your activity's onCreate() method, before calling setContentView().  To change the theme, you simply need to restart your activity.
If you have a theme name with a dot in it, such as MyTheme.Blue, then you will create a theme called MyTheme_Blue whose parent is the theme MyTheme. It is a convenient way to inherit the properties of a parent theme.

Sample Application

This sample program shows how to use custom themes. The application has one Activity with one corresponding layout file. Most of the views in the layout have a custom style. You can change the style dynamically by pressing the buttons at the bottom of the screen.

Project Source Code - Themes.zip (16.4 Kb)
Project Package - Themes.apk (28.1 Kb)
Screenshots

Conclusion

1. Define one or more themes in themes.xml and set the definitions of your styles there.
2. Define custom attributes, a.k.a. custom styles, in attrs.xml.
3. Describe what the values of your custom styles are in styles.xml.
4. In your layout files, give your views a style attribute, which has a custom style name as their values.
5. Set the theme of your application or activity in either AndroidManifest.xml or in the Activity's onCreate().

As an Android application programmer you should now know how to stop placing look and feel attributes directly into your layout files and start using styles to design your UI.

130 comments:

  1. Nice but i though you were going to post something on ColorStateList but this clear me some doubts... thanks

    ReplyDelete
  2. Great tutorial, i was waiting for that for months.

    ReplyDelete
  3. @Jose Espinoza

    There are some examples of the ColorStateList in the sample program. See the res/color/ directory. Basically, use the ColorStateList anywhere you'd use a regular color, and the colors will change depending on whether the containing View is focused, pressed, etc.

    ReplyDelete
  4. This is a brilliant tutorial Matt, Thanks

    ReplyDelete
  5. Nice explanation.

    Though I have not tried, but i assume the style overriding works in a similar fashion as web or are there some gotchas?

    ReplyDelete
  6. Extremely useful! Was exactly the use case I was looking at. Julia Child would be proud...

    ReplyDelete
  7. This was an amazing example. Clean, clear and functional! Thank you so much!

    ReplyDelete
  8. Can you help me i want to modify theme for DialogPrefernce used in ListPreference
    want to change radio button images and background of dialog.
    There is attribute defined in attrs.xml

    so how do i find out the theme defined for the dialog?

    ReplyDelete
  9. Great tutorial. Thanks! by the way what do you use to do your syntax highlighting?

    ReplyDelete
  10. @Eric Harlow Actually, it's just Eclipse syntax highlighting. When you copy anything from the Eclipse editor, it copies it in RTF format. Then, I run a script which formats it in Blogger.

    ReplyDelete
  11. this is exactly what i want, but i'm having trouble. the only diff is that i'm trying this with a widget.

    i set the theme at the application level in the manifest, and tried calling Context.setTheme() from the widget's buildUpdate() method. neither has an effect. the view widget just don't see the style="?whatever" styles, although there is no error at design time from eclipse.

    any ideas?

    ReplyDelete
  12. This was by far the most useful tutorial on themes in Android I've found yet. Thank you!

    I was in the middle of implementing themes based off of this when I ran into this problem and was hoping you could shed some light on my situation

    http://stackoverflow.com/questions/4035936/tag-that-references-current-theme-in-xml-causes-force-close

    ReplyDelete
  13. this is good meat on themes for a hungry man like me.

    ReplyDelete
  14. How can one also change the default string with the theme? So, for example, the title bar could say "Blue Theme" or "Gray Theme" when you switch themes. Is it possible to define this in the XML?

    ReplyDelete
  15. Indeed usefull,easy for all developers. thanks

    ReplyDelete
  16. How I do apply a custom theme to whole my android user interface on my phone?

    Sometimes I want black on white instead of white on black

    ReplyDelete
  17. Awesome, thanks a lot it really helps!!!

    ReplyDelete
  18. This a good example. But if the themes are not pre-define in theme.xml, how to implement it. That is to say, the themes are from another apk, not in the main apk. The example is like HCT HD Skin.

    ReplyDelete
  19. Thank u dude.Really very nice example with good explanation

    ReplyDelete
  20. great tutorial!

    i'm having the problem of when i apply style to listView it breaks on onClick events.

    https://groups.google.com/group/android-developers/browse_thread/thread/46bb94300cf4bf75

    any ideas?

    ReplyDelete
  21. Thanks a lot very simple and helpful

    ReplyDelete
  22. Hi,

    thank's for this tutorial.

    Did you try custom style/theme for spinner too ?
    When I modify spinner background (by xml attribute), it works but the selector arrow (on the right of first item when spinner is collapsed) becomes invisible ...
    Same unexpected result with spinnerStyle attribute.

    I am using API level 3 (Android 1.5 target).

    Thank's for any idea.

    ReplyDelete
  23. Thanks for this post! It is very helpful.

    ReplyDelete
  24. Awesome man.. i owe you a beer...

    ReplyDelete
  25. I have been looking for a way to do this for this afternoon.

    Thanks a bunch! That is a life saver!

    Richard L.
    http://android9patch.blogspot.com/

    ReplyDelete
  26. what is your email id , so that i can contact you.

    ReplyDelete
  27. Hi Mat,

    Will you please add Tabwidget style to the Theme.white and Theme.blue. I am using your theme having a listview inside a tabwidget and the colors dont match.

    Thanks

    Raianeh

    ReplyDelete
  28. Hi Matt Quigley !
    Thanks for the tutorial.
    I'm following your tutorial. And here I have two themes in my application. I tried to adapt my application but in the Util class when i put activity.setTheme (R.style ta ... the theme xml on my values ​​does not appear. In your example appears Theme.White and Theme.Blue. You know how to solve this problem ?

    ReplyDelete
  29. hello matt if I have more than one activity how can I change the theme at all?

    ReplyDelete
  30. Thanks for the article!

    Has anyone figured out how to either share themes across apps dynamically or load themes from a website?

    The idea is that other developers could create a module to theme your app.

    ReplyDelete
  31. I love you and want to have your babies. PS. Can I use this in one of my apps?

    ReplyDelete
  32. Best tutorial , i have ever seen..

    ReplyDelete
  33. Great tutorial! It help me a lot. Thank you

    ReplyDelete
  34. Nice tutorial.
    Thanks!

    ReplyDelete
  35. I've sth like this applied to TextView textColor.






    But it's always red instead of my colors. When I set textColor just to ?foreground color changes to foreground correctly. So there is issue with that selector? It doesn't know about references to the actual color?

    ReplyDelete
  36. I've sth like this applied to TextView textColor.
    selector xmlns:android="http://schemas.android.com/apk/res/android">
    item android:state_pressed="true" android:color="?background"/>
    item android:state_focused="true" android:color="?background"/>
    item android:color="?foreground"/>
    /selector>

    But it's always red instead of my colors. When I set textColor just to ?foreground color changes to foreground correctly. So there is issue with that selector? It doesn't know about references to the actual color?

    ReplyDelete
  37. Great information! After implementing into an actual application I noticed the call to "Utils.onActivityCreateSetTheme(this)" would not work correctly if placed after the "super.onCreate(savedInstanceState);" line in my Activity "onCreate" routine. After searching the Internet I discovered placing the line before "super.onCreate(savedInstanceState);" worked fine.

    ReplyDelete
  38. Just as here in the example textview styles are being changed dynamically... Is it possible to use the similar technique with action bar in ICS that too without relaunching the activity..

    ReplyDelete
  39. Hello,i'm so much thankful to the author of this blog...
    Bcoz this thread gave me not only an answer to my search for android design using themes,but also the method for creating and returning the android widgets from a POJO without extending Activity.Thank u a lot...

    ReplyDelete
  40. as I c in your example, pageMargin attribute is not actually used, and I was unable to modify your application to reference it to set, for example, paddings of main layout.

    This causes "java.lang.UnsupportedOperationException: Can't convert to dimension: type=0x2"

    From the other hand, referencing any attribute declared in android package works ok

    I spent lot of time googling for this problem but just found number of unanswered questions like this.

    ReplyDelete
  41. This was by far the most useful tutorial on themes in Android I've found yet. Thank you!

    ReplyDelete
  42. Awesome tutorial .I was Just searching the source codes since long time & thanks a lot for the details and step by step method you have explained here .

    ReplyDelete
  43. Hi there,

    at what API level does this start?

    Cheers

    ReplyDelete
  44. Cool post, I was look for something about Themes for Android App.

    Congratulations, It's works!

    Cheers.

    Marco Maddo
    Brazil
    http://www.4android.com.br

    ReplyDelete
  45. Holy... Man, works like magic! Thanks a lot!

    ReplyDelete
  46. It is useful. I did follow the guideline and I have a perfect setup.
    Thanks

    ReplyDelete
  47. Thanks a lot for such a good post

    ReplyDelete
  48. This is bad example. Instead of code beiing shown on wep page one must download it, unzip and then view it with some tool. Waste of time.
    But I believe it was done with best intensions.

    ReplyDelete
  49. Nice tutorial. In my case, I would like to programmatically create dynamic list populated from database. I am able to create the text view but I can’t reproduce the View. All stuck with java.lang.NullPointerException. The Code I use is :

    View vi = new View(Home.this);
    RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) vi.getLayoutParams();
    params.height = 1;
    vi.setLayoutParams(params);
    linearLayout.addView(vi);

    ReplyDelete
  50. This tutorial is a GOD SEND!! Thank you so much for making it so easy to understand for a designer like myself!! XXXX

    ReplyDelete
  51. Thank you for this useful tutorial.

    ReplyDelete
  52. Nice tutorial.
    In my case, I am creating some layouts dynamically depending on the conditions. So how can I handle theme change in such cases.
    For example, in one of my activity, I am creating the whole layout dynamically, which includes LinearLayout,Button and other widgets. Please suggest me to do this smoothly.
    Thanks

    ReplyDelete
  53. This comment has been removed by the author.

    ReplyDelete
  54. This comment has been removed by the author.

    ReplyDelete
  55. Thank you for this useful tutorial. :D

    ReplyDelete
  56. So, you wrote this almost 4 years ago. What have you learned since then that would make this information better? I'd love to see a deeper dive into the subject, how/why it works, etc.

    ReplyDelete
  57. Great tutorial, Thank you very much!

    ReplyDelete
  58. Great!!!ou
    Very Nice!!!

    you save my life!!!

    ReplyDelete
  59. Hi Matt, your tutorial help me a lot to understand themes & styles :-)
    Many thanks !!!
    @+Mat

    ReplyDelete
  60. At Webnet, we have effect of a force and acclaimed custom android app development affiliation really. Today, we are fulfilled to say that we have shockingly specific fulfilled clients who trust us with their work understanding that all they will get from us is yet the best quality android applications.

    ReplyDelete
  61. Replies
    1. http://gadgetssai.blogspot.com/2017/12/funny-wi-fi-names-for-your-home-router.html

      Delete
  62. Awesome tutorial .I was Just searching the source codes since long time & thanks a lot for the details and step by step method you have explained here ..
    for banking related content you can go through following website
    marksbooster.com

    ReplyDelete
  63. You can use this trippy backgrounds for themes it's free and useful thank you

    ReplyDelete
  64. ایوان باند
    Hey, very nice site. I came across this on Google, and I am stoked that I did. I will definitely be coming back here more often. Wish I could add to the conversation and bring a bit more to the table, but am just taking in as much info as I can at the moment. Thanks for sharing.
    امو باند
    cloud TV app thank you so much for your response
    هوروش باند

    ReplyDelete
  65. Great article! We will be linking to this great article on our website. Keep up the good writing.
    ابزار وبلاگ ابزار وبلاگ ابزار وبلاگ کد ابزار سایت وبلاگ
    ابزار وبلاگ
    http://webcity.ir/

    ReplyDelete
  66. Greet to see this type of Articles every informative. Latest Mobiles

    ReplyDelete
  67. We are the best SEO services company, we find and fix the errors on your website .As a SEO services company we tend to facilitate brands reach new customers through search optimization and social media organic visibility.

    ReplyDelete
  68. Thanks for sharing this post with us. These posts are really amazing. Website maintenance services in Karachi depict that we provides one of the best services. Must visit us !!

    ReplyDelete
  69. As an Android application programmer you should now know how to stop placing look and feel attributes directly into your layout files and start using styles to design your UI. pearl necklace canada , pearl necklace australia

    ReplyDelete
  70. ViralAd is the best digital marketing agency in Karachi

    ReplyDelete
  71. Cyber security is a broad term that encompasses a collection of technologies, processes, and practices aimed at defending networks, devices, programs, and data against attack, damage, and unauthorized access. We may also refer to this as information security.

    Breeze End Technology, LLC is specialize in the best Enterprise Security design and installation of complete, turn-key, security management systems.

    Cybersecurity is critical because of this, especially when dealing with the federal, private, and health sectors A sizable portion of that data may contain sensitive information, such as intellectual property, financial data, personal information, or other types of data for which unauthorized access or exposure could have negative consequences. In the course of conducting business, organizations transmit sensitive data across networks and to other devices, and cyber security is the discipline dedicated to protecting that data and the systems used to process or store it. As the volume and sophistication of cyber attacks increases, businesses and organizations, particularly those tasked with protecting national security, health, or financial records, must take steps to safeguard their sensitive business and personnel information.

    Information Security is basically the practice of preventing unauthorized access, use, disclosure, disruption, modification, inspection, recording or destruction of information, Contact today for a free quote

    Cyber security is the practice of preventing malicious attacks on computers, servers, mobile devices, electronic systems, networks, and data. Additionally, it is referred to as information technology security or electronic data security.

    Security Solutions, Security Solutions, Threat Management, Incident Response, cybersecurity solutions, cyber security company, Cyber Security Services

    ReplyDelete
  72. Best article for us on your amazing blog

    ReplyDelete
  73. Thank you for this information, it is very useful for all.
    forum posting sites list

    ReplyDelete
  74. Android is a mobile operating system based on a modified version of the Linux kernel and other open source software, designed primarily for touchscreen mobile devices such as smartphones and tablets.
    Custom Web Development | SEO Company Pakistan

    ReplyDelete
  75. Thank you very much for such an interesting post. Keep working, great job! Buy Instagram Followers In India

    ReplyDelete
  76. This are the best everwifi names seen ever I like the way you represent this information

    ReplyDelete
  77. Make the extraordinary web-based presence of your business with a wonderful, intuitive site created by a first class site advancement organization in Pakistan.

    ReplyDelete
  78. Thank you for this amazing blog.
    Imperial Money is a dedicated company that provides personalized services for wealth creation. It is an all-around choice to go for to induce your monetary assets at ease with multiple innovative prospects that add more value to your profile. The services and ideas include innovative products, best-in-class experience, mutual funds, and equities.Imperial Money is a mutual fund company in India that helps you to create wealth from your income. Imperial Money provides services like a SIP calculator yearly, education calculator, and many more.
    Step Up calculator
    Mutual fund investment app

    ReplyDelete
  79. Stainless Steel Vents - Titanium Art
    Stainless titanium cookware steel Vents is a metal razor that is made titanium studs for corrosion resistant stainless steel. The stainless steel handle acts as a cutting microtouch titanium trim edge for titanium engine block the blade $14.90 · 2018 ford fusion hybrid titanium ‎In stock

    ReplyDelete
  80. It is a Web & Mobile development company providing best-in-class services on web development, application development, CRM & ERP solutions & more internet based services.

    ReplyDelete
  81. New and used slot machines - Pragmatic Play - AprCasino
    NEW AND NEW https://deccasino.com/review/merit-casino/ SLOT MACHINES WITH A communitykhabar HIGH RTP! aprcasino For the ultimate high-quality herzamanindir.com/ gaming experience, Pragmatic Play offers all of the https://septcasino.com/review/merit-casino/

    ReplyDelete
  82. HELLO! the information is very good and interesting..please keep updating it! thank you
    thanks

    ReplyDelete
  83. Thank you for your amazing blog kindly do visit my website
    ideahits

    ReplyDelete
  84. Awesome article, it was exceptionally helpful! I simply began in this and I'm becoming more acquainted with it better! Cheers, keep doing awesome!

    mlsu ba 1st year result name wise

    ReplyDelete
  85. I am very thankful to you for providing such a great information. It is simple but very accurate information.

    ReplyDelete
  86. Incredible points. Sound arguments. Keep up the great work. Read about dotnet trainer in chennai from Maria Academy.

    ReplyDelete
  87. Thanks for sharing this informative blog post. You can contact us for Web Development services.

    ReplyDelete
  88. This a very helpful article. We are offering hair removal machines at very reasonable prices. For order and further details, visit our website: The Silk Skin Shop

    ReplyDelete
  89. Thanks for sharing the information. We offer the best digital marketing services in Pakistan. Contact us for business promotion.
    For accounting and bookkeeping services in Dubai visit Kabanico.ae

    ReplyDelete
  90. After reading your article, everything is clear. Thank you for sharing.

    ERP software companies in Hyderabad

    ReplyDelete
  91. I really appreciate this wonderful post that you have provided for us. I assure this would be beneficial for most of the people.
    We are SEO Expert in Karachi, Pakistan.

    ReplyDelete

  92. Lifelong Wealth Management Group: Your Trusted Partner for Financial Success

    #LifeLong Wealth Management Group

    ReplyDelete
  93. I want to express my sincere appreciation for this fantastic post you have shared with us. I'm confident it will prove beneficial to a wide audience.

    local seo services

    ReplyDelete
  94. Some pest control companies in Lahore offer environmentally friendly or low-toxicity termite control solutions. These options prioritize minimal environmental impact while effectively managing termite infestations. It is advisable to inquire about eco-friendly alternatives when seeking termite control services.

    ReplyDelete
  95. The company offers a comfortable and welcoming environment for customers, where they can feel at ease discussing their hearing aid concerns and receiving personalized care.

    ReplyDelete
  96. Experience friendly and courteous service with Portland Cab. Customer satisfaction is our top priority, and we go the extra mile to ensure your comfort.

    ReplyDelete
  97. Safety is our utmost concern. Ride with confidence knowing that Portland Cab prioritizes your well-being and offers a secure journey.

    ReplyDelete
  98. The pizzeria also offers a variety of appetizers, salads, and pasta dishes, making it an ideal destination for a complete Italian feast.

    ReplyDelete
  99. RFS Tradings caters to both wholesale and retail customers, making their pink salt products accessible to individuals, restaurants, and gourmet food stores.

    ReplyDelete
  100. Mice control is a must! These tiny pests can cause significant damage and health risks. Swift action, traps, and sealing entry points are essential for a rodent-free home. Protect your property and family from these unwanted guests!

    ReplyDelete
  101. Black marble kitchen countertops exude timeless sophistication! The sleek, luxurious surface adds a touch of elegance to any kitchen. Its durability and natural beauty make it an excellent choice for culinary enthusiasts. Elevate your kitchen aesthetics with the classic charm of black marble!

    ReplyDelete
  102. https://gadgetssai.blogspot.com/2017/12/funny-wi-fi-names-for-your-home-router.html

    ReplyDelete
  103. You put really very helpful information. Keep it up. Keep blogging.
    Regards,
    Email Marketing Services

    ReplyDelete
  104. Implementing CRM for ATMs can revolutionize banking operations, enhancing customer service, optimizing cash management, and enabling targeted marketing. It's a strategic move to deepen customer relationships and maximize ATM efficiency in a competitive financial landscape.

    ReplyDelete
  105. Dapatkan penawaran spesial bunga ringan dan unit ready stock. Lifetime warranty Battery Aion

    ReplyDelete
  106. This is a fantastic breakdown of the challenges facing modern grocery businesses. Implementing the right grocery delivery software can truly streamline operations, improve customer experience, and help scale your service efficiently. A must-read for anyone in the industry looking to stay competitive

    ReplyDelete
  107. This explanation of Android Views and the use of XML layouts is very clear and practical for beginners trying to build efficient applications. As a student, I often rely on Data Mining Assignment Help to organize and analyze technical concepts like these for my coursework. With the support of Native Assignment Help, I can better understand how using constants and centralized design principles improves code maintainability and UI consistency. Learning to manage layouts this way not only saves time but also helps create scalable applications, which is essential for any aspiring Android developer.

    ReplyDelete