Caused by: org.xmlpull.v1.XmlPullParserException: Binary XML file line #5<gradient> tag requires ‘angle’ attribute to be a multiple of 45
We all know how android project structure looks like — place all images inside this folder and all layouts inside that folder. But… during project development the number of files grow up rapidly and it becomes hard to navigate and search needed file.
Resource folder — per screen
In case if your screens consist of big amount of layouts, drawables, dimensions — it make sense to create separate resource folder for every screen.
As you can see on image above we have two root folders inside main folder:
res-main contain all common resources which are used on more than one screen.
res-screen contain resource folders for every screen e.g. about, chat,event details, event list, home, login
Let’s take a look what we have inside chat screen resource folder.
Chat itself consist of several xml layouts files so we created chat layoutfolder and moved all those files here. It also has a lot of .png images which are used only on chat screen, so we moved all those images files to chat drawable-hdpi, drawable-xhdpi, drawable-xxhdpi and drawable-xxxhdpifolders.
When times come to implement landscape layout or tablet version of chatwe will make layout-land and layout-sw720dp folders inside chat screen resource folder.
How declare screen resource folder?
Open app.gradle file and declare sourceSets inside android section. More about resource merging here.
Building for the “next billion” is a challenge, thanks to difficulties posed by the lack of internet, electricity, and low-cost devices. At SocialCops, we set out to build an Android data collection application that could work in the most remote, rugged parts of the world. We have been successful in building an Android application, Collect, that works without internet, on phones that cost INR 2,000 (USD 30), on 512 MB memory, and 1 GB storage. We still managed to include features such as voice to text, media capture, and location-based verification. Here’s how we did it.
Only 1 out of 3 people can access the Internet today. In a country like India, an estimated 75% of the population doesn’t have access to Internet facilities. Today, most of the data that we “mine” in the big data revolution comes from the 30% of the world’s population that can access the Internet. So much for #bigdata. At SocialCops, we aim to drive the most important decisions facing mankind through data — in most cases, these decisions heavily impact the 70% non-internet-accessing, non-Facebook-using population.
We set out to map the remotest of areas — along with the people living in them — by providing a free data collection and monitoring tool for non-profits around the world. By building a kickstarter for data collection, we aimed to empower non-profits and public sector organizations to effectively collect and manage their data. We decided to build the tool on Android. Given the Android revolution and the decreasing cost of phones, it was the only logical option. It wasn’t the easiest task though.
Challenge 1: Working with Memory Constraints in Low-Cost Android Devices
Most low-cost Android devices have a limited memory (RAM), usually 512 MB or 1 GB of RAM. This makes developing a “data collection device” for Android a difficult task. The data structure needs to be designed with the memory consumption of the application in mind. No user enjoys an “OUT OF MEMORY” warning message flashing on their screens.
To optimize memory consumption, we defined objects for each entity like surveys, questions, and other parameters. We carefully controlled each object to prevent memory leaks and to ensure the object was deleted while not in use. This saved us tons of memory and increased the speed of the application.
These are some tips to ensure your Android application can function with low memory:
1. Avoid memory leaks: Memory leaks are usually caused by holding on to object references in global members. Remember to release any reference objects at the appropriate time.
2. Use services sparingly: If your app needs a service to perform work in the background, do not keep it running unless it’s actively performing a job.
3. Release memory as it becomes tight: The onTrimMemory callback can be used to check when the overall device memory is getting low.
4. Check how much memory you should use: Call getMemoryClass to get an estimate of your app’s available heap in megabytes.
5. Release memory when your user interface is hidden: Another cool trick is to release any resources that are used only by your UI when the user navigates to a different app and your UI is no longer visible.
6. Avoid wasting memory with bitmaps: When you load a bitmap, keep only the resolution you need for the current device’s screen.
7. Use optimized data containers: Use SparseArrray, instead of generic HashMap.
8. Stay aware of memory overheads: Make sure you have sufficient knowledge about the cost and overhead of the language and libraries you are using, then keep this in mind at every step when you design your app. The less the RAM you use, the greater the efficiency of your Android application. This allows more data to be processed.
Memory is especially important while making an app usable without internet. You will need to store and process all your data at the same time, since you can’t fetch the required data and process it.
Challenge 2: Working with Storage Constraints in Low-Cost Android Devices
Given the limited storage on Android devices (e.g. 1 GB, no internal storage space, or 1 GB — 16 GB external memory), we had to leverage innovative solutions to ensure that field workers could collect data and store it locally until they could access internet at district centers. There are many alternatives available to store data, which you can choose from depending on your needs. Here are some storage parameters that you can use in Android:
1. Shared Preferences: This is a key/value store where you can save data under a certain key and easily access it by entering the key. This is very useful when you need to store a small amount of data, but storing and reading large structured data is extremely difficult as you need to define a key for every single data point. Furthermore, you can’t search within the data except when you have a certain concept for naming the keys. This is perfect for the NOSQL concept (JSON).
2. SQLite: Large amounts of similarly structured data should be stored in a SQLite database. Since the data is structured and managed by the database, the data can be queried using a query language like SQL. This makes it possible to search within the data and get a subset of the data that matches a certain criteria. Managing and searching large sets of data influences performance, so reading data from a database can be slower than reading data from Shared Preferences.
3. Files: Android uses a file system that is similar to disk-based file systems on other platforms. File objects are well-suited to reading or writing large amounts of data in start-to-finish order without skipping around. For example, Android files are perfect for image files or anything exchanged over a network, and these can be stored in internal or external storage before they are uploaded.
In the first version of Collect, we used Shared Preferences to store JSON data and Files to store media files until they can be uploaded to the server. For the next version, we are exploring Realm for storing JSON-formatted data.
Note: Don’t forget to delete local data from storage once it has been uploaded on the server.
Challenge 3: Dealing with Performance and Speed Issues in Low-Cost Android Devices
The speed of your application is one of your users’ top priorities, so you should be sure to optimize speed wherever possible. One classic way of improving speed is to fetch information in one go and restrict updates to when there is a worthy change.
Some of the other ways to optimize for speed are:
Avoid creating unnecessary objects
Prefer static over virtual
Use enhanced for Loop Syntax
Avoid using floating point
Know and use the Libraries
Use Native methods carefully
Using these simple methods, you can optimize performance and increase speed. This will ensure that the application runs in the same way both online and offline.
Challenge 4: Designing a User Interface for a Population That Has Never Been Online
Applications for rural India require a simple, intuitive user experience to ensure that rural users can actually use the platform. Designing for the next billion poses a whole new level of challenges, which we explored in depth ina separate blog post.
On the mobile front — we had to build the mobile application keeping in view the erratic internet connectivity in remote areas. The one mantra we religiously followed was to keep things simple and show users information up front.
Challenge 5: Optimizing Battery Use
The key limitation to using a phone in the rural world is battery — once a phone runs out of battery, data collection is done for the day. This is why it’s essential to be careful about how much battery an app uses.
While developing an Android application for the offline world, you need to be specific about everything you’re storing offline, the space you’re providing to every module, and the processes you’re running. Your user will most likely be using a low-cost phone, so make sure you know how to store information, change the frequency of storage, and notify the user if they need more storage space.
To optimize battery, optimize the way you fetch locations for the use case of your application. For example, if the application is navigation based, then the location has to be fetched faster. If we need the location at one point, you can use a single fetch. You can also decrease the location accuracy, since higher accuracy uses more battery.
We use Battery Historian (a tool in the Android studio) to observe an application’s battery consumption.
Most Android developers love the thrill of coding for the latest gadgets in the market, with rich graphics and lots of heavyweight features. However, this changed when I visited Mewat in Haryana to observe a field pilot with our partner NGO. I saw my product in the hands of people who had never used technology before and the sheer joy they derived from simply tapping on answers. I experienced a strange high for having conquered the challenge of developing for a world that hasn’t seen the internet age. Trust me — that feeling of building something that could potentially change someone’s life is indescribable.
This article was first published on the SocialCops blog on 26 December 2014 and updated on 19 May 2016.
For the last month I’ve been developing an app that relies heavily on a server-side API. The whole process was a mess. This is what a typical morning looked like: I would start working on a feature in the UI, realise I have a bug in my network layer, patch it up, continue working on the feature, realise there’s data I need that’s not in the server response, tell the backend guy it’s missing, have lunch, then forget what I was doing because I’m working on five things at once! That is no way to live.
So I got an idea. Why not just make a stub backend. That is, make a fake version of the service your app relies on, before you even start working on a single feature. If your app relies on some sort of server-side API to fetch data, write a class that will give you stub data. Make that class implement an interface, and then make the rest of your app talk to the interface.
I probably spent about 20% of my development time of this app going trough the whole flow of the app until I get to the point I want to test, just because that’s the way our backend is set up. Had I worked with dummy data and stubs from the beginning, I would have been able to test each part of the app separately and have complete control over the whole process.
Overhead doesn’t always mean slower. Construction workers working on your building would sure as hell have a harder time without their scaffolding. In this case, the (usually small) time it takes to write a dummy network service is minimal compared to the amount of time you’ll be waiting for your backend team to fix a server-side bug.
A programmer coding at full throttle is keeping zillions of things in their head at once: everything from names of variables, data structures, important APIs, the names of utility functions that they wrote and call a lot, even the name of the subdirectory where they store their source code. If you send that programmer to Crete for a three week vacation, they will forget it all. — Joel Spolsky
This is a real thing. It means that humans are more efficient at working on one thing at a time because it takes us time to get used to new ways of thinking. Constantly switching from working in your network layer to writing a new feature in the view layer means you’re always in that ‘getting started’ phase.
This is a popular saying in programming. But it doesn’t apply to just design — it also applies to the whole development process. You want to define your architecture as early as possible. And then, no matter how good you are, you will have made a ton of mistakes. This is why you start with a stub and make your app around it. This will show you the shortcomings of the way you’ve designed your app early on, and give you the opportunity for very easy change.
If you set up your architecture correctly, (layers decoupled from one-another and using interfaces for communication) your app won’t actually care whether it’s the server or a class from its own bundle supplying the data. So, your backend team can work on their end, and you can work on yours, and when it comes time you just join forces.
Makes you think of future changes
Software development is a whole series of changes. The whole point of using an SVN is to track changes. So, you want to make changes as easy and painless as possible. Using stubs will force you to design your architecture in a way where you can change the underlying model and network service without having to change your UI layer. This will make your life a lot easier down the line.
Sets you up for UI testing
UI testing is a huge pain in the ass. But it’s also a huge lifesaver. Using stubs will make your UI tests run much faster, and you’ll have much more control over them.
Make an interface (protocol) that the object (only one object) that will talk to the server should implement.
Make an implementation for the happy path (return dummy data, process requests with the correct response, etc.)
Make an implementation for the sad path (return no data, junk, incorrect responses, etc.)
Create your app. Never talk to the implementations above directly, always use the interface.
Switch between the happy and sad implementations to check if your app handles both correctly.
When you’re done with the app, create your real network service.