android_5.0_viewdemo
repository·master·Indexed 19 days ago
https://github.com/aiirux/android_5.0_viewdemoA collection of demonstration projects for Android 5.0, 6.0, and N. It features implementations of high-performance Gaussian blur using RenderScript and the BlurredView custom control, as well as architectural patterns for reducing boilerplate in lists via a generic CommonAdapter and CommonViewHolder using SparseArray for memory-efficient view caching.
What's inside android_5.0_viewdemo
- This repository is a collection of small demonstration cases focusing on new features introduced in Android 5.0 (Lollipop), 6.0 (Marshmallow), and Android N. It provides practical implementations for various Android components, architectural patterns, and UI effects to help developers understand and implement modern Android features.
Overview of HelloCharts capabilities
masterHelloCharts is a chart control library for Android. This demo showcases several types of visualizations and customization options available through the library:
- Basic Charts: Standard implementations of common chart types.
- Line Charts: Visualizing data trends over time.
- Column Charts: Representing data using vertical bars.
- Combo Charts: Combining different chart types (e.g., Line and Column) in a single view.
- Advanced Customization: High-level configuration of modules, attributes, and visual effects.
Note: This demo is intended for Android 5.0 and above.
What is RxJava and the ReactiveX concept
masterRx (ReactiveX) is a library that allows developers to compose asynchronous and event-based programs using observable sequences and LINQ-style query operators.
RxJava is the Java implementation of this concept. It is essentially a library for implementing asynchronous operations using observable sequences on the Java VM. It is a programming paradigm used to create asynchronous, event-driven programs.
Understand the RxJava execution flow (create vs subscribe)
masterIn RxJava, the relationship between an
Observableand aSubscriber(orObserver) is established through a two-step process: creation and subscription.create(): This method creates anObservableinstance and attaches anOnSubscribeobject to it. TheOnSubscribeobject contains the logic that defines how data is emitted.subscribe(): This method triggers the execution. When you callsubscribe(subscriber), RxJava executes thecall(subscriber)method stored within theObservable'sonSubscribeproperty. Thiscallmethod is what actually invokes theonNext,onCompleted, andonErrormethods of your subscriber.
Crucial Execution Order: The
subscribe()method initiates the process, but the actual logic inside theOnSubscribe.call()method (where your data emission happens) is executed as a result of the subscription. In a synchronous setup, thesubscribecall will block until thecallmethod completes its execution.// 1. Create the Observable Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("Hello"); subscriber.onNext("World"); subscriber.onCompleted(); Log.i("Execution Order", " call completed "); } }); // 2. Subscribe to trigger the logic observable.subscribe(new Observer<String>() { @Override public void onNext(String s) { Log.i("onNext", s); } @Override public void onCompleted() { Log.i("onCompleted", "done"); } @Override public void onError(Throwable e) { Log.i("onError", e.toString()); } });Understand Gson core components: JsonParser, JsonElement, and TypeToken
masterWhen working with GSON for manual or complex parsing, understand these three key components:
JsonParser: A utility class used to parse JSON strings into structured GSON objects. Use.parse(string).getAsJsonObject()for objects or.parse(string).getAsJsonArray()for arrays.JsonElement: An abstract base class representing any element in a JSON string. It can be aJsonObject,JsonArray, orJsonPrimitive. When iterating through aJsonArray, each item is returned as aJsonElement.TypeToken<T>: A utility used to capture generic type information (likeList<UserBean>) at runtime. Because of Java's type erasure,TypeTokenallows GSON to use reflection to understand the specific typeTinside a generic container.
How the RxJava Observer Pattern works
masterRxJava extends the traditional Observer pattern. In this model, an Observer reacts to changes in an Observable through a subscription relationship established via
subscribe().Key Differences in RxJava:
- Subscription: Achieved via the
subscribe()method. - Event Callbacks: There are three primary lifecycle events:
onNext(): Emits the next item in the sequence.onCompleted(): Signals the end of the event queue. A correctly running sequence should callonCompleted()oronError()exactly once, and it must be the last event.onError(): Signals an error in the event processing. This terminates the sequence immediately.
Observable Types:
- Cold Observable: Only emits items when at least one Observer has subscribed.
- Hot Observable: Emits items regardless of whether there are active subscribers.
- Subscription: Achieved via the
Understand FuncX and ActionX interfaces
masterRxJava uses
FuncXandActionXinterfaces to wrap functional logic. The primary difference is thatFuncXreturns a value, whileActionXdoes not.ActionX (No return value)
Used to wrap methods that perform an action without returning a result. They are often used in
subscribe()to provide incomplete callback definitions:Action0: WrapsonCompleted()(zero arguments).Action1<T>: WrapsonNext(T)andonError(Throwable)(one argument).Action2,Action3, etc.: Wrap methods with more arguments.
FuncX (With return value)
Used to wrap functions that transform data and return a result:
Func1<T, R>: Takes one argument of typeTand returns a result of typeR. This is the standard interface used with themapoperator.
Parse highly complex/nested JSON using JsonReader
masterFor extremely complex, deeply nested JSON structures where creating full Bean models is impractical or inefficient, use
JsonReader. This approach is similar to XML parsing: you navigate the JSON tree node-by-node based on keys.Mental Model:
- Use
beginObject()andendObject()to enter and exit JSON objects. - Use
beginArray()andendArray()for arrays. - Use
nextName()to retrieve the current key/tag. - Use
nextString(),nextInt(), etc., to retrieve values. - Use
skipValue()to ignore fields you don't care about, which prevents unnecessary processing.
Warning: This method is more verbose and requires manual management of the parsing state, but it is highly efficient for selective parsing.
/** * Example of manual node-based parsing with JsonReader */ private void parseComplexJArrayByReader() throws IOException { String strByJson = "...json_string..."; JsonReader reader = new JsonReader(new StringReader(strByJson)); try { reader.beginObject(); String tagName = reader.nextName(); if (tagName.equals("group")) { readGroup(reader); } reader.endObject(); } finally { reader.close(); } } private void readGroup(JsonReader reader) throws IOException { reader.beginObject(); while (reader.hasNext()) { String tagName = reader.nextName(); if (tagName.equals("user")) { readUser(reader); } else if (tagName.equals("info")) { readInfo(reader); } else { reader.skipValue(); // Skip unknown nodes } } reader.endObject(); } private void readUser(JsonReader reader) throws IOException { reader.beginObject(); while (reader.hasNext()) { String tag = reader.nextName(); if (tag.equals("name")) { String name = reader.nextString(); // Use name... } else if (tag.equals("age")) { String age = reader.nextString(); // Use age... } else { reader.skipValue(); // Skip irrelevant fields } } reader.endObject(); }- Use
Evaluate the Pros and Cons of Android Data Binding
masterWhen deciding whether to use Data Binding in your Android project, consider the following trade-offs:
Advantages
- Reduces Boilerplate: Eliminates the need to manually assign IDs to views and perform
findViewByIdcalls. - Safety: Helps prevent
NullPointerExceptionrelated to view lookups. - Efficiency: Provides a fast way to handle simple data-to-view mappings.
Disadvantages
- Complexity: Handling highly complex layouts or intricate logic within XML can become difficult and hard to maintain.
- Tooling: IDE support may not be as seamless as other libraries (like ButterKnife).
- Learning Curve: Requires understanding the specific XML syntax and lifecycle of binding objects.
- Reduces Boilerplate: Eliminates the need to manually assign IDs to views and perform
Implement a CommonViewHolder for efficient view recycling
masterA
CommonViewHolderuses aSparseArray<View>to cache views by their ID, reducing the need for repeatedfindViewByIdcalls. It manages the lifecycle of aconvertViewand provides a fluent API for setting view properties.Key Responsibilities:
- Caching: Uses
SparseArrayto store and retrieve views by ID. - Lifecycle: Handles inflation of the layout and manages the
convertViewviasetTag. - Fluent API: Supports method chaining (e.g.,
.setText(...).setImageResource(...)) to simplify view updates.
Core Methods:
get(Context, View, ViewGroup, int, int): Static method to retrieve an existing ViewHolder from aconvertViewtag or create a new one.getView<T>(int viewId): Retrieves a view of typeTfrom the cache or performs afindViewByIdif not cached.getConvertView(): Returns the underlyingViewfor use in the Adapter'sgetViewmethod.
// Example of using CommonViewHolder in an Adapter's getView method @Override public View getView(int position, View convertView, ViewGroup parent) { // 1. Get the ViewHolder CommonViewHolder viewHolder = CommonViewHolder.get(context, convertView, parent, R.layout.item_list, position); NewsBean bean = list.get(position); // 2. Set content using fluent API viewHolder.setText(R.id.tv_title, bean.getTitle()) .setText(R.id.tv_desc, bean.getDesc()) .setText(R.id.tv_time, bean.getTime()) .setText(R.id.tv_phone, bean.getPhone()); // 3. Return the recycled view return viewHolder.getConvertView(); }- Caching: Uses
Implement a Three-Level Cache mechanism (ImageLoader pattern)
masterFor optimal performance in image loading, it is recommended to combine different caching strategies into a single ImageLoader class. This is known as a Three-Level Cache mechanism:
- Memory Cache (
LruCache): Provides the fastest access to recently used Bitmaps in RAM. - Disk Cache (
DiskLruCache): Provides persistent storage for images on the device disk, preventing re-downloads after app restarts. - Network/Source: The fallback mechanism to fetch data when both memory and disk caches miss.
By encapsulating these into an
ImageLoader, you can manage Bitmap compression and seamless transitions between cache levels automatically.- Memory Cache (
Understand Scheduler operators: subscribeOn vs observeOn
masterRxJava uses Schedulers to control concurrency. Two primary operators manage thread switching:
subscribeOn(Scheduler): Specifies the thread on which thesubscribe()method (and consequently thecall()method of the source Observable) executes. It defines the thread where the event is produced.observeOn(Scheduler): Specifies the thread on which theObservercallbacks (likeonNext(),onError(), andonCompleted()) execute. It defines the thread where the event is consumed.