1. 程式人生 > >Android Dagger2(二)原始碼分析-物件是如何被注入的

Android Dagger2(二)原始碼分析-物件是如何被注入的

分析的原始碼是基於Android Dagger2(一) 基本使用 的例子來分析物件是如何被注入的. 如果還沒看上一篇文章, 可以先去看看.

在分析原始碼之前, 先理一理類與類之間的依賴關係 :

public class AddMenuBalanceFragment extends BaseFragment{
    @Inject
    AddMenu BalancePresenter presenter;
}

從上面的程式碼可以看出 AddMenuBalanceFragment需要注入AddMenuBalancePresenter

Dagger2要想注入AddMenuBalancePresenter

, 必須呼叫AddMenuBalancePresenter的構造方法:

public class AddMenuBalancePresenter implements AddMenuBalanceContract.Presenter {

    private final AddMenuBalanceContract.View mView;

    private final MenuBalanceRepository mMenuBalanceRepository;

    @Inject
    AddMenuBalancePresenter(AddMenuBalanceContract.View view, MenuBalanceRepository mMenuBalanceRepository) {
        this
.mView = view; this.mMenuBalanceRepository = mMenuBalanceRepository; } }

AddMenuBalancePresenter的構造方法又依賴ViewMenuBalanceRepository, 這裡的View就是Activity或者Fragment, 這個不能是我們new出來的,因為所有的介面都是由Android系統來建立和銷燬的. 所以這個引數只能我們通過傳遞引數的方式傳遞給Dagger2.

要想提供MenuBalanceRepository Dagger2就必須要呼叫MenuBalanceRepository

的構造方法 :

@Singleton
public class MenuBalanceRepository implements IMenuBalanceSource {

    private final IMenuBalanceSource remoteSource;

    @Inject
    MenuBalanceRepository(@Remote IMenuBalanceSource remoteSource) {
        this.remoteSource = remoteSource;
    }
}

發現MenuBalanceRepository的構造方法又依賴IMenuBalanceSource.

它們的依賴關係可以用下圖來表示:

這裡寫圖片描述

通過面的圖得知, 只要把IMenuBalanceSource構造出來了, MenuBalanceRepository也就可以構造出來了, 如果MenuBalanceRepositoryView都有了就可以把AddMenuBalancePresenter構造出來了.

這樣AddMenuBalanceFragment所需要的AddMenuBalancePresenter也就被注入了.

下面就分析下Dagger2生成的原始碼, 看看這些依賴到底是怎麼被注入的.

我們分析原始碼的不能一下子扎進原始碼堆裡不能自拔, 那麼分析原始碼該如何下手, 我覺得應該從使用它的地方入手. 比如Dagger2, 使用它的地方也就是觸發依賴注入的地方:

public class AddMenuBalanceFragment extends BaseFragment{
    @Inject
    AddMenuBalancePresenter presenter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    DaggerAddMenuBalanceComponent.builder()
        .menuBalanceRepoComponent(((CcdApplication) getActivity().getApplication()).getMenuBalanceRepoComponent())
        .addMenuBalancePresenterModule(new AddMenuBalancePresenterModule(this))
        .build()
        .inject(this); //完成注入
    }
}

從上面的程式碼可以直觀的看出DaggerAddMenuBalanceComponent使用了Builder模式, 設定了兩個引數 menuBalanceRepoComponentaddMenuBalancePresenterModule, 最後呼叫inject()把當前的Fragment作為引數傳遞進去了.

接下來看看inject()的實現 :

  @Override
  public void inject(AddMenuBalanceFragment fragment) {
    addMenuBalanceFragmentMembersInjector.injectMembers(fragment);
  }

然後看看DaggerAddMenuBalanceComponentaddMenuBalanceFragmentMembersInjector是怎麼產生的:

  private void initialize(final Builder builder) {

    this.provideAddMenuBalanceViewProvider =
        AddMenuBalancePresenterModule_ProvideAddMenuBalanceViewFactory.create(
            builder.addMenuBalancePresenterModule);

    this.getMenuBalanceRepositoryProvider =
        new Factory<MenuBalanceRepository>() {
          private final MenuBalanceRepoComponent menuBalanceRepoComponent =
              builder.menuBalanceRepoComponent;

          @Override
          public MenuBalanceRepository get() {
            return Preconditions.checkNotNull(
                menuBalanceRepoComponent.getMenuBalanceRepository(),
                "Cannot return null from a [email protected] component method");
          }
        };

  this.addMenuBalancePresenterProvider =
          AddMenuBalancePresenter_Factory.create(
  provideAddMenuBalanceViewProvider, getMenuBalanceRepositoryProvider);

  this.addMenuBalanceFragmentMembersInjector =
          AddMenuBalanceFragment_MembersInjector.create(addMenuBalancePresenterProvider);
}

initialize方法裡可以看出
addMenuBalanceFragmentMembersInjector依賴addMenuBalancePresenterProvider
addMenuBalancePresenterProvider又依賴provideAddMenuBalanceViewProvidergetMenuBalanceRepositoryProvider

所以要想明白addMenuBalanceFragmentMembersInjector是怎麼創建出來的, 就必須弄清楚addMenuBalancePresenterProvider,provideAddMenuBalanceViewProvidergetMenuBalanceRepositoryProvider.

1) provideAddMenuBalanceViewProvider屬性的分析

this.provideAddMenuBalanceViewProvider =
    AddMenuBalancePresenterModule_ProvideAddMenuBalanceViewFactory.create(
        builder.addMenuBalancePresenterModule);

從上面的程式碼可以看出, provideAddMenuBalanceViewProvider是通過AddMenuBalancePresenterModule_ProvideAddMenuBalanceViewFactory.create構建出來的:

  public static Factory<AddMenuBalanceContract.View> create(AddMenuBalancePresenterModule module) {
    return new AddMenuBalancePresenterModule_ProvideAddMenuBalanceViewFactory(module);
  }

然後看看構造方法和AddMenuBalancePresenterModule_ProvideAddMenuBalanceViewFactory.get()方法:

  public AddMenuBalancePresenterModule_ProvideAddMenuBalanceViewFactory(
      AddMenuBalancePresenterModule module) {
    assert module != null;
    this.module = module;
  }

  @Override
  public AddMenuBalanceContract.View get() {
    return Preconditions.checkNotNull(
        module.provideAddMenuBalanceView(),
        "Cannot return null from a [email protected] @Provides method");
  }

如此可見,AddMenuBalancePresenterModule_ProvideAddMenuBalanceViewFactory.get方法的返回值是通過傳遞進去的module.provideAddMenuBalanceView()提供的,這個module就是在FragmentDaggerAddMenuBalanceComponent.build的時候設定進去的,程式碼如下:

public class AddMenuBalanceFragment extends BaseFragment{

    //ignore other code

    DaggerAddMenuBalanceComponent.builder()
        .addMenuBalancePresenterModule(new AddMenuBalancePresenterModule(this))
        .build()
        .inject(this); //完成注入
    }
}

說白了AddMenuBalancePresenterModule_ProvideAddMenuBalanceViewFactorymodule就是AddMenuBalancePresenterModule(this). 這裡的this就是View

看看AddMenuBalancePresenterModule的程式碼:

@Module
public class AddMenuBalancePresenterModule {

    private final AddMenuBalanceContract.View mView;

    public AddMenuBalancePresenterModule(AddMenuBalanceContract.View view) {
        mView = view;
    }

    @Provides
    AddMenuBalanceContract.View provideAddMenuBalanceView(){
        return mView;
    }
}

所以provideAddMenuBalanceViewProvider.get返回的值就是View也就是我們的Fragment了。

所以provideAddMenuBalanceViewProvider的作用就是返回View , 至此provideAddMenuBalanceViewProvider講解完畢了。

2) getMenuBalanceRepositoryProvider 屬性的分析

    this.getMenuBalanceRepositoryProvider =
        new Factory<MenuBalanceRepository>() {
          private final MenuBalanceRepoComponent menuBalanceRepoComponent =
              builder.menuBalanceRepoComponent;

          @Override
          public MenuBalanceRepository get() {
            return Preconditions.checkNotNull(
                menuBalanceRepoComponent.getMenuBalanceRepository(),
                "Cannot return null from a [email protected] component method");
          }
        };

從上面的程式碼可以看出, 它通過一個匿名內部類來實現的。先看看匿名內部類中的menuBalanceRepoComponent屬性

這裡的menuBalanceRepoComponent是build.menuBalanceRepoComponent,DaggerAddMenuBalanceComponent.build我們只在AddMenuBalanceFragment裡設定了引數了,如下:

DaggerAddMenuBalanceComponent.builder()
        .menuBalanceRepoComponent(((CcdApplication) getActivity().getApplication()).getMenuBalanceRepoComponent())
        .addMenuBalancePresenterModule(new AddMenuBalancePresenterModule(this))
        .build()
        .inject(this);

從程式碼可以看出menuBalanceRepoComponent就是((CcdApplication) getActivity().getApplication()).getMenuBalanceRepoComponent()

Ok, 那我們看看CcdApplication.getMenuBalanceRepoComponent() :

public void onCreate() {
    //...
    mMenuBalanceRepoComponent = DaggerMenuBalanceRepoComponent.builder()
            .applicationModule(new ApplicationModule(getApplicationContext()))
            .build();
}

public MenuBalanceRepoComponent getMenuBalanceRepoComponent() {
    return mMenuBalanceRepoComponent;
}

所以匿名內部類(Factory)中的getMenuBalanceRepositoryProvider屬性就是DaggerMenuBalanceRepoComponent.

然後再看匿名內部類(Factory)的get()方法, 返回的是 DaggerMenuBalanceRepoComponent.getMenuBalanceRepository();, getMenuBalanceRepository()方法具體是怎麼實現的:

public final class DaggerMenuBalanceRepoComponent implements MenuBalanceRepoComponent {
  @Override
  public MenuBalanceRepository getMenuBalanceRepository() {
    return menuBalanceRepositoryProvider.get();
  }
}

發現該方法返回的是menuBalanceRepositoryProvider.get(); , 那麼menuBalanceRepositoryProvider是什麼東西?

menuBalanceRepositoryProvider是在DaggerMenuBalanceRepoComponent.initialize(builder)中初始化:

  private void initialize(final Builder builder) {

    this.provideRemoteDataSourceProvider =
        ScopedProvider.create(
            MenuBalanceRepoModule_ProvideRemoteDataSourceFactory.create(
                builder.menuBalanceRepoModule));

    this.menuBalanceRepositoryProvider =
        ScopedProvider.create(
            MenuBalanceRepository_Factory.create(provideRemoteDataSourceProvider));
  }

從這段程式碼可以看出 menuBalanceRepositoryProvider初始化依賴於provideRemoteDataSourceProvider

所以又得先分析下 provideRemoteDataSourceProvider了, provideRemoteDataSourceProvider的初始化需要builder.menuBalanceRepoModule, 這個builder.menuBalanceRepoModule是在我們呼叫build的時候Dagger2建立的:

public MenuBalanceRepoComponent build() {
  if (menuBalanceRepoModule == null) {
    this.menuBalanceRepoModule = new MenuBalanceRepoModule();
  }
  return new DaggerMenuBalanceRepoComponent(this);
}

所以builder.menuBalanceRepoModule = new MenuBalanceRepoModule() , MenuBalanceRepoModule類的程式碼如下:

@Module
public class MenuBalanceRepoModule {

    @Singleton
    @Provides
    @Remote
    IMenuBalanceSource provideRemoteDataSource() {
        return new MenuBalanceRemoteSource();
    }
}

provideRemoteDataSourceProvider屬性需要MenuBalanceRepoModule_ProvideRemoteDataSourceFactory.create創建出來的, 那來看看這個工廠方法 :

  @Override
  public IMenuBalanceSource get() {
    return Preconditions.checkNotNull(
        module.provideRemoteDataSource(),
        "Cannot return null from a [email protected] @Provides method");
  }

  public static Factory<IMenuBalanceSource> create(MenuBalanceRepoModule module) {
    return new MenuBalanceRepoModule_ProvideRemoteDataSourceFactory(module);
  }

create方法的引數module就是我們剛剛分析的MenuBalanceRepoModule, 工廠方法的get方法返回的就是:

    IMenuBalanceSource provideRemoteDataSource() {
        return new MenuBalanceRemoteSource();
    }

所以provideRemoteDataSourceProvider的作用就是提供new MenuBalanceRemoteSource()物件的.

menuBalanceRepositoryProvider屬性依賴的引數provideRemoteDataSourceProvider講完了, 那麼就可以分析menuBalanceRepositoryProvider屬性了:

this.menuBalanceRepositoryProvider =
    ScopedProvider.create(
        MenuBalanceRepository_Factory.create(provideRemoteDataSourceProvider));

MenuBalanceRepository_Factory類:

  @Override
  public MenuBalanceRepository get() {
    return new MenuBalanceRepository(remoteSourceProvider.get());
  }

  public static Factory<MenuBalanceRepository> create(
      Provider<IMenuBalanceSource> remoteSourceProvider) {
    return new MenuBalanceRepository_Factory(remoteSourceProvider);
  }

它的get()方法new了一個MenuBalanceRepository, 構造這個MenuBalanceRepository需要MenuBalanceRemoteSource引數,通過傳進來的provideRemoteDataSourceProvider提供即可.

所以menuBalanceRepositoryProvider的作用就是提供new MenuBalanceRepository物件的.

所以DaggerMenuBalanceRepoComponent.getMenuBalanceRepository()方法返回的就是MenuBalanceRepository

  @Override
  public MenuBalanceRepository getMenuBalanceRepository() {
    return menuBalanceRepositoryProvider.get();
  }

再來回顧下匿名內部類(Factory) :

    this.getMenuBalanceRepositoryProvider =
        new Factory<MenuBalanceRepository>() {
          private final MenuBalanceRepoComponent menuBalanceRepoComponent =
              builder.menuBalanceRepoComponent;

          @Override
          public MenuBalanceRepository get() {
            return Preconditions.checkNotNull(
                menuBalanceRepoComponent.getMenuBalanceRepository(),
                "Cannot return null from a [email protected] component method");
          }
        };

到現在為止, 我們就可以解釋匿名內部類get()方法返回的是什麼了, 返回就是MenuBalanceRepository物件.

所以getMenuBalanceRepositoryProvider屬性的作用就是提供MenuBalanceRepository物件的.

3) addMenuBalancePresenterProvider 屬性的分析

addMenuBalancePresenterProvider屬性初始化所依賴的provideAddMenuBalanceViewProvidergetMenuBalanceRepositoryProvider都分析完畢了, 現在就可以分析addMenuBalancePresenterProvider屬性了.

通過上面的分析我們知道:

provideAddMenuBalanceViewProvider屬性的作用就是返回View

getMenuBalanceRepositoryProvider屬性的作用就是提供MenuBalanceRepository物件的

看看addMenuBalancePresenterProvider初始化程式碼如下:

  this.addMenuBalancePresenterProvider =
          AddMenuBalancePresenter_Factory.create(
  provideAddMenuBalanceViewProvider, getMenuBalanceRepositoryProvider);

AddMenuBalancePresenter_Factory類:

  public AddMenuBalancePresenter_Factory(
      Provider<AddMenuBalanceContract.View> viewProvider,
      Provider<MenuBalanceRepository> mMenuBalanceRepositoryProvider) {
    assert viewProvider != null;
    this.viewProvider = viewProvider;
    assert mMenuBalanceRepositoryProvider != null;
    this.mMenuBalanceRepositoryProvider = mMenuBalanceRepositoryProvider;
  }

  @Override
  public AddMenuBalancePresenter get() {
    return new AddMenuBalancePresenter(viewProvider.get(), mMenuBalanceRepositoryProvider.get());
  }

  public static Factory<AddMenuBalancePresenter> create(
      Provider<AddMenuBalanceContract.View> viewProvider,
      Provider<MenuBalanceRepository> mMenuBalanceRepositoryProvider) {
    return new AddMenuBalancePresenter_Factory(viewProvider, mMenuBalanceRepositoryProvider);
  }

通過它的get()方法就知道該工廠方法返回一個AddMenuBalancePresenter例項, 構造AddMenuBalancePresenter需要的兩個引數通過上面講解了兩個屬性provideAddMenuBalanceViewProvider和getMenuBalanceRepositoryProvider提供.

所以addMenuBalancePresenterProvider屬性的最終的作用就是提供AddMenuBalancePresenter物件的.

到此為止, 我們就知道了Presenter是怎麼被構建出來的了.

4) addMenuBalanceFragmentMembersInjector 屬性的分析

接下來分析DaggerAddMenuBalanceComponent最後一個需要分析的屬性addMenuBalanceFragmentMembersInjector

  this.addMenuBalanceFragmentMembersInjector =
          AddMenuBalanceFragment_MembersInjector.create(addMenuBalancePresenterProvider);

AddMenuBalanceFragment_MembersInjector類程式碼:

  public static MembersInjector<AddMenuBalanceFragment> create(
      Provider<AddMenuBalancePresenter> presenterProvider) {
    return new AddMenuBalanceFragment_MembersInjector(presenterProvider);
  }

  @Override
  public void injectMembers(AddMenuBalanceFragment instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.presenter = presenterProvider.get();
  }

核心就是injectMembers方法, 該方法完成了Fragment中對Presenter的注入, injectMembers方法所需要的引數 presenterProvider 就是addMenuBalancePresenterProvider屬性(提供AddMenuBalancePresenter物件的).

因為DaggerAddMenuBalanceComponent.inject()方法呼叫了AddMenuBalanceFragment_MembersInjector.injectMembers.

所以為什麼說呼叫DaggerAddMenuBalanceComponent.inject()方法就完成了依賴注入操作.

所以這也就是為什麼需要在Fragment中呼叫它了, 如下程式碼所示:

public class AddMenuBalanceFragment extends BaseFragment{
    @Inject
    AddMenuBalancePresenter presenter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    DaggerAddMenuBalanceComponent.builder()
        .menuBalanceRepoComponent(((CcdApplication) getActivity().getApplication()).getMenuBalanceRepoComponent())
        .addMenuBalancePresenterModule(new AddMenuBalancePresenterModule(this))
        .build()
        .inject(this); //完成注入
    }
}

上面的原始碼分析流程可以用如下圖來表示 :

這裡寫圖片描述

Dagger2生成類我們寫的Component和Module類對應關係

AddMenuBalanceComponent(Interface) –> DaggerAddMenuBalanceComponent implements AddMenuBalanceComponent

AddMenuBalancePresenterModule –> AddMenuBalancePresenterModule_ProvideAddMenuBalanceViewFactory

MenuBalanceRepoComponent(Interface) –> DaggerMenuBalanceRepoComponent implements MenuBalanceRepoComponent

MenuBalanceRepoModule –> MenuBalanceRepoModule_ProvideRemoteDataSourceFactory

從上面的原始碼分析,Dagger2生成的原始碼大量使用了BuilderFactory模式。

相關推薦

Android Dagger2原始碼分析-物件是如何注入

分析的原始碼是基於Android Dagger2(一) 基本使用 的例子來分析物件是如何被注入的. 如果還沒看上一篇文章, 可以先去看看. 在分析原始碼之前, 先理一理類與類之間的依賴關係 : public class AddMenuBalanceFr

Spring AOP實現原理筆記 -- 原始碼分析

1、註冊AnnotationAwareAspectJAutoProxyCreator 首先要了解Spring解析XML配置檔案時,遇到自定義節點是如何解析的。可以參考Spring自定義XML標籤解析及其原理分析 當Spring遇到這個標籤的時候,它會

Nacos原始碼分析Nacos服務端註冊示例流程

  上回我們講解了客戶端配置好nacos後,是如何進行註冊到伺服器的,那我們今天來講解一下伺服器端接收到註冊例項請求後會做怎麼樣的處理。   首先還是把博主畫的原始碼分析圖例發一下,讓大家對整個流程有一個大概的理解:圖示流程地址:https://www.processon.com/view/link/5f7e

Spring學習筆記——註解建立物件注入屬性

一、Bean相關的註解 與SpringBean相關的註解有以下四大類: @Component:標註一個普通的Spring Bean類 @Controller:標註一個控制器元件類 @Service:標註一個業務邏輯元件類 @Repository:標註一個D

jquery 1.7.2原始碼解析構造jquery物件

構造jquery物件 jQuery物件是一個類陣列物件。 一)建構函式jQuery() 建構函式的7種用法:   1.jQuery(selector [, context ]) 傳入字串引數:檢查該字串是選擇器表示式還是HTML程式碼。如果是選擇器表示式,則遍歷文件查詢匹配的DOM元

Android開源專案分析android輕量級開源快取框架——ASimpleCacheACache原始碼分析

ASimpleCache框架原始碼連結 官方介紹 ASimpleCache 是一個為android制定的 輕量級的 開源快取框架。輕量到只有一個java檔案(由十幾個類精簡而來)。 1、它可以快取什麼東西? 普通的字串、J

從ECMAScript規範深度分析JavaScript:變數物件

本文譯自Dmitry Soshnikov的《ECMA-262-3 in detail》系列教程。其中會加入一些個人見解以及配圖舉例等等,來幫助讀者更好的理解JavaScript。 宣告:本文不涉及與ES6相關的知識。 前言 在本系列教程上一篇文章《從ECMAScript規範深度分

從ECMAScript規範深度分析JavaScript:變數物件

本文譯自Dmitry Soshnikov的《ECMA-262-3 in detail》系列教程。其中會加入一些個人見解以及配圖舉例等等,來幫助讀者更好的理解JavaScript。 宣告:本文不涉及與ES6相關的知識。 前言 在學習變數物件之前,我們要對執行期上下文有所瞭解,可以先

JVMJVM 建立物件過程分析

在語言層面上,建立物件通常僅僅是一個new關鍵字而已,而在虛擬機器中,物件(文中討論的物件限於普通Java物件,不包括陣列和Class物件等)的建立又是怎樣一個過程呢?首先來看一下JVM建立物件時的流程圖: Created with Raphaël 2.1

Android 7.0 虛擬按鍵NavigationBar原始碼分析 之 View的建立流程

    最近有個需求是修改虛擬按鍵的單擊和長按效果。所以研究了下Android關於虛擬按鍵的實現流程。好記性不如爛筆頭,記錄如下。     首先,幾個重要的類: //實現 單個虛擬按鍵的 自定義ImageView     frameworks/base/packages/

Kafka原始碼解析---Log分析

上一篇文章講了LogSegment和Log的初始化,這篇來講講Log的主要操作有哪些。 一般來說Log 的常見操作分為 4 大部分。 1. 高水位管理操作 2. 日誌段管理 3. 關鍵位移值管理 4. 讀寫操作 其中關鍵位移值管理主要包含Log Start Offset 和 LEO等。 ## 高水位H

設計模式:面向物件及其特性分析

# 面向物件 > 根據大綱,首先我們來學習一種程式碼設計與編寫的風格,即面向物件。 ## 面向物件程式設計和麵向物件程式語言 - 面向物件程式設計是一種程式設計正規化,通俗來說,就是將 **程式碼的組織單元改成類和物件**,並將 **封裝、繼承、抽象、多型** 作為程式碼設計和編寫的基石。 -

MVC排球計分——需求分析與數據庫設計

logs 用例圖 中國隊 eight 需求 back 過程 style .cn 需求分析和數據庫的設計是很重要的一個環節,這個環節會直接影響項目的開發過程和質量。 這裏做的排球計分程序是一個例子,而且其業務極為簡單,因此,這裏並不是真正的需求分 析和數據庫設計,而是將排球計

MVC項目實踐——需求分析

用例 分析 strong span 詳細 現在 同時 喜歡 發揮 需求: 作為一名觀眾,我希望知道詳細的比分變化和得分信息,以便於了解比賽走向和隊員的精彩得分。 用例故事: 裏約奧運女排決賽進行中... Ht7:現在比分多少了? LP:2:1,中國隊領先。 Ht7:那小比

php7新特性:面向物件部分

1)、PHP 7 支援new class 來例項化一個匿名類這可以用來替代一些"用後即焚"的完整類定義。 2)、Closure::call():將一個閉包函式動態繫結到一個新的物件例項並呼叫執行該函式 3)、use:可以使用一個 use 從同一個 namespace 中匯入類、函

Android學習—— Android SDK

在上一篇文章中,提到了一個概念,叫SDK,這篇文章就來對SDK進行一個簡單的講解 Android SDK Android SDK(Software Development Kit)提供了在Windows/Linux/Mac平臺上開發Android應用的開發元件,Android支援所有的平臺,其包含了在An

Android動畫-屬性動畫

概述 上一篇主要介紹了ViewAnim和幀動畫,篇幅有點長,另起一篇。上篇介紹的兩種動畫開發中用到的不多,主要還是本篇的屬性動畫使用比較廣。 1 補間動畫 1.1 Property Anim 開發中Property Anim使用比View Anim要更為廣泛,主要還是出於剛剛

python資料分析新手入門課程學習——探索分析與視覺化來源:慕課網

 一,單因子與對比分析視覺化 資料 import pandas as pd df = pd.read_csv('./HR.csv') #檢視前十條資料 df.head(10) 以下為顯示的結果 我們可以看出: 第一個屬性satisf

Android學習

##常用控制元件 所有的安卓控制元件都需要指定 layout_width 和 layout_height 都具有visibility屬性 TextView <TextView android:id="@+id/txtOne" android:layout_w

java基礎-初級【面向物件與類】

目錄   2、面向物件與類 2.1  面向物件思想 2.2  類與物件 2.3  成員和區域性變數 2.4  匿名物件 2.5  類的訪問許可權修飾符 2.6  static關鍵字-靜態域、靜態