It is above all a way of insulating data consumers and data providers. You develop your own content provider or extend an existing one if you want to make some of your data public or at least available to other application.
True this can server to control accesses from a security point of view but it also allows you to rework the physical implementation of your data whenever you want. All you need to do is to adapt the back-end of your content provider in that case. The data consumer applications will not have to be rewritten. They will carry on accessing your data through their content resolver unaware of any change in the actual underlying implementation.
Also, Android will instantiate only one instance of your content provider even if the data is accessed by several clients so it will take care of concurrent accesses without you having to care about it.
Finally, I believe it will also handle the drudgery of clean start up and shut down.
Well, most immediate justification for this design decision can be found in method javadocs:
you can cast the return value from this method to Spannable or Editable...
Casts mentioned above are possible only because Spannable and Editable implement CharSequence; String wouldn't allow for that.
For a deeper understanding of the design motivation, take a look at class javadocs:
TextView is a complete text editor...
Above means that TextView object is designed to support frequent changes of its content.
If getText would return immutable String, this would mean a high chance of creating multiple objects while working with TextView. This in turn would go against general approach preferred in Android and outlined in Avoid Creating Unnecessary Objects guidelines:
Object creation is never free. A generational garbage collector with per-thread allocation pools for temporary objects can make allocation cheaper, but allocating memory is always more expensive than not allocating memory.
As you allocate more objects in your app, you will force a periodic garbage collection, creating little "hiccups" in the user experience. The concurrent garbage collector introduced in Android 2.3 helps, but unnecessary work should always be avoided.
Thus, you should avoid creating object instances you don't need to...
For the sake of completeness, it is worth noting that reasoning in above guidance implicitly involves mobile applications specifics.
In particular, one can imagine desktop or server platforms having more sophisticated garbage collection, allowing developers to design immutable objects at their discretion, without worrying much about performance implications.
At mobile platforms, API designers have to take into account resource limitations of mobile devices (memory, processor, power consumption etc) that can block implementation of theoretically better approaches.
Best Answer
The point of
CharSequence
is to provide a read-only view to a character sequence, and that's it. This interface does not provide any string manipulation or searching methods. Those are out of scope.The Interface Segregation Principle suggests that clients of a type should not depend on methods they don't use. Therefore, an interface should declare only the minimal useful set. If a different use case needs different methods, there should be a different interface.
A client that only needs a character source likely does not need search methods.
It is of course possible to overdo this Principle and end up with a thousand little interfaces. That's not good either. So the
CharSequence
interface doesn't just contain the minimalcharAt()
andlength()
methods, but also the deeply related convenience methodsubSequence()
. (A CharSequence can likely provide a view onto a subsequence without a string copy, which is why this should be an instance method). SpecifyingtoString()
is OK because that method would be inherited anyway fromObject
. The methodschars()
andcodePoints()
adapt aCharSequence
to aStream
interface. Because these are default methods, they do not impose additional requirements for classes implementingCharSequence
.The
CharSequence
type is useful when a method needs a generic character source without specifying a particular implementation (e.g. String vs. CharBuffer vs. StringBuilder). TheString#join()
andString#contains()
methods are good examples of usingCharSequence
s.It is not necessary for
CharSequence
to provide acontains()
method because it can be implemented externally. While Java does not have the convenience of C#'s extension methods, a static method is essentially the same thing. So instead ofboolean Editable#contains(CharSequence needle)
you would have astatic boolean contains(CharSequence haystack, CharSequence needle)
. String search algorithms are a well-studied computer science topic. Different algorithms with different tradeoffs are readily available.Further reading:
Wikipedia: String search algorithms. See particularly the Boyer-Moore algorithm.
Wikipedia: Interface Segregation Principle.
Robert C. Martin: The Interface Segregation Principle (PDF on Google Drive, PDF on the Internet Archive's Wayback Machine).