第一次嘗試——使用Retrofit+Dagger架構一個拿來就可以使用的Android空項目

    剛開始來公司的時候,接手了兩個項目,兩個項目的架構是用的同一個,雖然做了一些封裝,但在我這個菜鳥的眼裏,也覺得不好,單其中一個項目在不久後就上線了,因爲百分之八十以上的頁面在我來之前就寫好了,而且之前也上傳了幾個版本了,在這種情況下,雖然後來的擴展和修改bug讓我很頭疼,也還是沒有想着做一些改變。另外一個項目至今沒有上線,還有一些東西沒有完成,而另一個開發者又離職了,UI給我列出來一大堆要改的頁面和邏輯,在縫縫補補做了半個月的時候,我終於終於沒辦法忍受,於是毅然決定重構整個項目,哦,不對,是重新做這個項目。

    那麼,既然重新做,就不能用之前的架構了,縫縫補補太痛苦,所以開始了這篇博客的主題所指,當然,在我這個閱歷下,能想到的封裝思路和能夠封裝的程度都是有限的,只是給初級的開發者一些參考,大神,請繞步。。。

一、網絡加載

    首先,選擇網絡加載框架,恩,之前就一直聽說Retrofit,是最近非常流行的一個框架,但是一直沒有機會自己來好好玩一次,所以在研究了一段時間之後毅然決定就它了。因爲自己研究的程度目前還不能給大家分析,所以,詳情請看下後面的代碼吧!如果你都還沒聽說過,就去看看官方文檔,這個不是今天的重點。

二、圖片加載

    然後就是圖片加載框架,現在流行的有三大圖片框架:

        1)    Picasso

        2)    Glide

        3)    Fresco

    當然,ImageLoader是歷史舞臺的大佬,不過我好久沒用過了。。。

    先簡單的介紹下這三個框架:

    Picasso :和Square的網絡庫一起能發揮最大作用,因爲Picasso可以選擇將網絡請求的緩存部分交給了okhttp實現。

    Glide:模仿了Picasso的API,而且在他的基礎上加了很多的擴展(比如gif等支持),Glide默認的Bitmap格式是RGB_565,比    Picasso默認的ARGB_8888格式的內存開銷要小一半;Picasso緩存的是全尺寸的(只緩存一種),而Glide緩存的是跟ImageView尺寸相同的(即56*56和128*128是兩個緩存) 。

    FB的圖片加載框架Fresco:最大的優勢在於5.0以下(最低2.3)的bitmap加載。在5.0以下系統,Fresco將圖片放到一個特別的內存區域(Ashmem區)。當然,在圖片不顯示的時候,佔用的內存會自動被釋放。這會使得APP更加流暢,減少因圖片內存佔用而引發的OOM。爲什麼說是5.0以下,因爲在5.0以後系統默認就是存儲在Ashmem區了。

    再看下三者的比較:

    Picasso所能實現的功能,Glide都能做,無非是所需的設置不同。但是Picasso體積比起Glide小太多如果項目中網絡請求本身用的就是okhttp或者retrofit(本質還是okhttp),那麼建議用Picasso,體積會小很多(Square全家桶的幹活)。Glide的好處是大型的圖片流,比如gif、Video,如果你們是做美拍、愛拍這種視頻類應用,建議使用。

    Fresco在5.0以下的內存優化非常好,代價就是體積也非常的大,按體積算Fresco>Glide>Picasso,不過在使用起來也有些不便(小建議:他只能用內置的一個ImageView來實現這些功能,用起來比較麻煩,我們通常是根據Fresco自己改改,直接使用他的Bitmap層)

    因爲使用了retrofit,再加上本應用對圖片的要求不高,所以我們這裏最完美的選擇就是Picasso了,那就決定了,就用它。

三、其他

    做完了這兩個選擇後,接下來要考慮的事情是對基類的封裝。當然最基礎的基類有BaseApplication,BaseActivity和BaseFragment三個,對於BaseApplication的話,我沒有做太多的處理,現在想到一個對網絡狀態進行監聽的方法,然後在當網絡由不可用轉爲確實可用的時候,發送一個消息給所有加載失敗的頁面,重新加載數據,這個在我寫完這篇博客後會加上去的。

    BaseActivity和的ParentActivity封裝

    至於ParentActivity是幹嘛的?因爲我需要在BaseActivity中封裝好對錯誤頁面,未加載完成的頁面,加載成功後的頁面和對標題欄等的一些頁面的處理,但是很多頁面其實是不需要加載網絡的,所以不需要加載錯誤,未加載完成的頁面,他只需要直接顯示出來一些界面就好,所以ParentActivity就誕生了,在這個類裏面,就是單單的做了除了與View有關的其他所有操作。

    ParentActivity.java

    

  1. /**
  2. * Created by cretin on 16/10/27.
  3. */
  4. public abstract class ParentActivity extends AppCompatActivity {
  5.    //記錄下所有的Activity
  6.    public final static List<ParentActivity> mActivities = new LinkedList<ParentActivity>();
  7.    public static boolean isKitkat;
  8.    public static ParentActivity mActivity;
  9.    @Override
  10.    protected void onCreate(@Nullable Bundle savedInstanceState) {
  11.        super.onCreate(savedInstanceState);
  12.        getSupportActionBar().hide();
  13.        synchronized (mActivities) {
  14.            mActivities.add(this);
  15.        }
  16.        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  17.            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  18.            isKitkat = true;
  19.        }
  20.        initView(null);
  21.    }
  22.    protected abstract void initView(View view);
  23.    @Override
  24.    protected void onResume() {
  25.        super.onResume();
  26.        mActivity = this;
  27.    }
  28.    @Override
  29.    protected void onPause() {
  30.        super.onPause();
  31.        mActivity = null;
  32.    }
  33.    @Override
  34.    protected void onDestroy() {
  35.        super.onDestroy();
  36.        synchronized (mActivities) {
  37.            mActivities.remove(this);
  38.        }
  39.        ButterKnife.unbind(this);
  40.    }
  41. }

    在上面的代碼中,首先定義了一個List<ParentActivity> mActivities的集合,用於存儲所有的已打開的Activtiy,便於以後統一的去處理和查詢;還定義了一個public static boolean isKitkat;這個是用來記錄當前Android版本支不支持沉浸式狀態欄,如果支持,直接使用沉浸式狀態欄;還有一個抽象方法initView(null);是用來暴露給用戶,讓他去處理View相關的事情,但是由於ParentActivity沒有處理View相關的操作,所以傳入了null;在onDestroy方法裏面,移除掉了當前的Activity,並且ButterKnife.unbind(this);由於整個架構默認使用ButterKnife來對View進行綁定,所以在退出的時候主動unbind掉,免得每個子類都要各自去處理。

    在BaseActivity裏面,就需要處理上面ParentActivity沒有能處理的事情,所以BaseActivity是繼承自ParentActivity的。

具體如下:

BaseActivity.java

  1. package com.cretin.www.createnewprojectdemo.base;
  2. import android.graphics.Color;
  3. import android.graphics.drawable.AnimationDrawable;
  4. import android.os.Bundle;
  5. import android.text.TextUtils;
  6. import android.view.View;
  7. import android.widget.ImageView;
  8. import android.widget.RelativeLayout;
  9. import android.widget.TextView;
  10. import com.cretin.www.createnewprojectdemo.R;
  11. import com.cretin.www.createnewprojectdemo.utils.ViewUtils;
  12. import com.cretin.www.createnewprojectdemo.view.CustomProgressDialog;
  13. import butterknife.ButterKnife;
  14. import retrofit2.Call;
  15. import retrofit2.Callback;
  16. import retrofit2.Response;
  17. import rx.Subscription;
  18. import rx.subscriptions.CompositeSubscription;
  19. /**
  20. * Created by cretin on 16/10/27.
  21. * 如果是需要處理自己的邏輯 則繼承這個
  22. * 如果只是給加載Fragment提供一個容器 則繼承ParentActivity
  23. */
  24. public abstract class BaseActivity extends ParentActivity {
  25.    private CustomProgressDialog dialog;
  26.    private OnTitleAreaCliclkListener onTitleAreaCliclkListener;
  27.    private TextView tvMainTitle;
  28.    private ImageView ivMainBack;
  29.    private ImageView ivMainRight;
  30.    private TextView tvMainRight;
  31.    private RelativeLayout relaLoadContainer;
  32.    private TextView tvLoadingMsg;
  33.    private ImageView ivBack;
  34.    private CompositeSubscription mCompositeSubscription;
  35.    protected void addSubscription(Subscription s) {
  36.        if ( this.mCompositeSubscription == null ) {
  37.            this.mCompositeSubscription = new CompositeSubscription();
  38.        }
  39.        this.mCompositeSubscription.add(s);
  40.    }
  41.    @Override
  42.    protected void onCreate(Bundle savedInstanceState) {
  43.        super.onCreate(savedInstanceState);
  44.        View view = getLayoutInflater().inflate(R.layout.layout_base_activity, null);
  45.        setContentView(view);
  46.        initHeadView(view);
  47.        initContentView(view);
  48.        if ( isKitkat ) {
  49.            view.findViewById(R.id.ll_main_title).setPadding(0, ViewUtils.getStatusBarHeights(), 0, 0);
  50.        }
  51.        initData();
  52.        initEvent();
  53.    }
  54.    private AnimationDrawable animationDrawable;
  55.    private void initContentView(View view) {
  56.        RelativeLayout container = ( RelativeLayout ) view.findViewById(R.id.main_container);
  57.        relaLoadContainer = ( RelativeLayout ) view.findViewById(R.id.load_container);
  58.        tvLoadingMsg = ( TextView ) view.findViewById(R.id.loading_msg);
  59.        ImageView imageView = ( ImageView ) view
  60.                .findViewById(R.id.loading_image);
  61.        animationDrawable = ( AnimationDrawable ) imageView
  62.                .getBackground();
  63.        animationDrawable.start();
  64.        View v = getLayoutInflater().inflate(getContentViewId(), null);
  65.        ButterKnife.bind(this, v);
  66.        container.addView(v);
  67.        initView(v);
  68.    }
  69.    //onResponse子類去實現
  70.    public abstract class ResultCall<T> implements Callback<T> {
  71.        @Override
  72.        public void onResponse(Call<T> call, Response<T> response) {
  73.            hidProgressView();
  74.            onResponse(response);
  75.        }
  76.        protected abstract void onResponse(Response<T> response);
  77.        @Override
  78.        public void onFailure(Call<T> call, Throwable t) {
  79.            showErrorView();
  80.            onError(call, t);
  81.        }
  82.        protected abstract void onError(Call<T> call, Throwable t);
  83.    }
  84.    //隱藏正在加載視圖
  85.    public void hidProgressView() {
  86.        if ( relaLoadContainer != null )
  87.            relaLoadContainer.setVisibility(View.GONE);
  88.        if ( animationDrawable != null )
  89.            animationDrawable.stop();
  90.    }
  91.    //顯示正在加載視圖
  92.    public void showProgressView() {
  93.        if ( relaLoadContainer != null && relaLoadContainer.getVisibility() == View.GONE )
  94.            relaLoadContainer.setVisibility(View.VISIBLE);
  95.        if ( animationDrawable != null )
  96.            animationDrawable.start();
  97.    }
  98.    //隱藏返回按鈕
  99.    public void hidBackIv() {
  100.        if ( ivBack != null && ivBack.getVisibility() == View.VISIBLE )
  101.            ivBack.setVisibility(View.GONE);
  102.    }
  103.    //顯示加載錯誤
  104.    public void showErrorView() {
  105.        if ( relaLoadContainer != null && relaLoadContainer.getVisibility() == View.GONE )
  106.            relaLoadContainer.setVisibility(View.VISIBLE);
  107.        if ( animationDrawable != null )
  108.            animationDrawable.stop();
  109.        tvLoadingMsg.setText("加載錯誤");
  110.    }
  111.    //初始化頭部視圖
  112.    private void initHeadView(View view) {
  113.        tvMainTitle = ( TextView ) view.findViewById(R.id.tv_title_info);
  114.        ivMainBack = ( ImageView ) view.findViewById(R.id.iv_back);
  115.        ivMainRight = ( ImageView ) view.findViewById(R.id.iv_right);
  116.        tvMainRight = ( TextView ) view.findViewById(R.id.tv_right);
  117.        ivBack = ( ImageView ) view.findViewById(R.id.iv_back);
  118.        ivMainBack.setOnClickListener(new View.OnClickListener() {
  119.            @Override
  120.            public void onClick(View v) {
  121.                finish();
  122.                if ( onTitleAreaCliclkListener != null )
  123.                    onTitleAreaCliclkListener.onTitleAreaClickListener(v);
  124.            }
  125.        });
  126.        ivMainRight.setOnClickListener(new View.OnClickListener() {
  127.            @Override
  128.            public void onClick(View v) {
  129.                if ( onTitleAreaCliclkListener != null )
  130.                    onTitleAreaCliclkListener.onTitleAreaClickListener(v);
  131.            }
  132.        });
  133.        tvMainRight.setOnClickListener(new View.OnClickListener() {
  134.            @Override
  135.            public void onClick(View v) {
  136.                if ( onTitleAreaCliclkListener != null )
  137.                    onTitleAreaCliclkListener.onTitleAreaClickListener(v);
  138.            }
  139.        });
  140.    }
  141.    /**
  142.     * 顯示加載對話框
  143.     *
  144.     * @param msg
  145.     */
  146.    public void showDialog(String msg) {
  147.        if ( dialog == null ) {
  148.            dialog = CustomProgressDialog.createDialog(this);
  149.            if ( msg != null && !msg.equals("") ) {
  150.                dialog.setMessage(msg);
  151.            }
  152.        }
  153.        dialog.show();
  154.    }
  155.    /**
  156.     * 關閉對話框
  157.     */
  158.    public void stopDialog() {
  159.        if ( dialog != null && dialog.isShowing() ) {
  160.            dialog.dismiss();
  161.        }
  162.    }
  163.    public void setOnTitleAreaCliclkListener(OnTitleAreaCliclkListener onTitleAreaCliclkListener) {
  164.        this.onTitleAreaCliclkListener = onTitleAreaCliclkListener;
  165.    }
  166.    //設置Title
  167.    protected void setMainTitle(String title) {
  168.        if ( !TextUtils.isEmpty(title) )
  169.            tvMainTitle.setText(title);
  170.    }
  171.    //設置TitleColor
  172.    protected void setMainTitleColor(String titleColor) {
  173.        if ( !TextUtils.isEmpty(titleColor) )
  174.            setMainTitleColor(Color.parseColor(titleColor));
  175.    }
  176.    //設置TitleColor
  177.    protected void setMainTitleColor(int titleColor) {
  178.        tvMainTitle.setTextColor(titleColor);
  179.    }
  180.    //設置右邊TextView顏色
  181.    protected void setMainTitleRightColor(int tvRightColor) {
  182.        tvMainRight.setTextColor(tvRightColor);
  183.    }
  184.    //設置右邊TextView顏色
  185.    protected void setMainTitleRightColor(String tvRightColor) {
  186.        if ( !TextUtils.isEmpty(tvRightColor) )
  187.            setMainTitleRightColor(Color.parseColor(tvRightColor));
  188.    }
  189.    //設置右邊TextView大小
  190.    protected void setMainTitleRightSize(int size) {
  191.        tvMainRight.setTextSize(size);
  192.    }
  193.    //設置右邊TextView內容
  194.    protected void setMainTitleRightContent(String content) {
  195.        if ( !TextUtils.isEmpty(content) ) {
  196.            if ( tvMainRight.getVisibility() == View.GONE )
  197.                tvMainRight.setVisibility(View.VISIBLE);
  198.            tvMainRight.setText(content);
  199.        }
  200.    }
  201.    //設置左邊ImageView資源
  202.    protected void setMainLeftIvRes(int res) {
  203.        if ( ivMainBack.getVisibility() == View.GONE )
  204.            ivMainBack.setVisibility(View.VISIBLE);
  205.        ivMainBack.setImageResource(res);
  206.    }
  207.    //設置又邊ImageView資源
  208.    protected void setMainRightIvRes(int res) {
  209.        if ( ivMainRight.getVisibility() == View.GONE )
  210.            ivMainRight.setVisibility(View.VISIBLE);
  211.        ivMainRight.setImageResource(res);
  212.    }
  213.    interface OnTitleAreaCliclkListener {
  214.        void onTitleAreaClickListener(View view);
  215.    }
  216.    protected abstract void initData();
  217.    protected abstract int getContentViewId();
  218.    protected void initEvent() {
  219.    }
  220.    @Override
  221.    protected void onDestroy() {
  222.        super.onDestroy();
  223.        ButterKnife.unbind(this);
  224.        if ( this.mCompositeSubscription != null ) {
  225.            this.mCompositeSubscription.unsubscribe();
  226.        }
  227.    }
  228. }


layouy_base_activity.xml:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.    xmlns:tools="http://schemas.android.com/tools"
  4.    android:layout_width="match_parent"
  5.    android:layout_height="match_parent"
  6.    android:orientation="vertical">
  7.    <LinearLayout
  8.        android:id="@+id/ll_main_title"
  9.        android:layout_width="match_parent"
  10.        android:layout_height="wrap_content"
  11.        android:background="@color/white"
  12.        android:orientation="vertical">
  13.        <RelativeLayout
  14.            android:layout_width="match_parent"
  15.            android:layout_height="wrap_content">
  16.            <ImageView
  17.                android:id="@+id/iv_back"
  18.                android:layout_width="wrap_content"
  19.                android:layout_height="wrap_content"
  20.                android:layout_centerVertical="true"
  21.                android:layout_marginLeft="5dp"
  22.                android:clickable="true"
  23.                android:src="@mipmap/arrow_left"/>
  24.            <TextView
  25.                android:id="@+id/tv_title_info"
  26.                android:layout_width="wrap_content"
  27.                android:layout_height="wrap_content"
  28.                android:layout_centerInParent="true"
  29.                android:padding="13dp"
  30.                android:textColor="@color/font_black3"
  31.                android:textSize="@dimen/text_size_17"
  32.                tools:text="標題" />
  33.            <TextView
  34.                android:id="@+id/tv_right"
  35.                android:layout_width="wrap_content"
  36.                android:layout_height="wrap_content"
  37.                android:layout_alignParentRight="true"
  38.                android:layout_centerInParent="true"
  39.                android:layout_marginRight="5dp"
  40.                android:clickable="true"
  41.                android:drawablePadding="5dp"
  42.                android:textColor="@color/font_black3"
  43.                android:textSize="@dimen/text_size_17"
  44.                android:visibility="gone"
  45.                tools:text="修改" />
  46.            <ImageView
  47.                android:id="@+id/iv_right"
  48.                android:layout_width="wrap_content"
  49.                android:layout_height="wrap_content"
  50.                android:layout_alignParentRight="true"
  51.                android:layout_centerVertical="true"
  52.                android:layout_marginRight="5dp"
  53.                android:visibility="gone"
  54.                tools:src="@mipmap/ic_launcher" />
  55.        </RelativeLayout>
  56.        <include layout="@layout/line" />
  57.    </LinearLayout>
  58.    <RelativeLayout
  59.        android:id="@+id/main_container"
  60.        android:layout_width="match_parent"
  61.        android:layout_height="match_parent"
  62.        android:layout_below="@+id/ll_main_title" />
  63.    <RelativeLayout
  64.        android:id="@+id/load_container"
  65.        android:layout_width="match_parent"
  66.        android:layout_height="match_parent"
  67.        android:layout_below="@+id/ll_main_title"
  68.        android:background="@color/white">
  69.        <LinearLayout
  70.            android:layout_width="120dip"
  71.            android:layout_height="120dip"
  72.            android:layout_centerInParent="true"
  73.            android:gravity="center"
  74.            android:orientation="vertical">
  75.            <ImageView
  76.                android:id="@+id/loading_image"
  77.                android:layout_width="wrap_content"
  78.                android:layout_height="wrap_content"
  79.                android:layout_gravity="center_vertical|center_horizontal"
  80.                android:background="@drawable/load_progress_bar" />
  81.            <TextView
  82.                android:id="@+id/loading_msg"
  83.                android:layout_width="wrap_content"
  84.                android:layout_height="wrap_content"
  85.                android:layout_gravity="center_vertical|center_horizontal"
  86.                android:padding="10dip"
  87.                android:text="正在加載..."
  88.                android:textSize="12sp" />
  89.        </LinearLayout>
  90.    </RelativeLayout>
  91. </RelativeLayout>

     先看上面的佈局文件,分爲兩個大的部分,一個是標題欄,一個是內容區域,標題欄左邊有一個默認的返回ImageView,中間是一個TextView,用於顯示標題,右邊有一個TextView和一個ImageView,TextView用來顯示比如修改的操作,ImageView用來顯示設置什麼的圖標,默認左邊的返回按鈕個標題欄可見狀態,右邊兩個都是隱藏的,因爲用到他們的機會還是挺少的。在內用區域,有一個顯示內容的佈局,到時候用來顯示需要加載的佈局,還有一個正在加載的佈局,用來顯示正在加載中。。這個可自己去根據需求定製,這個頁面也可以作爲加載失敗的頁面,根據需求來就可以,當這個界面的網絡加載完成之後,就可以主動的隱藏掉這個正在加載的頁面就可以了,用戶體驗相對也會好一點。

    然後來看下BaseActivity中的操作,首先,我們避免寫findViewById的操作,所以我們在BaseActivity中封裝好了對ButterKnife的bind和unbind操作,這樣在子類中就只需要簡單的操作就行,不需要再bind和unbind了,然後提供了一系列的對標題欄自定義的操作,比如設置標題內容,文字大小顏色,設置標題欄右邊的圖標的資源。。等等,這些根據需求,不夠的還可以自己再自行添加就好;還有在前面我們判斷了Android版本是否支持沉浸式狀態欄,如果支持的話,我在BaseActivity中也對標題欄進行了setPadding的操作,因爲不設置的話,標題會跟狀態欄的文字重疊,就會比較難看,這種操作不需要子類來理會,所以封裝出來會比較好;另外我還提供了一個比較方便的的方法,就是showDialog和stopDialog的操作,當頁面需要二次請求網路的時候,顯示showDialog,加載完就stopDialog即可,這樣用戶體驗就會好一點;還有一個很大的點就是對網絡請求的封裝,這個因爲我現在對Retrofit還不是非常熟練,所以只進行了簡單的封裝,到時候經過再研究之後,再來進行完善!在目前的代碼中,我寫了一個抽象方法,在抽象方法中對請求的響應做出一個初級的判斷,如果請求是成功的,並且數據的返回也是正常的,那麼回調給調用者,否則直接顯示網絡加載錯誤的頁面,統一的對網絡錯誤進行處理,不過,這個要能真正完美的使用,需要後臺不要太差。。不然老是返回亂七八糟的錯誤給你,就不太好統一處理了。。到此,BaseActivity的處理也要到此爲止了。

    BaseFragment的封裝

    對於BaseFragment來說,其封裝跟BaseActtivity是一模一樣的,本質的差別也就是一個是Activity一個是Fragment,所以就不再贅述了。

    BaseFragmentActivity和BackFragmentActivity的封裝

    爲什麼會有這兩個類的存在?我現在比較喜歡的一種加載界面方式是使用Fragment碎片化的方式,就是開一個Activity,這個Activity就是承載Fragment的一個容器,所以這個Activity啥都不做,就只作用於添加Fragment,顯然,這個Activity是不需要加載網絡和一些其他操作的,所以我把他們倆都是集成自ParentActivity,這個具體看下項目中的操作。看這兩個類的名字也很清楚,繼承BaseFragmentActivity的時候,代表要加載的Fragment是不需要假如回退棧的,繼承BackFragmentActivity的時候,代表要加載的Fragment是需要假如回退棧的,當然,在計入Fragment的時候,也可以使用動畫,具體的使用,看Demo就好,在此不再贅述了,代碼什麼的還是要自己看,理解才快。


工具類

    最後再來說下項目中默認添加使用的一些其他好用的東西:

    本地數據的存儲:Hawk 

    這個工具是當年一個叫Calvin的大哥告訴我的,一用起來就愛不釋手。

    Hawk 是一個非常便捷的數據庫  . 操作數據庫只需一行代碼 , 能存任何數據類型 .

    github 地址: https://github.com/orhanobut/hawk

    Hawk 是一個簡單的  key-value  數據庫

    它使用: 

    AES 加密

    能選擇使用SharedPreferences  或者  SQLite

       Gson解析

    提供:

    安全數據持久化

    能存儲任何類型

    具體的使用,大家去Github上去看吧,相信只要你用過你就會喜歡上他的,信我。

    Android事件總線:EventBus

    這個不多說,已經非常成熟了。簡單介紹下

    實際項目開發過程中,經常遇到如下場景:不同的應用程序組件的控件間具有一定的相互關聯性,其中用戶對後者進行的某種操作會引起前者的相應改變。舉一個具體的場景:以糗事百科爲例,在糗事列表頁和詳情頁頁,對於每個糗事而言,佈局基本一致,在詳情頁點擊了個贊,讚的數量增加,同時讚的圖標發生了變化,此時返回到列表頁,此糗事上的贊圖標以及數量與剛剛詳情頁的需要保持一致。在舉一個例子,對於多個底部導航tab下的資訊類閱讀app,在諮詢詳情頁點擊了收藏,然後收藏成功,此時回到底部tab中的個人中心,假如個人中心中有我的收藏,同時後面顯示的是收藏數量,此時此收藏數量需要同於於剛剛用戶所進行的收藏/取消收藏而即時更改數字。凡此種種,類似需求場景非常常見。

    有時候,當此類需求相對簡單時,通過接口以實現回調等方式可以完成,但是當不同組件/控件之間的關係紛繁複雜時,基於接口的方案不僅使得代碼非常繁瑣,同時是的程序邏輯很混亂,基於此,EventBus,爲此類需求的實現提供了非常方便的方案。

    butterknife註解框架的偷懶插件

    這個也不多說,已經非常成熟了。簡單介紹下

    事實上這是個Android Studio的plugin,他可以讓你在添加Butterkinfe註解時偷偷懶,直接點擊幾下鼠標既可以完成註解的增加,同時還是圖形化的操作,可以說,大大的減輕了開發負擔。尤其是當你的layout中有很多很多的view需要通過findviewbyid來獲得引用時。實際上如果不用這個插件而通過手打加ButtefKnife註解的方式,要是view很多啓示也挺麻煩的,不是嗎?


    到此這篇博客也就到了尾聲了,可能有很多地方還不是很準確,希望大家多提提意見,而且,這個封裝也還很基礎,希望大佬有時間看下,多提提意見和建議,再次謝過了。如果覺得不是太爛,記得Star一下哦。

    

    我是Cretin,一個可愛的小男孩。

    下面是Github的地址:

    https://github.com/MZCretin/CreateNewProjectDemo


發佈了61 篇原創文章 · 獲贊 65 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章