My practical experience in Android development

My practical experience in Android development

I have always wanted to write an article summarizing my experience in Android development. I guess I was not at a certain level at that time, so I couldn't keep up with my thoughts and couldn't write well. Recently, my thoughts became clearer, so I picked up the keyboard again and started typing. Let me make it clear that I am not a programmer from a big company. Before I graduated last year, I have been working in my current entrepreneurial team and doing the coding business that I love. The following summary is based on my current technical level and cognition. If you have different opinions, please leave a comment and communicate with each other.

1. Understand abstraction and encapsulate changes

Currently, most of the development on the Android platform is done in Java. When dealing with an object-oriented language like Java, it is inevitable to touch upon the concepts of abstraction and encapsulation . Some of the developers I have come into contact with still stay at the stage of writing an abstract class, interface, or a method (or abstract method) for these concepts. As for why, I am not sure whether they cannot express it or do not understand it. I will not talk about it in detail below, but directly give examples to explain what I understand as abstraction.

 //Two ways to pass data between Activities using Intent The following are pseudo-codes, please ignore some details

//Writing method 1

//SrcActivity passes data to DestActivity
Intent intent = new Intent( this ,DestActivity.class);
intent.putExtra( "param" , "clock" );
SrcActivity.startActivity(intent);

//DestActivity gets the data passed by SrcActivity
String param = getIntent.getStringExtra( "param" );

//Writing method 2

//SrcActivity passes data to DestActivity
Intent intent = new Intent( this ,DestActivity.class);
intent.putExtra(DestActivity.EXTRA_PARAM, "clock" );
SrcActivity.startActivity(intent);

//DestActivity gets the data passed by SrcActivity
public final static String EXTRA_PARAM = "param" ;
String param = getIntent.getStringExtra(EXTRA_PARAM);

The problem with the first method is that if either SrcActivity or DestActivity types "param" incorrectly as "para" or "paran", the data being transferred cannot be received successfully. The second method does not have this problem, because the data being transferred between the two Activities only needs to know the EXTRA_PARAM variable, and it does not matter whether the EXTRA_PARAM variable is "param", "para", or "paran". This is a manifestation of abstract encapsulation of places that may change, which reduces the probability of errors caused by hand shaking and facilitates our modification.

Based on abstraction and encapsulation, many Java APIs are designed in this way, such as many sorting methods in Collections:

Sorting API in Collections

These methods are based on the abstract list interface List for sorting. As for what kind of data structure is used to implement List (ArrayList or LinkedList), the sorting method itself does not care. See, does it reflect the abstract programming thinking of JDK designers? Because there may be tens of millions of specific implementations of List, if you have to write a set of sorting methods for each type of List, it is estimated that you will cry blind.

Summary: Abstracting the parts that are prone to change is a kind of encapsulation of the change.

2. Choose the right "wheel"

We cannot develop a project from scratch. If we do, we will be in big trouble. Therefore, it is very important to be good at borrowing the "wheels" that have been made, such as:

  • Network access framework: OKHttp , retrofit, android-async-http, volley
  • Image loading framework: Android-Universal-Image-Loader, Glide , Fresco , Picasso
  • Cache framework: DiskLruCache , Robospice
  • Json parsing framework: Gson, Fastjson, Jackson
  • Event Bus: EventBus, Otto
  • ORM framework: GreenDAO, Litepal
  • There are also various other open source custom controls, animations, etc. In addition to the open source frameworks mentioned above, there are also some closed source SDKs
  • Data statistics: Umeng statistics, Baidu statistics…
  • Crash collection: Tencent bugly, bugtags…
  • Cloud Storage: Qiniu…
  • Even if the communication: Huanxin, RongCloud, Alibaba Baichuan...
  • Push: Xiaomi push, Tencent push, Baidu push...
  • Security reinforcement: 360 reinforcement, iCrypt...

Generally speaking, I choose whether to introduce some open source frameworks based on the following factors:

  • With the help of search engines, if there is a lot of information online, it means that many people are using it, and it is easy to find solutions when problems arise; of course, if there are generally bad reviews, you can just pass it up.
  • Look at the author or team of the framework, such as Jake Wharton, Facebook team, etc. The quality of frameworks produced by great authors and large companies is relatively high, which can ensure subsequent maintenance and bug fixes, and is not easy to be unfinished;
  • Pay attention to the commit density of open source projects, the number of issues submitted, replied, closed, watched, started, forked, etc. For projects that rarely submit code, raise issues, and rarely reply or fix them, it is best to pass them;

The choice of closed source SDK is mainly based on the following considerations:

  • Use search engines to find out word of mouth;
  • The homepage of many third-party SDK websites will tell you how many applications have been connected to this SDK. If you see a lot of well-known applications on it, then you can consider trying this SDK. For example, Umeng official website:

Access Umeng App

  • Check the SDK documentation, their developer community, and contact customer service. For a good SDK, the documentation will definitely guide you in detail. If you have any questions, ask them in the developer community, and their development engineers will also answer them in the community. If it really doesn't work, you can only contact customer service. If the attitude of the customer service makes you unhappy, then you can consider switching to another SDK.

Summary: Choose the right "wheel" to get twice the result with half the effort

3. Abstract dependencies on third-party frameworks

Why do we need to abstract our reliance on third-party frameworks? This is consistent with the first point, which is to reduce our reliance on a specific framework, so that we can quickly switch to different frameworks. At this point, you may find it very abstract, so let me give you an example of loading a picture.

Suppose you are currently introducing a framework for loading images into your project - Android-Universal-Image-Loader. The easiest way is to add the corresponding dependency package and write the following code snippet wherever you need to load images.

ImageLoader imageLoader = ImageLoader.getInstance(); // Get singleton instance
// Load image, decode it to Bitmap and display Bitmap in ImageView ( or any other view 
// which implements ImageAware interface )
imageLoader.displayImage(imageUri, imageView);
// Load image, decode it to Bitmap and return Bitmap to callback
imageLoader.loadImage(imageUri, new SimpleImageLoadingListener() {
    @Override
    public void onLoadingComplete( String imageUri, View view , Bitmap loadedImage) {
        // Do whatever you want with Bitmap
    }
});

This approach is the simplest and crudest, but it also brings the most serious problems. If I write this way in dozens or hundreds of places, and one day, I heard that Facebook has released a magic tool Fresco, which wants to replace Android-Universal-Image-Loader, you will find that you need to madly change the code in dozens or hundreds of places, which is not only a lot of work, but also prone to errors. The reason for this is that there is a strong coupling between the project and the framework for loading images, but in fact, the project itself should not know which framework I use to load images.

The correct way should be to make an abstract encapsulation of the framework to cope with future changes. I will directly give an example of an encapsulation method in my own open source project AndroidAlbum.

AndroidAlbum

The general code is as follows:

 //1. Declare the ImageLoaderWrapper interface and define some abstract loading interface methods

public interface ImageLoaderWrapper {

    /** * Display image * * @param imageView ImageView that displays the image * @param imageFile Image file * @param option Display parameter settings */
    public void displayImage (ImageView imageView, File imageFile, DisplayOption option) ;

    /** * Display image * * @param imageView ImageView that displays the image * @param imageUrl URL of the image resource * @param option Display parameter settings */
    public void displayImage (ImageView imageView, String imageUrl, DisplayOption option) ;

    /** * Image loading parameters */
    public static class DisplayOption {
        /** * The resource id being loaded */
        public int loadingResId;
        /** * Resource id that failed to load */
        public int loadErrorResId;
    }
}

// 2. Encapsulate UniversalAndroidImageLoader into a UniversalAndroidImageLoader that inherits the ImageLoaderWrapper interface.
//The code here is a bit long. If you are interested, you can check the implementation in the project source code https://github.com/D-clock/AndroidAlbum

// 3. Make an ImageLoaderFactory

public class ImageLoaderFactory {

    private static ImageLoaderWrapper sInstance;

    private ImageLoaderFactory () {

    }

    /** * Get the image loader * * @return */
    public static ImageLoaderWrapper getLoader () {
        if (sInstance == null ) {
            synchronized (ImageLoaderFactory.class) {
                if (sInstance == null ) {
                    sInstance = new UniversalAndroidImageLoader(); //<link>https://github.com/nostra13/Android-Universal-Image-Loader</link>
                }
            }
        }
        return sInstance;
    }
}

//4. Make the following calls in all places where you need to load pictures

ImageLoaderWrapper loaderWrapper = ImageLoaderFactory.getLoader();
ImageLoaderWrapper.DisplayOption displayOption = new ImageLoaderWrapper.DisplayOption();
displayOption.loadingResId = R.mipmap.img_default;
displayOption.loadErrorResId = R.mipmap.img_error;
loaderWrapper.displayImage(imagview, url, displayOption);

In this way, the cost of switching frameworks will become very small, which is the benefit of not relying directly on the framework. Of course, the above is just my simple encapsulation, you can also do more detailed processing.

Summary: Reserve changes and do not couple strongly to third-party frameworks

4. From MVC to MVP

To be honest, before I came into contact with the MVP architecture, I had always used the MVC model for development. As the project grew larger, the code in the Activity or Fragment became more and more bloated, and I felt like vomiting when I read it, and I felt like shitting when I modified it... I will leave aside various other architectures here and only compare MVC and MVP.

  • View: layout xml file
  • Controller: Activity, Fragment, Dialog, etc.
  • Model: related business operations process data (such as operations on databases and networks should all be in the Model layer)

You will find that if the View layer only contains XML files, then we can't do much with the View layer in our Android project. At most, we can reuse the layout by using include. Activity is a peculiar thing. Although it belongs to the Controller layer, it actually does the work of the View layer (the initialization and related operations of the View are all in the Activity). It is this structure that is both a View and a Controller that violates the single responsibility principle and causes the bloated problem mentioned above in Activity.

  • View: Activity, Fragment, Dialog, Adapter, etc. This layer does not contain any business logic
  • Presenter: Intermediary, View and Model have no contact, all passed through Presenter
  • Model: related business operations process data (such as operations on databases and networks should all be in the Model layer)

Compared with MVC, MVP is more clear in terms of layer division, and there will not be a situation where one person has two roles (some unit testers will find that unit test cases are easier to write). Here you can see that the View and Model are unaware of each other's existence, which is more beneficial for dealing with changes. In many cases, the changes are in the View layer, while the changes in the Model layer are relatively few. After following the MVP structure development, it is not so painful to modify the code.
There are also some things to note here. Because a large number of interactive operations are concentrated in the Presenter layer, it is necessary to grasp the granularity of the Presenter. An Activity can hold multiple Views and Presenters, so that the problem of a huge View and Presenter can be avoided.

I recommend two good MVP architecture projects to you. If you don’t understand them yet, you can experience their design ideas by yourself:

https://github.com/pedrovgs/EffectiveAndroidUI
https://github.com/antoniolg/androidmvp

Summary: Let’s understand MVP in practice

5. Archive code

Categorize some commonly used tool classes or business process codes and add them to your own code library (those who don’t have their own personal code library can consider building one). Such as encryption and decryption, taking pictures, cropping pictures, getting the path of all pictures in the system, custom controls or animations, and other commonly used tool classes. Archiving helps improve your development efficiency and can be easily introduced and used when encountering new projects. If you want to better maintain your own code library, you might as well open source this private code library with detailed documentation without leaking company secrets. This can attract more developers to use these codes, and you can also get corresponding bug feedback, so as to locate and fix problems and enhance the stability of this warehouse code.

Summary: Archive code properly and maintain it as open source if possible

6. Performance Optimization

Regarding performance optimization, most of the focus is on the following aspects: memory, CPU, power consumption, lag, rendering, process survival rate, etc. There are already many answers on the Internet about performance optimization ideas and analysis methods in these areas, so I will not go into details here. I just want to say the following points:

  • Don’t optimize performance too early. Make the app usable first and then make it easy to use. Spending a lot of time on optimization before the requirements are met is putting the cart before the horse.
  • Optimization should be based on actual data and tested with the help of testing tools (such as: NetEase's Emmagee, Tencent's GT and APT, iFlytek's iTest, Google's Battery Historian). After all, when your boss asks you how much power consumption has been reduced compared to before, you can't just answer that it has been reduced a little, right?
  • Any method that does not reduce performance loss to keep the system alive is a hooligan approach.

Summary: Reasonable optimization and data quantification

7. Practice new technologies

After Rxjava, React Native, Kotlin ...began to rise, many developers around me followed suit. The spirit of learning new technologies is very worthy of encouragement, but it is inappropriate to introduce new technologies into commercial projects without a period of practical observation. For teams in large companies, there will be special teams or projects to study these emerging technologies to determine whether to introduce them into their own product line development. But as a small company, does it mean that there is no opportunity to try new technologies in practice? Not really! I have the following suggestions:

  • Use search engines to see if there are many pitfalls in this technology. If the reputation is good but there are many pitfalls, it means that the current technology is not mature and you can wait patiently for updates;
  • Consider the learning cost. If the learning cost is too high and it is difficult to recruit developers who understand this aspect, it is recommended not to introduce this technology;
  • Copy a project and open source it. If you want to introduce React Native for commercial development, it is best to copy an application and then open source it. In this way, some developers who are interested in RN will run your code and report bugs to you, which will help you know the pitfalls of some new technologies, find corresponding solutions, and finally decide whether to introduce the technology;
  • Lower the entry threshold. Try to document the process of practicing new technologies in detail, which will help lower the entry threshold for other colleagues in the project team. If possible, open source the learning documents to obtain more feedback from developers and correct some errors in the documents.
  • Combined with actual business. All new technologies must be considered whether they meet current business needs. I have heard that some programmers want to introduce new technologies because they think the technology is cool, and the Internet says it is very useful, and it is very... I have never used it myself, but I just follow the crowd. Sometimes I feel speechless, and I feel that using some technologies is like showing off;

Conclusion: Empty talk ruins a country, but hard work makes it prosperous

8.UML

UML is a powerful tool for taming code and understanding project structure. I am also on the road of learning and experiencing its benefits. No matter whether the project is big or small, with it, you can better sort out some context structures. It is absolutely a must-have for developers who deal with old large project codes or are interested in reading some open source project codes.

Summary: If you want to do your work well, you must first sharpen your tools

9. Make your own wheel

As mentioned in 2 above, a project cannot be started from scratch, and many third-party frameworks need to be introduced. This does not contradict 2, but suggests that developers who want to improve their technical skills can code and implement a framework in their spare time. If you have a lot of research insights on network access and image loading, you might as well implement these ideas in your mind into specific code. You may find that when you put your hands into practice, you will consider much more things, and you will get more in the end. ( Especially recommended for those who have read a lot of open source code but have not yet tried it themselves )

Summary: Don’t stop at the API call level

10. Expand the Tech Circle

When you have time and can afford it, you might as well attend some technical exchange meetings that you are interested in. Many of them have experts giving speeches. You can listen to their solutions and broaden your thinking about problems. You can also participate in more valuable online activities. I have many developer friends who I met at events. Sometimes when I encounter some technical problems, we will discuss and exchange solutions with each other. It's great!

Summary: Broaden your technical horizons

11. Write a blog summary

There is probably nothing much to say about this, and you will understand it after reading the title. Its biggest advantage is:

  • Systematically record your solutions;
  • It is convenient for you to review it later;
  • If there are any questions, readers will comment and give feedback to promote technical exchanges;
  • Improve your written expression skills;

Summary: Carefully summarize and continuously improve

12. Find a partner

Programmers should stop sitting in front of computers all the time and find a partner to improve their happiness. It is said that programmers with high happiness have high coding efficiency and are less likely to have bugs...

Summary: Be an object-oriented programmer

That’s about all I can think of. If I have something else to write, I’ll open a new chapter. I’ve written so much, but the most important thing is to implement it yourself. Don’t just hear too many truths but still not live a good life!

<<:  Aiti Tribe Stories (1): How a rookie transformed into a senior programmer

>>:  What Master brings to the world: Is it "out of control" or evolution?

Recommend

Profit as soon as you buy it: iPhone 13 depreciates 50% lower than iPhone 12

According to the latest report from SellCell (Int...

Disassembling 6 ways to play red envelopes in event marketing

Red envelopes are a value-added service provided ...

These "grapes" are free, but they can cost you your life!

In nature, there are many kinds of grapes that ar...

New media operation user growth skills!

Growth is from less to more. The root of all grow...

About domestic programmers climbing over the firewall

[[226521]] I originally had no inclination to dis...

Kobe Bryant endorses Ele.me, and it only takes five steps to pass the level!

These days, Kris Wu is the spokesperson for Honor...

Is "Shake" the peacemaker between TV and the Internet?

The 2015 Lunar New Year was a little later than u...

VIVO App Store Application Submission Process

Application Submission Process 1. Create an appli...

Hu Chao - The Road to a Sales Master

Hu Chao - Road to Sales Master Resource Introduct...

iOS 9 new features revealed, artificial intelligence becomes another highlight

According to the US technology blog 9to5Mac, sour...

Briefly talk about 20 laws of brand communication

Once the defense is broken, it will kill instantl...

Operators should use VoLTE to compete with WeChat Phonebook

Operators invest hundreds of billions of yuan eve...