This article is the first in our series on Functional Design, discussing the design ideas for our online project feed card exposure/consumption.

The series will break down the design process of important features in online projects. The focus is to let readers understand the significance of the design of functional modules and the overall idea of building, most of the details of each project can be realized by themselves.

background

Most apps in the market adopt the design form of information flow to carry the display of information content, and the design form of information flow is different for products with different characteristics.

Such as picture waterfall stream, product list stream or news Feed stream.

(Taobao product Stream)

(Understand video streaming)

Although the presentation is different, the flow of content through the list is the same, and the interaction of scrolling through the list exposes more content.

The display effect of list contents can be measured by multi-dimensional calculation of the exposure times/click times/exposure time/sliding time of list items.

Like the usual click-through rate, length of consumption.

CTR = number of clicks/number of exposures, the higher the CTR, the higher the user’s intention to further understand the content.

Consumption time =t(sliding time)-t(last exposure time), the longer the consumption time, the higher the user’s interest in the content.

Of course, the calculation rules for different list contents are different, and the emphasis for evaluating the effect of content presentation should not be the same.

For example, content items in the information Feed stream are more displayed in the form of mixed pictures and texts to attract users to click on consumption, and pay more attention to the click rate of content.

For short video FMCG content items in video stream, they generally support direct play on the stream and pay more attention to the viewing and consumption time of the content.

So the exposure/consumption data of the news stream list items is crucial to measure the effectiveness of the stream delivery, so how do you get this information?

Design ideas

Take our online project for example. There are a lot of in-app information flow pages.

Dynamic card streams with microblogs.

Class information class card flow.

Dual-column video streaming.

The above are only three common scenarios. If the design is made for the list of all scenarios, it is obvious that the maintainability and expansibility are very poor. Therefore, a universal design must be considered.

We agreed on several high-frequency words and used them to replace the expression in the subsequent description.

  • Card, any information flow list item.
  • Exposure, the act of exposure of a card.
  • Consumption, the consumption of cards.
  • Effective area, the visible area of the card exposed to the interface.
  • Effective area ratio, the ratio of the card valid area to the total area of the card view1/2 ~ 4/5.
  • Valid card. If the valid area ratio of a card is higher than a certain threshold, the card is considered valid, which is usually 2/3, 3/5.
  • Minimum valid consumption time. When the valid card consumption time is less than this time, the user is considered to have no consumption behavior. The value can be 100 to 200 milliseconds.

Effective area is used to calculate the size of the card visible on the interface, and when a card’s visible area is too small, even for a long time, we assume that the user has no perception of its content.

Valid cards are ones where the user has a perception of the card’s content, and they have a chance to be exposed and consumed.

With that in mind, let’s define a general card exposure/consumption rule:

  1. When the list is still and the user has no contact with the interface, the valid cards in the list are recorded as an exposure behavior;
  2. When the stationary list starts to slide again, the valid cards in the original stationary list record a consumption behavior.

According to the rules, the logic of card exposure consumption is as follows:

  1. Collect all cards visible when the list is still and the user has no contact with the interface;
  2. The effective area rate of filtration is less than3/5Is the valid card set for cache, and the cache set is obtainedList [currently valid card];
  3. The valid card set is exposed and the exposure time point is recordedt[exposure]In fact, this time is also the time to start spendingt[startConsume].
  4. When the list starts to slide, get the current time stamp minus the last exposure time to get the consumption time, if the consumption time is not less than 100 milliseconds, thenList [currently valid card]Keep track of your spending.
  5. Expansion Enhances expansion. Reserve the above process to support key parameters, such as whether to dynamically adjust the effective area rate and the minimum effective consumption time.

In addition, it can also control whether the same card in the same interface allows multiple exposures, or control the card exposure gap, as required.

The specific implementation

Define an interface CardLogFeed to describe the card.

Public interface CardLogFeed {// Business defined card information class, custom extension modify @nullable CardLogInfo buildCardLogInfo(); Void logExposure(); // Trigger consume callback void logConsume(long time); Boolean isVaildLogUnit(); }Copy the code

The callback behavior for each card exposure/consumption is different and open to implementation by the business side.

CardLogInfo class records the log information about each card. Generally, the log information is required to be reported for exposure or consumption.

The isVaildLogUnit method requires the business to tell whether the current card is a valid card. The method realizes the decision logic of valid cards mentioned in the chapter of design idea.

In addition, there may be differences in different card styles, such as rectangle, square, circle, or even irregular graphics, so the implementation idea is not limited to comparing the visual area ratio, and the business implementation party can choose freely.

Define a class CradLogScrollLisener class, inheritance RecyclerView OnScrollListener list and implement related logic.

First, override the onScrollStateChanged method to get the list state and process it accordingly.

Private int currentNewState = SCROLL_STATE_IDLE; @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); Case SCROLL_STATE_IDLE: {exposureCardLog(); break; } // Try consuming case SCROLL_STATE_DRAGGING: {if (currentNewState! = SCROLL_STATE_SETTLING) { consumeCardLog(startConsumeTime); } break; } default: break; } currentNewState = newState; }Copy the code

By capturing the SCROLL_STATE_IDLE state to try exposure, the collection process and exposure of valid cards were realized in the exposureCardLog method. The core logic is listed below (only the core logic is listed).

Private void exposureCardLog() {startConsumeTime = system.nanotime (); . / / collect valid card currentValidVisibleFeeds currentValidVisibleFeeds (); if (currentValidVisibleFeeds.isEmpty()) { return; } for (CardLogFeed logFeed: currentValidVisibleFeeds) {logfeed.logExposure (); }}Copy the code

The final step exposes the collected CardLogFeed objects (valid cards), and the collected logic is implemented in the currentValidVisibleFeeds method.

public List<CardLogFeed> getCurrentValidVisibleFeeds() { List<CardLogFeed> currentValidVisibleFeeds = new ArrayList<>();  / / get layoutManager RecyclerView. LayoutManager layoutManager = mRecyclerView. GetLayoutManager (); If (LinearLayoutManager instanceof LinearLayoutManager) {int firstVisibleIndex = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); int lastVisibleIndex = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); for (int i = firstVisibleIndex; i <= lastVisibleIndex; i++) { RecyclerView.ViewHolder viewHolder = mRecyclerView.findViewHolderForAdapterPosition(i); if (viewHolder instanceof CardLogFeed && ((CardLogFeed) viewHolder).isVailLogUnit()) { currentValidVisibleFeeds.add((CardLogFeed) viewHolder); }}} / / in view of the waterfall flow layout if (layoutManager instanceof StaggeredGridLayoutManager) {/ /... } return currentValidVisibleFeeds; }Copy the code

Taking linear typesetting as an example, obtain all visible Holder objects on the interface and judge whether each object is CardLogFeed type and meets the judgment conditions of valid cards, and finally obtain the valid card set.

After finishing the exposure, go back to the list when sliding triggered by the consumeCardLog consumption method.

Private long DURATION_STEP =1000000; Private long MIN_CONSUME_DURATION = 100; Private void consumeCardLog(long startConsumeTime) {// Obtain the interval long consumeTime = (system.nanotime () - startConsumeTime)/DURATION_STEP; if (consumeTime < MIN_CONSUME_DURATION) { return; } if (currentValidVisibleFeeds.isEmpty()) { return; } // Consume for (CardLogFeed logFeed: currentValidVisibleFeeds) {logFeed. LogConsume (consumeTime); }}Copy the code

When the list starts to slide, a purchase is made with the valid card from the last exposure cache.

At this point, a complete exposure/consumption logic is implemented, the core process remains unchanged, and internal details can be adjusted freely.

As a final demonstration, set the color to gray when a valid card is exposed and return to normal after consumption.

The latter

Feed card discovery/consumption data feedback is a great guide to your content delivery strategy. The purpose of this article is to explore the overall programming ideas for more developers to compare when they encounter similar scenarios in the future.

If you have better ideas or suggestions, welcome to discuss.

As far as developers are concerned, sometimes a seemingly simple requirement is received, but in fact, it is extremely important to develop a good design pattern for every program developer.

I remember one time, we were asked to make automatic playback of video cards of information stream. We said, “After the list stops, the video cards that meet the automatic playback conditions will be played. It should be quite simple, right? .

Me: “…”

The next installment of that series will talk about how to choose rich media items in the context of the news stream, including Gif/video playback.

Welcome to follow more.

Welcome to the Android Zen account to share valuable and thoughtful technical articles with you. Can add wechat “Ming_Lyan” remarks “into the group” to join the technical exchange group, discussion of technical problems is strictly prohibited all advertising irrigation. If you have technical problems in the Android field or have doubts about your future career plan, discuss with us. Welcome to the party.