A summary of the use of generics in Android in actual projects

Keywords: Android Java network PHP

Preface

Why summarize the use of generics? How does generics represent value in a project? Don't talk about it. Summarize it. From practice to theory, finally return to generic nature.

1. What is generics? Why generics?

Definition:

Generics: the "broad data type", any data type.

Effect:

  • Generics can solve the security problem of data types. The main principle of generics is to represent the type of a property in a class or the return value and parameter type of a method through an identifier when a class is declared
  • In development, it is often used for code abstraction and encapsulation to make it tool and general. It can effectively reduce the code redundancy and make the code more readable.

In the ArrayList source code, you can find the use of generics everywhere.

public class ArrayList<E> extends AbstractList<E>
   
 public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
            add(index++, e);
            modified = true;
        }
        return modified;
    }

Note:

  • Generics are usually represented by < > and a capital letter, while there are four ways commonly used, namely < T >, <? >, < extends Object >, < super Object >.

    • In which, T represents the same type, and T represents the same type,? Represents any type, < extends xx > represents type xx, and the child of type xx <? Super xx > represents type xx, and the parent of type xx.
    • Class < T >: when instantiating, you need to specify a specific type Class <? >: can represent all types.
  • It is not recommended to use such a wonderful way of definition as < g >, < Q >.
  • Generics cannot use basic data types, such as int, double, etc., but only their container classes, such as Integer, double, etc. Because Java's generics are implemented by type erasure, and objects are used at runtime, and basic data types are not inherited from objects, so they cannot be used in generics.
  • out and in in Kotlin

    Like Java generics, generics in Kolin are immutable.

    • Using the keyword out to support covariance is equivalent to the upper bound wildcard "extends" in Java.

      Foo<? extends Bar>CorrespondingFoo<out Bar!>!

    • Using the keyword in to support inversion is equivalent to the lower bound wildcard super in Java.

      Foo<? supter Bar >CorrespondingFoo<in Bar!>!

2. Usage scenarios in Android

2.1 use change of findviewbyid

 /**
     * FindViewById Reduce strong conversion code
     */
    public <T extends View> T findViewById(@IdRes int id) {
        return getDelegate().findViewById(id);
    }

//Before use:
 Button btnReload =(Button) findViewById(R.id.btn_reload);
//Now:
 Button btnReload =  findViewById(R.id.btn_reload);

After the continuous iteration of Android version, it must be forced to convert from the beginning to the later when the generic encapsulation has been implemented internally. Of course, now that Kotlin is popular, this step can be omitted directly.

2.2 BaseAdapter implements the encapsulated Adapter

When ListView is widely used, we usually encapsulate an Adapter like this.

public abstract class CommonAdapter<T> extends BaseAdapter {
    protected LayoutInflater mLayoutInflater;
    protected List<T> mDatas;
    protected Context mContext;

    public CommonAdapter(Context mContext) {
        this.mContext = mContext;
    }
    public CommonAdapter(List<T> mDatas, Context mContext) {
        this.mDatas = mDatas;
        this.mContext = mContext;
    }

    public CommonAdapter(LayoutInflater mLayoutInflater, List<T> mDatas, Context mContext) {
        this.mLayoutInflater = mLayoutInflater;
        this.mDatas = mDatas;
        this.mContext = mContext;
    }

    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public T getItem(int position) {
        return mDatas.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public abstract View getView(int position, View convertView, ViewGroup parent);
}

When RecycleView was born, we can use generics in this way. For details, see the summary of the use of RecycleView in this article, Click to go

The Adapter usually needs to accept a data or collection, but the data type is uncertain, so it's natural for scenarios like this to use generics because they want to accept a wide range of data types. Generality is one of the benefits of generics.

2.3 network request data

In development, the json data returned when the network requests data is generally long, such as returning a user information:

      "code": 0,
      "message": "success",
      "data": {
        "token": "pbGUiLCJuYmYiOjE1NzI4NTg0NjIsInN1YiI6IjMxNDQifQ.YJ2A1wl2Jo9hbyRfkMlthoMkhfuKtlZh0vrkgi-rPpw",
        "uid": "a41b3bb3e6b050b6c915",
        "phone": "13908213909",
        "name": "Little lamb said",
        "shopName": "Chengdu Yintai City",
        "authTrueName": 1
      }
    }

Or return a grouping information:

       "code": 0,
      "message": "Success",
      "data": {
        "groups": [
          {
            "name": "I love you China",
            "count": 12,
            "groupId": 116
          },      
    
          {
            "name": "One born with a silver spoon in one's mouth",
            "count": 1,
            "groupId": 97
          },
          {
            "name": "Tall, rich and handsome",
            "count": 2,
            "groupId": 96
          },
          {
            "name": "Undefined group",
            "count": 21886,
            "groupId": -1
          }
        ],
        "linkman": "Valuable"
      }
    }
        

The key values in the code, message and data fields are the same, which can be understood as the common basic data is the same, no matter what data the server returns, these are the same.

Only the data in data is different, which can be understood as different demand data.

Once we find the common return information, we can start to generalize the encapsulation. BaseBean is to encapsulate the basic data.

First, encapsulate the generic BaseBean:

public class BaseBean<T> {
    public int code;
    public String message;
    public T data;

    @Override
    public String toString() {
        return "code: " + code +
                "\nmessage: " + message +
                "\ndata: " + data;
    }
}

It's much more convenient to use.


//Such as the implementation class in the detection version information
public class VersionBean extends BaseBean<VersionBean.DataBean> {

    public static class DataBean {
        public String appname; //App application name
        public String detailhtml; //Update details
        public String downloadurl;//Channel download address
        public String downloadurl_common; //Universal download address standby
        public String detail; //Update details
        public String updatetime;
        public String version; //Version name as version "1.1.2"
        public int versionCode;//Version No. every upgrade
        public int isforceupdate; //Do you want to force upgrade as 0 normal upgrade 1 forced upgrade

    }
}

//Such as entity class in the list returned by multiple keywords
public class KeywordBean extends BaseBean<List<KeywordBean.KeyWord>> {
    public static class KeyWord {
        public int id;
        public String title;
    }
}

At the same time, modify the returned data type in combination with the RxJava+Retrofit request interface:

    @GET("getAppVersion.php")
    Observable<VersionBean> checkVersion(@Query("deviceType") int deviceType,
                                         @Query("channel") String channel,
                                         @Query("versionCode") int versionCode);
    @GET("keyWords.php")
    Observable<KeywordBean> keyWord();

The generic simple examples in network requests are introduced here first. For specific use, please refer to my previous summary, Click to go

2.4 other application scenarios

For example, MVP architecture is used in the development, which will also be used. It's important to be familiar with generics.

How to use generics and abstractions to optimize the structure of MVP has become the key to make good use of MVP. Of course, we can abstract some common models and presenters through generic parameters and abstract parent classes. This should be the essence of using MVP architecture.

3. summary

Generics are widely used in development and will be updated in the future.

Extended reading:

1. The generics of Kotlin

2. Analysis of Google's official MVP architecture

Posted by baselinej on Tue, 05 Nov 2019 02:15:53 -0800