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
的構造方法又依賴View
和MenuBalanceRepository
, 這裡的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
也就可以構造出來了, 如果MenuBalanceRepository
和View
都有了就可以把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
模式, 設定了兩個引數 menuBalanceRepoComponent
和 addMenuBalancePresenterModule
, 最後呼叫inject()
把當前的Fragment作為引數傳遞進去了.
接下來看看inject()
的實現 :
@Override
public void inject(AddMenuBalanceFragment fragment) {
addMenuBalanceFragmentMembersInjector.injectMembers(fragment);
}
然後看看DaggerAddMenuBalanceComponent
中 addMenuBalanceFragmentMembersInjector
是怎麼產生的:
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
又依賴provideAddMenuBalanceViewProvider
和getMenuBalanceRepositoryProvider
所以要想明白addMenuBalanceFragmentMembersInjector
是怎麼創建出來的, 就必須弄清楚addMenuBalancePresenterProvider
,provideAddMenuBalanceViewProvider
和getMenuBalanceRepositoryProvider
.
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
就是在Fragment
中DaggerAddMenuBalanceComponent.build
的時候設定進去的,程式碼如下:
public class AddMenuBalanceFragment extends BaseFragment{
//ignore other code
DaggerAddMenuBalanceComponent.builder()
.addMenuBalancePresenterModule(new AddMenuBalancePresenterModule(this))
.build()
.inject(this); //完成注入
}
}
說白了AddMenuBalancePresenterModule_ProvideAddMenuBalanceViewFactory
的module
就是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
屬性初始化所依賴的provideAddMenuBalanceViewProvider
和getMenuBalanceRepositoryProvider
都分析完畢了, 現在就可以分析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生成的原始碼大量使用了Builder
、Factory
模式。
相關推薦
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輕量級開源快取框架——ASimpleCache(ACache)原始碼分析
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相關的知識。 前言 在學習變數物件之前,我們要對執行期上下文有所瞭解,可以先
JVM(二)JVM 建立物件過程分析
在語言層面上,建立物件通常僅僅是一個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關鍵字-靜態域、靜態