陳昱儒
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # Android、Kotlin 重大組件 ★★★ ## 一、Koin 1. 定義的方法: 1. single -> 每次拿到同一個(單例) Ex:`val myModule = module{ single{ MyWood() as Wood} }` 2. factory -> 每次都New一個新的 Ex: `val myModule = module{ factory{ MyPrinter(get(),get()) as Printer} }` 3. scope -> 可以是一個範圍的人都取到同一個 2. 裡面會放get(),會自動拿取該class 照順序的資料型別,且這個get(),會再繼續尋找對應的建構式。 Ex: ```kotlin= class Test(val code:Int, val student:Student) val module = module{ factory{ Test(get(), get()) as Test} //第一個get() = Int //第二個get() = Student } ``` 3. 因為kotlin沒有隱式轉換,因此要用as,才會確定class;或是`single<HelloRepository> { HelloRepositoryImpl() }`。 4. 使用方式: 1. 創立一個di的資料夾,在裡面依照分類,先定義好modules 2. 自定義Application(繼承Application後,記得註冊檔要改成自定義的App),並於onCreate做koin的設置。 ```kotlin= startKoin{ androidContext(application-應用程式)//應用的範圍 androidLogger()//蒐集錯誤用,通常會用buildConfig Debug模式才開啟 modules(module) } ``` 3. modules,放入自己定義好的module,可以是一個moduleList 4. 在任何一個context base(Fragment也可以)的class,就可以透過by inject(lazy Loading) 或get(),拿到對應的資料。 5. 默認情況下,Koin將按類型或名稱綁定定義(如果該類型已綁定到定義),可以透過named()給他名字`single<Service>(named("Test")){ ServiceImpl2 ()}`,這樣如果有兩個相同的類型或名稱時,給予姓名,才會拿到不同的。[範例](https://insert-koin.io/docs/reference/koin-core/definitions) 6. 如果是要有參數的話,在調用時就使用parametersOf(args),將參數放入`val presenter : Presenter by inject { parametersOf(view) } --- ## 二、Room (Android Local DB) ### 概述 1. Room是把一些 SQLite 底層實作封裝起來讓我們能更方便存取資料庫,並支援編譯時期的SQL語法檢查。-也因此有些時候可能會打SQL的指令。 2. Room是操作資料庫的單一路口,等同於資料來源,包含了Room Database、Data Access Objects、Entities三個組成。 3. 內建可以跟LiveData或RxJava(Flowable)整合一起用,但都需要增加dependency。([範例](https://ansgarlin.github.io/android/room.html#More-about-DAO) 4. 搭配RxJava後,可以在資料改變時收到通知,但無法確定收到的資料是不是重複,因為Room不會知道是什麼造成變動,所以建議加上distinctUntilChanged()。 5. 執行過程: 1. 透過RoomDatabase取得DAO。 2. 呼叫DAO內的函式存入或取得Entity。 3. 針對Entity修改內容。 4. 示意圖: ![](https://i.imgur.com/jw1ZwVq.png) 6. MVVM Data Stream: ![](https://i.imgur.com/WjBvPp9.png) ![](https://i.imgur.com/QwqK1VD.png) ### Entity (修改內容): 1. 一定要設定這兩個宣告: * 使用@Entity標記。 * 使用@PrimaryKey標記變數(作為主鍵)。 2. PraimaryKey (主鍵)注意事項: * 變數的值是否唯一,不然會產生衝突。 * 如果預設值會是null,要加上@NonNull。(簡單來書,避免主鍵是null。) 3. 其他設定-非必要(設定在@Entity裡面): * @tableName:設置表單名稱。(預設表單名稱是Entity類別名) * @ColumnInfo:設置欄位名稱。(預設欄位名稱是變數名) * @Index:用於標記特定欄位來加快查詢速度,如有特定組合是不希望重複的,可以再加上unique。 * @Ignore:用於不想被存入資料庫的變數。 * @ForeignKey:用於設定外部關聯。 * @Embedded:用於加入另一個Entity或POJO的變數。(跟其他的有關聯,可能會重名,會需要給名字) * [使用範例](https://ansgarlin.github.io/android/room.html#Entity) 4. 可以有多個constructor(建構式),但參數名稱要和Entity內的變數名稱相同。 5. tableName 沒有大小寫之分(在SQLite裡) 6. 有設定ForeignKey,的話,可以使用`onDelete`或`onUpdate`設定外部資料變動時要做的事情;並且要注意存取有foreignKey的Entity十,資料庫要已經有指定的Entity,否則會錯誤。 7. 如果Embedded所擁有的變數名稱相同,可以透過加上prefix避免欄位重複發生錯誤。`@Embedded(prefix = "prefix_")` 8. ColumnInfo、Embedded、Relation(Pojo類才可適用)不能同時使用在同一個變數上。 ### DAO (Data Access Objects)(函式存入或取得Entity) 1. 必要條件: * 使用@Dao標記。 * 使用@Query、@Insert、@Update、@Delete、@Transaction標記函式。 2. Relation(用來創建POJO): 1. 利用`@Relation`設定變數。 2. 指定的變數,一定要是List或Set。 3. 並透過parentColumn指定變數所在類別對應到的欄位,而entityColumn則是變數類型內對應到的欄位。 EX:`@Relation(parentColumn = "uid", entityColumn = "id")` 4. 如果變數類型跟要聯合查詢的型別不同,可以另外用entity指定 EX: `@Relation(parentColumn = "uid", entityColumn = "id", entity = Address.class) ` 5. 如果只是需要Entity的特定欄位,可以設定projection EX: `@Relation(parentColumn = "uid", entityColumn = "id", entity = Address.class, projection = {"city"})` 3. @Query:取資料 1. 定義為:@Query("SELECT A FROM B") * A = 要取的欄位,*代表全部,如果是多個,可以用逗號隔開 * B = 要找的Entity。 * FROM後面可以在加WHERE C(欄位) = D(參數) OR WHERE "欄位名稱" LIKE :參數名稱 表示有條件的尋找(篩選) * LIMIT (Int) 是限制他 query 的數量 2. 如果沒有參數,代表回傳這個Entity的全部資料。 3. 如果參數是一個集合,只要再加上括號,Room就會自動將其內容分批執行然後回傳。(也就是用一個list去對照,拿取資料),回傳的list或個體自己決定。 4. 如果參數是變數(1或多個)可以將參數名稱加入指令內,並在前面加冒號,已進行篩選。(也就是輸入條件,拿取資料),回傳的list或個體自己決定。 5. 可以透過不同的資料表(table)來篩選要的結果回傳。 6. 如果需要多表查詢,可以建立一個POJO。 7. Primitive type的物件類型如Boolean、Long無法使用 8. [使用範例](https://ansgarlin.github.io/android/room.html#Query) 4. @Insert:放資料進資料庫 1. 可以放入單數個體、複數變數、陣列、集合。 2. 定義Insert時,可以設定好資料重複時的處理方式,否則PrimaryKey重複會錯誤。 3. 處理方式:`@Insert(onConflict = OnConflictStrategy.REPLACE)` 4. OnConflictStrategy.三種方式(有五種但兩種要被棄用): * REPLACE:替換掉舊的資料。 * ABORT:終止並撤銷這次所做的任何更改。 - 閃退(是默認值) * IGNORE:忽略掉這個資料。 * [詳細:ON CONFLICT條款](https://sqlite.org/lang_conflict.html) 5. insert 除了不回傳資料以外,也可以回傳rowid,如果是傳入多個或集合時,會回傳LongArray,一個的話就回傳Long。 5. @Update:用PrimaryKey搜尋資料,並更新資料內容(傳入一~多筆資料)。 6. @Delete:用PrimaryKey搜尋資料,並刪除資料(傳入一~多筆資料)。 7. Update跟Delete可以透過回傳int,取得成功更新/刪除的比數。 8. @Transaction: 1. 用來將DAO操作組合,確保全部操作在一個transaction內完成。 2. 如果跟@Query組合,則可以確保資料在兩種情況下不會出錯: * 回傳結果超過CursorWindow(游標窗口?)一次能容納的量。 * 回傳結果是POJO類型,且其中的變數將是分開查詢。 9. 給予一個POJO,可以讓取資料的同時,將結果轉成較為精簡的資料類別。 ### Database 1. 必要條件: 1. 必須是一個抽象類別,並繼承RoomDatabse。 2. 使用@Database標記,並給予會用到的Entity類別、資料庫版本。 3. 設定一個抽象並沒有接受參數的函式,取得Dao。 4. EX:`@Database(entities = {User.class}, version = 1)` ### TypeConverter 1. 如果有需要儲存Room無法支援的類別時,可以透過加上宣告@TypeConverters、@TypeConverter,來做轉換函式,不用自己一直打轉型。 2. 必要條件: 1. 要用@TypeConverter標記。 2. 轉換的函示的輸入參數須為想轉換的類別,轉出的類別則為Room可支援的類別。 3. 一個轉換的函示,要對應到一個還原的函示。 3. 使用方式:在Database的類別,告知額外可用的TypeConverter,EX:`@TypeConverters({Converters.class})`,之後在遇到對應的class時,就會自動轉換 ### 如何使用 1. 取得Database:透過靜態函式databaseBuilder 並給予有@Database標記的類別和想要的資料庫名稱,實體的產生很耗資源建議singleton。 `Room.databaseBuilder(context: Context, dataClass: Class<T!>, name:String).build()` 2. 預設情況,存取資料庫(Insert、Query...)行為都強制在背景處理,否則會報錯(跟網路一樣)。 3. 如果需要在MainThread取得,必須在Builder,加上`allowMainThreadQueries()`。 4. 如果資料庫版本不同,可以進行整合,一樣是在Builder加上`addMigrations(Migration)`。 * Migration是一個內,放入兩個int,並override migrate方法即可。[範例](https://ansgarlin.github.io/android/room.html#Migration) 5. 如果有用Migration,要自行建立新的表單,才能將資料重新塞入,有兩種方式(一種透過SQL指令,一種透過內建的ContentValues)[範例](https://ansgarlin.github.io/android/room.html#Migration) 6. 如果確定不使用了,記得使用close()關閉資料庫,避免記憶體外洩。 7. builder還有很多可以設定的,有空可以研究。 ### 如何測試(Unit Test) 1. @Before: 透過Room.inMemoryDatabaseBuilder()產生RoomDatabae,並呼叫getUserDao()取得DAO 2. @Test: 產生假資料,透過DAO加入資料庫,並透過DAO將資料取回並驗證。 3. @After: 執行close()關閉資料庫。 4. 測試Migration,要多做些前置作業(暫時用不到,之後有需要可以看範例後面的資料)。 5. [範例](https://ansgarlin.github.io/android/room.html#After) 參考資料: [- ★Room (Android Interface Definition Language)](https://ansgarlin.github.io/zh-tw/android/room.html) [- ★Room &MVVM](https://enginebai.com/2019/04/03/android-database-room/) --- ## 三、Rxjava (ReactiveX) - 合併未看 ### 概述 1. 以資料為中心,關注點在資料的流動上。 2. Rxjava的缺點:快速的 Observable 和慢速的Observer 可能會迅速導致積壓的太多未消耗的資料,這將消耗系統資源,甚至可能導致OutOfMemoryException。 這個問題被稱為背壓 - (EX:WebSocket)。 3. 解決背壓,可以透過操作符,利用拿取的週期等方式,或是將Observable替換成Flowable的方式(Flowable其實跟Observable的創建方式相同)。 4. 既然使用Flowables不用擔心背壓,為什麼我不直接使用Flowables而要使用Observable呢? 答案是,Flowable比普通Observable需要更多的開銷,所以為了創造一個高性能的APP,你應該堅持使用Observable,除非你懷疑你的APP出現背壓。 5. reactive type共有五種: * Flowable * Observable * Single * Maybe * Completable ### 使用方法 1. just():在裡面直接放入要讀取的資料,EX:`Observable.just(1,2,3,4,5)`。 2. from():能夠讀取繼承Iterable(遍歷器)的所有類別,EX:`Observable.from(listOf(1,2,3,4,5))`。 3. filter:過濾資料。 4. map:調整資料(一筆一筆處理),可以在這邊增加數值,甚至是轉換資料的格式也OK。 5. flatmap:直接將整筆資料轉換成另一個Observable。 6. sample(): 在指定時間間隔內檢查Observable的輸出,並拿取最後一個值。 7. throttleFirst():同上,但哪取第一個值 8. buffer():批量發射,存一段時間後,把這段時間的資料發射出去。 9. 如果只是需要觀察一個數值,可以利用Singles,非常輕量的Observable,只能接收一個值,當然後面可以利用方法來合併: * mergeWith():將多個Singles合併成一個單一的Observable。 * concatWith():將多個Singles連在一起,形成Observable發射資料 * toObservable():將一個Single轉換為一個Observable,發出最初由Single發出的資料,然後完成。 ### 關於Threading這回事 1. 發射資料的時間點,是在subscribe時,從哪個thread呼叫,預設thread就在哪裡,可以藉由subscribeOn、observeOn進行切換。 2. 會有三個階段(自己取的): * 連線階段:一開始subscribe時,以當前的thread進行。 * 訂閱階段(Subscribe階段):拿取資料的過程,可能會有filter、map * 完成階段:也就是Subscribe裡面的CallBack,這裡記得Observer的資料格式,如果上面有定義map,要跟map出來的資料格式相同。 * 資料拿到後會執行onNext()(依序將訊息處理完畢),當全部的onNext()都處理完後,就會觸發onComplete() 3. subscribeOn(影響訂閱階段Thread): 1. 改變subscribe執行的thread,通常只會被呼叫一次 。 2. 如果沒有定義subscribeOn,會沿用一開始訂閱階段的Thread。 4. observeOn(影響完成階段Thread): 1. 只會影響到在這個function以後的所有操作。 2. 不是全域的設定,可以被呼叫多次,呼叫的順序也會有影響。 3. 最後的呼叫會覆蓋掉之前的設定,會以最後一個observeOn為主(包括subscribeOn - 如果在observeOn之後才執行的話) 4. 如果沒有定義observeOn,會沿用subscribeOn的Thread。 5. 上述兩種都需要放入一個scheduler作為參數,預設有: 1. Schedulers.io():如果有網路、檔案存取需求推薦使用,Rx 會幫我們管理 ThreadPool reuse 的部分。 2. Schedulers.computation():計算數據推薦;跟 io() 一樣也是會由 ThreadPool 管理,但是 ThreadPool 的大小跟裝置 CPU core 相關。 3. Schedulers.newThread():顧名思義就是每次都會建立新的 Thread,所以稍微耗效能一點。 4. AndroidSchedulers.mainThread():Main Thread。 (需要額外引用library `implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'`) 6. subscribe執行時,會先跑上面原本的設定,除非是寫在subscribe之後的動作(或是subscribe的onNext)才會跑到observeOn上。 7. 範例: ```kotlin= //假設有一串陣列1~6,要去讀取他,並在顯示時要轉換成String型態 Observable //要讀的東西 - 可能是網路資料 .just(1,2,3,4,5,6) //讀到後要不要過濾 - subscribe階段 .filter{ println("Filter " + Thread.currentThread().name) it % 3 == 0} //對資料有沒有更改 - subscribe階段 ->這裡可以改變資料的型態,下面的Observer要跟他相同 .map { println("Map " + Thread.currentThread().name) "${it * 3}" } //定義subscribe階段要在哪個執行緒上 .subscribeOn(Schedulers.io()) //定義完成階段要在哪個執行緒上 .observeOn(Android.mainThread()) .subscribe(object : Observer<String>{ //訂閱頻道會看在哪個Thread呼叫,就是在哪裡,因此不受限subscribeOn的Thread override fun onSubscribe(d: Disposable) { println("onSubscribe " + Thread.currentThread().name) } //onNext、onComplete、onError都算完成階段,會被observerOn的Thread影響 override fun onNext(t: String) { //資料已經處理好了,要做什麼,EX:顯示於畫面。 println("onNext / $t " + Thread.currentThread().name) } override fun onComplete() { println("onComplete " + Thread.currentThread().name) } override fun onError(e: Throwable) { println("onError " + Thread.currentThread().name) } }) ``` 參考資料: [- [Android 十全大補] RxJava](https://ithelp.ithome.com.tw/articles/10223248) [- 官方Reactive運算符](http://reactivex.io/documentation/operators.html) [- Rxjava的操作符(sample,buffer...)](https://code.tutsplus.com/zh-hant/tutorials/reactive-programming-operators-in-rxjava-20--cms-28396) [- Rxjava的創建符](https://code.tutsplus.com/zh-hant/tutorials/reactive-programming-operators-in-rxjava-20--cms-28396) [- Rxjava的運用簡例](https://medium.com/jastzeonic/rxjava2-%E5%85%A5%E9%96%80%E9%82%A3%E4%B8%80%E5%85%A9%E5%80%8B%E5%BF%83%E5%BE%97-346d3affdf70) [- 关于RxJava最友好的文章](https://www.jianshu.com/p/6fd8640046f1) [- 给初学者的RxJava2.0教程(一)](https://www.jianshu.com/p/464fa025229e) --- ## 四、 MPAndroidChart ### [- MPAndroidChart LineChart使用,基本語法都在這裡可以查](https://bloggi.co/posts/1188fe) ### 基本使用 1. [ValueFormatter官方預設值](https://weeklycoding.com/mpandroidchart-documentation/formatting-data-values/) 2. 須按照生冪排序放資料(因為系統是用二分搜尋法) 3. Data:一張圖的資料(會分line、bar...) * DataSet(一個資料可以包含很多的DataSet,每一個DataSet,代表一種資料的全部,以線,來說,一個DataSet,就是一條線) * Entry (一個DataSet,可以有很多個Entry,每一個Entry,代表一個資料點會有x,y座標,也可以放資料) ![](https://i.imgur.com/GdEPdMV.jpg) --- ## 五、SpanString && Im 1. 流程: 1. 取得要用到的文字(可以不是getString直接打) 2. 取得要開始改變的index 3. 先將第一組文字,new成 SpannableString 4. **如果開始改變的index不為-1;計算 結束的index(開始改變 + 要改變的程度)** 5. 設定Span(樣式,起始index,結束index,規則) * 樣式、規則都有多個預設可選 2. * 以下的前後指的是 startIndex (前), endInex (後) * – Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:前后都不包括,即在指定范围的前-面和后面插入新字符都不会应用新样式 * – Spannable.SPAN_EXCLUSIVE_INCLUSIVE :前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式 * – Spannable.SPAN_INCLUSIVE_EXCLUSIVE :前面包括,后面不包括。 * – Spannable.SPAN_INCLUSIVE_INCLUSIVE :前后都包括。 ```kotlin= val browseTitle: String = getString(R.string.template_base_information_browse_title) val smallerPartTitle: String = getString(R.string.template_base_information_browse_title_smaller) val matchStart: Int = browseTitle.indexOf(smallerPartTitle) val spannableString = SpannableString(browseTitle) if (matchStart != -1) { val matchEnd = matchStart + smallerPartTitle.length /* 1.設定樣式 AbsoluteSizeSpan 字體大小改變的Span 前面包括,後面不包括 */ spannableString.setSpan( AbsoluteSizeSpan(14, true), matchStart, matchEnd, Spannable.SPAN_INCLUSIVE_EXCLUSIVE ) } ``` 參考資料: [- SpanString和SpanStringBuilder的使用](https://blog.csdn.net/u010126792/article/details/83538829) [- Android SpannableString使用详解](https://blog.csdn.net/wenzhi20102321/article/details/54017417) [- Android中的SpannableString與SpannableStringBuilder詳解](https://codertw.com/android-%E9%96%8B%E7%99%BC/335316/) ###### tags: `Android`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully