Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to optimize the built-in diagram network

2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article focuses on "how to optimize the built-in map network", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to optimize the built-in map network.

The main optimization methods of App package

Through the apk package structure, it can be found that the main means of packet size optimization are focused on resource optimization.

Analysis of Networked Technology of built-in Map

After investigation and summary can be divided into the following four points, this paper is mainly aimed at these four points.

When to intercept pictures to load

How to display a picture

Picture download and caching

Built-in picture deletion

How to intercept the method of view setting Picture Picture load two intercepting methods

GetDrawable

LoadDrawable

Android system view display pictures are finally obtained through the Resources class of the picture of the drawable object display. There are two interfaces getDrawable and loadDrawable to get the drawable object. GetDrawable is a public interface, and this method can be overloaded to achieve interception. Usually, setBackground or setImageDrawable will call it, and the loadDrawable method system View initializes the Drawable call.

/ / Resource#getDrawable,public Drawable getDrawable (@ DrawableRes int id, @ Nullable Theme theme) throws NotFoundException {if (whether the picture needs to be networked) {return network load} else {/ / return the normal process return baseResources.getDrawable (id, theme);}}

GetDrawable is easier to handle, but the loadDrawable method is a protected method that cannot be intercepted. After looking at the source code loadDrawable, the process did not find an opportunity to hook. I thought it would be easy to intercept drawable, but I didn't expect to spend a lot of time on this issue. Check the information, look at the source code and finally find a way!

Because the loadDrawable method is only used by the src and background properties of the system base view configured by xml (such as "ImageView, TextView, various layout managers, etc."), the drawable object is obtained during initialization of view. So it only affects the view configured by the xml layout file. So by implementing LayoutInflater.Factory2, intercept the xml View creation process and replace the view of xml with our custom base view. Determine whether to use src or background by traversing the current Attr attribute in the custom view, and then call the corresponding setImageDrawable or setBackground to trigger the Resournces#getDrawable API to complete the hook. Through this hook method, we can intercept the setting of drawable for XML layout view.

Class SkinTextView extend TextView {public SkinTextView (Context context, @ Nullable AttributeSet attrs) {super (context, attrs); setSkin (this,attrs);} private static final int [] ATTR_ARRAY = {/ / this attribute is a property of the system class View and is not visible to the APP realm. / / but this value is fixed, so it can be written like this, here refer to the RecycleView#NESTED_SCROLLING_ATTRS implementation 16842964 * android.R.attr.background * /, android.R.attr.src}; public static void setSkin (View view, AttributeSet attrs, DraweeHolderSupplier supplier) {Context context = view.getContext (); Resources resources = context.getResources (); TypedArray ta = context.obtainStyledAttributes (attrs, ATTR_ARRAY); Drawable background; int drawableId For (int I = 0; I

< ATTR_ARRAY.length; i++) { int attr = ATTR_ARRAY[i]; drawableId = ta.getResourceId(i,0); if (drawableId == 0){ continue; } background = resources.getDrawable(drawableId,context.getTheme()); switch (attr) { case 16842964: view.setBackground(background); break; case android.R.attr.src: if (view instanceof ImageView) { ((ImageView)view).setImageDrawable(background); } break; } } ta.recycle();}} 但是以上方案只能解决XML中系统基础的View,如果XML中使用开发自定义View则不管用。为了解决自定义view的问题我想到了两种解决方案。 方案一 通过字节码修改方式将所有自定义view继承的系统基础view改为继承我们自定义的基础view 我通过asm字节码修改将APP内所有自定义view继承的系统基础view改为自定义基础view,这个方案可行,但是缺点比较多需要全局修改所有库的字节码包括androidx库AppCompatView,修改范围太大,框架稳定性不太容易保证,由于自定义基础view有一些拦截代码所以对view初始化性能也有一定影响,且ASM代码编写出现bug不易排查。如果只修改我们业务线的字节码,可以正常运行。但修改第三方aar字节码后,遇到一个坑,应用一直ANR期间没找到具体原因。 方案二 hook LayoutInflater解析XML自定义view过程 // LayoutInflater#createViewFromTagView createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr) { try { View view; if (mFactory2 != null) { view = mFactory2.onCreateView(parent, name, context, attrs); } else if (mFactory != null) { view = mFactory.onCreateView(name, context, attrs); } else { view = null; } if (view == null && mPrivateFactory != null) { view = mPrivateFactory.onCreateView(parent, name, context, attrs); } // 以下onCreateView方法可以重载,拿到view对象强制触发getDrawable即可,中间需要一些过滤。讲一下大致思路,细节就不加了。 if (view == null) { final Object lastContext = mConstructorArgs[0]; mConstructorArgs[0] = context; try { if (-1 == name.indexOf('.')) { view = onCreateView(parent, name, attrs); } else { view = createView(name, null, attrs); } } finally { mConstructorArgs[0] = lastContext; } } return view; }} 这个方案可以将自定义view拦截,缺点就是依赖android系统版本,如果android系统这块逻辑发生变化那么需要适配。不过对于后续需要使用Fresco框架加载图片以及内存管理,这个方案无法做到融合Fresco,所以该方案最终也没有利用起来。 最终决定放弃对自定义view这种情况处理。通过遍历xml 将自定义attr和自定义view过滤。 字节码修改和自定义属性、view过滤方案可以参考下图。

/ * Custom attributes, view filtering * hook aapt packaging process, get the res resource paths of all modules, traverse the xml * / Pattern pattern = Pattern.compile under all res/layout ("(? / / get xml content, match the string} through regular expressions to download the picture scheme and how to display the picture download scheme.

At that time, two options for downloading pictures were considered.

Apk, the image plug-in, packages all the required pictures into apk, and then downloads the plug-in only once, without considering the image memory problem.

Download pictures directly from the network and manage memory problems through Fresco

Comparing the two schemes, I chose the second one, which is easier to implement.

Picture display

This problem is easy to solve. View and drawable are transmitted through Drawable.Callback, so download the image to get the drawable object through drawable callback#invalidateDrawable. Of course, the drawable returned here should be a LayerDrawable, because the Drawable used by Drawable.Callback to perform updates must be the same Drawable object, and it is convenient to return the default diagram in synchronous state, and refresh the asynchronous network diagram when it is returned.

It is important to note that you cannot use the Fresco RootDrawable object to return directly here, because Fresco does not support the view wrap_content property.

Picture download strategy and caching

Because you need to use Fresco, a brief introduction. Fresco structure layering can be divided into three layers, namely, layer, controller, picture acquisition, each layer structure and function as shown in the figure.

RootDrawable is the final returned image Drawable object

DataSources returns the subscription source of image information.

The middle bridge between Controler picture acquisition and layer display

The third layer is the three-level cache of pictures, which can be obtained from the cache and the network.

Get a general understanding of Fresco. The following describes the integration of the built-in graph networking framework with Fresco, and the use of Fresco for image download and caching.

This implementation can be compared to the DraweeView implementation of Fresco, using several life cycle functions of view attach, detach, visible to trigger the loading and destruction of drawble through DraweeHolder, so as to achieve the image cache and memory release of Fresco. The specific process is not introduced, you can read the Fresco source code if you are interested.

The implementation process is shown in the following figure.

Built-in map deletion

After practical research, the built-in image can not be deleted directly, otherwise an error can not be found when the image is linked in the packaging process, so the main idea is to replace the picture to be deleted through a 1-pixel picture.

There are several ways to delete a built-in diagram

I choose option 4, which has the following advantages

It is convenient to select batch deletion according to the size of the picture.

The optimized packet size can be calculated directly.

Can be directly integrated into the APP compilation process, compilation in one step

The implementation scheme is as follows

At the end of the hook aapt resource packaging process moregeResources

Traverse all the generated image flat binaries and replace the png, webp, and jpg binary data in the flat file with the one-pixel default image.

The trouble with this scheme is the process of reading the binary stream of flat files.

Flat file container format transfer gate

At this point, I believe you have a deeper understanding of "how to optimize the built-in map network". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report