2017-08-01

Error installing polyglot in Python 3

Chuyển code từ Python 2.7 sang 3.x

Gặp lỗi dạng như sau:

UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 4941: character maps to 

https://stackoverflow.com/questions/41746072/error-installing-polyglot-in-python-3-5-2
https://github.com/aboSamoor/polyglot/issues/93

Nếu chưa cài những packages sau thì cài trước pycld2, PyICU, numpy
Trên Windows download tại http://www.lfd.uci.edu/~gohlke/pythonlibs
pycld2-0.31-cp36-cp36m-win32.whl
PyICU-1.9.7-cp36-cp36m-win32.whl
numpy-1.13.1+mkl-cp36-cp36m-win32.whl

Thực hiện download source từ Github
https://github.com/aboSamoor/polyglot/archive/master.zip
https://codeload.github.com/aboSamoor/polyglot/zip/master

Unzip và chạy tại folder và install bằng source thay vì dùng pip:
python setup.py install

Install một số libraries khác trên Windows.

Install libxml2, libxslt:
pip install lxml

Install SQLAlchemy:
pip install SQLAlchemy


2017-02-16

Notepad++: Remove lines containing/not containing string/word

Đôi khi dùng Notepad++ để remove lines chứa string hay word nào đó có thể sử dụng Regular Expression với negative lookbehind. Dùng nhiều nhưng giờ mới note lại ở đây để nhớ.

Tham khảo link
http://stackoverflow.com/questions/1971738/regex-for-all-strings-not-containing-a-string
http://stackoverflow.com/questions/406230/regular-expression-to-match-a-line-that-doesnt-contain-a-word

Ví dụ muốn remove nhưng line chứa warning hay error thực hiện như sau

^((?!(error|warning)).)*$



Sau đó có thể remove empty lines dùng Edit » Line Operation » Remove Empty Lines hay TextFX » TextFX Edit » Delete Blank Lines.

Nếu ngược lại muốn remove tất cả các lines ngoại trừ các lines chứa string/word. Thực hiện replace RegEx với empty như sau:

(?!^.*sometext.*$)^.+\r?\n
https://superuser.com/questions/290247/delete-all-lines-in-notepad-except-lines-containing-a-word-i-need/1318767#1318767?newreg=552307d560554536922266c54ac56cb7

2017-01-11

Tại sao chiều cao gần như tuân theo phân phối chuẩn ...?

Trong hầu hết các sách về lý thuyết xác xuất thống kê đều lấy ví dụ như vậy.

Đại khái là chiều cao của con người (hay đàn ông/phụ nữ ...) là một biến ngẫu nhiên tuân theo quy luật phân phối chuẩn. Hay khi textbook đề cập hầu hết các hiện tượng sinh học trong tự nhiên (or nhiều hiện tượng trong tự nhiên) gần như tuân theo phân phối chuẩn.

Khi học mình đến đây mình cũng thắc mắc ngay (trong đầu và để đó). Mới đầu mình cũng chưa hình dung vì sao, cứ để tạm đó xem, chắc có một lý do gì thôi. Sau đó chẳng thấy có giải đáp mẹ gì cả, cũng đặt câu hỏi tại sao lại như thế, nhưng cũng chẳng hỏi ai (ít lên lớp, lên cũng nằm ngáp ngáp). Và mình đã ngồi search kiếm câu trả lời. Gần đây có đứa em hỏi tại sao :D. Lâu rồi mình cũng mới thấy có người hỏi như vậy (trước đây khá lâu cũng có vài lần được hỏi...).

Thật ra có nhiều câu trả lời. Trên Quora thôi là đã rất nhiều (rất tiếc chẳng có phiên bản Quora tiếng Việt nào) mà hình như cũng không nhiều người xài Quora. Ví dụ:

Why do quantities in nature tend to be normally distributed, such as students' grade, human's height, size of snowflakes and so on. However, we find the returns of assets (like stocks, bonds, options) don't follow normal distribution (fat tail),How to explain it?

What are some real world examples of normally distributed quantities?


Bạn có thể tham khảo cả hai bài sau của John D. Cook (rất dễ hiểu)

Why hieghts are not normally distributed?


Mình tóm tắt lại bài đầu như sau:

Nếu chiều cao là một đặc tính di truyền đơn giản (simple genetic characteristic) thì sẽ quy định chiều cao là cao hoặc lùn (:D). Ví dụ tác giả nói rằng trong thí nghiệm di truyền của Mendel, Mendel có để là đậu nhăn nheo hoặc mịn chứ không để thuộc tính đậu hơi nhăn nheo. 

Có rất nhiều yếu tố di truyền và cả môi trường ảnh hưởng đến chiều cao. Theo đó nhiều yếu tố độc lập góp thành (sum) sẽ tạo nên một phân phối Gauss (Gaussian distribution) theo định lý giới hạn trung tâm (central limit theorem CLT).

2016-12-26

Castle Windsor Part 2 - Array configuration, dictionary configuration

Xem original

Part 2 – Array Configuration
Part 3 – Dictionary configuration

Array configuration

Đầu tiên là config array.

Ví dụ holiday service có code như sau:
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using System;

namespace ConsoleApp
{
    public class HolidayService
    {
        private DateTime[] holidays;

        public DateTime[] Holidays
        {
            get { return holidays; }
            set { holidays = value; }
        }

        public bool IsHoliday(DateTime date)
        {
            if (holidays != null)
            {
                DateTime matchDate = date.Date;
                foreach (DateTime dt in Holidays)
                {
                    if (dt.Date.Equals(matchDate))
                    {
                        return true;
                    }
                }
            }

            return false;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            WindsorContainer container = new WindsorContainer(new XmlInterpreter());

            HolidayService holidayService = container.Resolve<HolidayService>();

            DateTime xmas = new DateTime(2016, 12, 25);
            DateTime newYears = new DateTime(2017, 1, 1);

            if (holidayService.IsHoliday(xmas))
            {
                Console.WriteLine("Merry X'mas!");
            }
            else
            {
                Console.WriteLine("X'mas is only for management!");
            }

            if (holidayService.IsHoliday(newYears))
            {
                Console.WriteLine("Happy new year!");
            }
            else
            {
                Console.WriteLine("New year, you haven't done all the work for last year!");
            }

            Console.ReadLine();
        }
    }
}
Config trong App.config như sau:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component type="ConsoleApp.HolidayService, ConsoleApp">
        <parameters>
          <holidays>
            <array>
              <item>2016-12-24</item>
              <item>2016-12-25</item>
              <item>2017-1-1</item>
            </array>
          </holidays>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Có thể dùng <Holidays> hoặc <holidays> đều được vì Windsor đủ smart để inject. Nếu muốn resolve trực tiếp ra IList (hoặc IList, IEnumerable ... nói chung là generic collection)
static void Main(string[] args)
{
    WindsorContainer container = new WindsorContainer(new XmlInterpreter());
    var holidays = container.Resolve<IList<DateTime>>("holidays");
    Console.WriteLine(string.Join("\r\n", holidays));
    Console.ReadLine();
}
File config tương ứng như sau:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component id="holidays" type="System.Collections.Generic.List`1[System.DateTime]">
        <parameters>
          <collection>
            <array>
              <item>2016-12-24</item>
              <item>2016-12-25</item>
              <item>2017-1-1</item>
            </array>
          </collection>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>

Cần nhớ ở dạng config này là thực hiện theo <parameters><collection><array><item>. Nếu đầy đủ hơn thì type chỉ định có cả assembly là <component id="holidays" type="System.Collections.Generic.List`1[[System.DateTime, mscorlib]], mscorlib">.

Dictionary configuration

Tương tự như array, dictionary configuration thực hiện với <parameters><dictionary><dictionary><entry>. Ví dụ AliasService như sau:
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using System;
using System.Collections.Generic;

namespace ConsoleApp
{
    public class AliasService
    {
        private Dictionary<string, string> dict;

        public Dictionary<string, string> Aliases
        {
            get { return dict; }
            set { dict = value; }
        }

        public string Evaluate(string term)
        {
            if (dict == null)
            {
                return term;
            }

            while (dict.ContainsKey(term))
            {
                term = dict[term];
            }

            return term;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            WindsorContainer container = new WindsorContainer(new XmlInterpreter());

            AliasService aliasService = container.Resolve<AliasService>();
            string sentence = "A dog ate my homework";

            foreach (string word in sentence.Split(new char[] { ' ' }, 
                StringSplitOptions.RemoveEmptyEntries))
            {
                Console.Write("{0} ", aliasService.Evaluate(word));
            }

            Console.ReadLine();
        }
    }
}
App.config cấu hình dictionary:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component type="ConsoleApp.AliasService, ConsoleApp">
        <parameters>
          <Aliases>
            <dictionary>
              <entry key="dog">duck</entry>
              <entry key="ate">broke</entry>
              <entry key="homework">code</entry>
            </dictionary>
          </Aliases>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Để resolve trực tiếp ra IDictionary
static void Main(string[] args)
{
    WindsorContainer container = new WindsorContainer(new XmlInterpreter());
    var states = container.Resolve<IDictionary<string, string>>("states");
    Console.WriteLine(string.Join("\r\n", states.Keys));
    Console.ReadLine();
}
File config tương ứng như sau:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component id="states" type="System.Collections.Generic.Dictionary`2[System.String, System.String]">
        <parameters>
          <dictionary>
            <dictionary>
              <entry key="VN-CT">Cần Thơ</entry>
              <entry key="VN-DN">Đà Nẵng</entry>
              <entry key="VN-HN">Hà Nội</entry>
              <entry key="VN-HP">Hải Phòng</entry>
              <entry key="VN-SG">Hồ Chí Minh</entry>
            </dictionary>
          </dictionary>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Tới đây là xong part 2. Về type convertor có thể tham khảo thêm phần Configuration with type converters trong series của Mike Hadlow '10 Advanced Windsor tricks'.

Container tutorials ... example with Castle Windsor. Part 1 - Configuration parameters.

Mình dùng Castle Windsor từ lâu. Cũng có note nhưng rồi để đâu mất. Mình đã tính viết 1 series làm sao đủ để xài Windsor từ cái thời còn dùng CAB/SCSF, sau đó là Prism nhưng rồi chẳng biết sao lúc đó bỏ nửa chừng.

Inversion of Control (IoC), Dependency Inversion Principle (DIP) và Dependency Injection (DI), CAB&SCSF cũng chỉ viết tới Part 03: Dependency Injection

Gần đây coi lại và thấy lần này nên note kỹ. Nói chung đầu tiên là lược dịch từ những tutorials trên NET bắt đầu từ series trên BitterCoder (đã rất lâu rồi từ tận 2007). Có thể đọc thêm hướng dẫn từ project chính thức trên Github castleproject/Windsor.

Gần đây có nhiều lựa chọn IoC container cho .NET gồm có Autofac, StructureMap, Unity. Một vài container có vẻ dần chiếm được nhiều quan tâm hơn như Autofac với simple API, dễ sử dụng và performance tốt. Tuy nhiên Windsor nói chung vẫn đáp ứng được yêu cầu đặt ra với nhiều module (facilities) từ logging, NHibernate, ASP.NET MVC ...

Configuration parameters

Part đầu tiên là configuration parameters. Windsor cho phép cấu hình component với parameters run-time. Mặc dù có thể configuration với .NET qua app.config bình thường nhưng sử dụng với Windsor khá là đơn giản và tiện dụng.

Tạo một Project ConsoleApp, dùng NuGet install Castle Windsor. Tạo file app.config.


Giả sử có một class là Tax, mặc định tax rate là 10%. Có thể config rate thông qua app.config.
public class Tax
{
    private decimal rate = 0.10m;

    public decimal Rate
    {
        set { rate = value; }
        get { return rate; }
    }

    public decimal Calculate(decimal gross)
    {
        return Math.Round(rate * gross, 2);
    }
}
Sau khi tạo class Tax, thực hiện dùng với Windsor như sau:
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using System;

namespace ConsoleApp
{
    public class Tax
    {
        private decimal rate = 0.10m;

        public decimal Rate
        {
            set { rate = value; }
            get { return rate; }
        }

        public decimal Calculate(decimal gross)
        {
            return Math.Round(rate * gross, 2);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            WindsorContainer container = new WindsorContainer(new XmlInterpreter());

            // Resolve
            Tax calculator = container.Resolve<Tax>();

            decimal gross = 100;
            decimal tax = calculator.Calculate(gross);

            Console.WriteLine("Gross: {0}, Tax: {1}", gross, tax);
            Console.ReadLine();
        }
    }
}
Container được tạo với XmlInterpreter() sẽ đọc configuration từ file app.config (hoặc web.config với web app), instance calculator được tạo bởi container thông qua Resolve().

Thực hiện Build và Run sẽ ra báo lỗi không có config section 'castle'.
Thực hiện thêm config section vào App.config. Giả sử App.config không có cấu hình component sẽ gây exception ComponentNotFoundException
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Thực hiện config component nhưng không set tax rate như sau
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component id="tax" type="ConsoleApp.Tax, ConsoleApp">
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Type có thể không cần dùng AssemblyQualifiedName mà để đơn giản là Tax hoặc ConsoleApp.Tax cũng OK. Kết quả trả ra 'Gross: 100, Tax: 10.00'.

Thực hiện setup rate bằng parameters như sau:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component id="tax" type="ConsoleApp.Tax, ConsoleApp">
        <parameters>
          <rate>0.25</rate>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Kết quả trả ra 'Gross: 100, Tax: 25.00'.

Với id="tax" có thể dùng để resolve component khác nhau, ví dụ:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component id="tax1" type="ConsoleApp.Tax, ConsoleApp">
        <parameters>
          <rate>0.25</rate>
        </parameters>
      </component>
      <component id="tax2" type="ConsoleApp.Tax, ConsoleApp">
        <parameters>
          <rate>0.05</rate>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
và code
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
decimal gross = 100;

// Resolve tax #1
Tax calculator1 = container.Resolve<Tax>("tax1");
decimal tax1 = calculator1.Calculate(gross);
Console.WriteLine("Gross: {0}, Tax: {1}", gross, tax1);

// Resolve tax #2
Tax calculator2 = container.Resolve<Tax>("tax2");
decimal tax2 = calculator2.Calculate(gross);
Console.WriteLine("Gross: {0}, Tax: {1}", gross, tax2);

Console.ReadLine();
Như vậy coi như là đủ cho part 1. Phần tiếp theo sẽ thực hiện config arrays, dictionary ...

2016-12-24

How to integrate SyntaxHighlighter to Blogger, Blogspot

Dạo gần đây post nhiều code, nhìn lại mới thấy blogger của mình post code rất ẹ. Vì vậy phải chuyển qua một dạng OK cho đồng nhất. Search một vòng và mình chọn Syntax Highlighter vì thấy nó đơn giản và nhìn rõ ràng. Hướng dẫn integrate vào Blogger/Blogspot thì có nhiều ngay tại trang chính SyntaxHighlighter.

Nói sơ qua một chút như sau. Thông thường khi viết code có thể đơn giản dùng tag blockquote được hỗ trợ sẵn <blockquote></blockquote> và post source vào đó. Tuy nhiên source sẽ không được highlight syntax và sẽ khó đọc 1 chút. Hay vẫn có thể dùng http://hilite.me/ như trước đây. Nhưng nói chung là vẫn cảm thấy không được tốt lắm.

Một cách khác là embbeded gist trên Github. Có thể tham khảo tại đây
Embedding Github code into your Blogger blog
SyntaxHighlighter là một các embedded trực tiếp dùng Javascript,  có thể download và dùng dễ dàng với bất kỳ website nào, không loại trừ Blogger/Blogspot. Nó giống như dạng MathJax.

Cơ bản như sau:
1. Download và put tại host/web server

2. Thực hiện theo các bước hướng dẫn tại http://alexgorbatchev.com/SyntaxHighlighter/manual/installation.html

3. Dùng config và brush alias tương ứng với language của source code http://alexgorbatchev.com/SyntaxHighlighter/manual/configuration/

Với Blogger/Blogspot, vào Template
1. Để chắc ăn thực hiện backup Template » Backup/Restore » Download template

2. Vào Edit HTML, trong tag <head> thực hiện include CSS, Javascript và init code cần thiết tùy theo version với link bắt đầu http://alexgorbatchev.com/pub/sh/. Version hiện tại là
3.0.83 ngày 2016/12/24. Hay có thể dùng CDN https://cdnjs.com/libraries/SyntaxHighlighter (Blogger dùng với https). Có thể dùng theme default, Eclipse hay midnight. Include các brush thông dụng như C++, Java, C#, Scala, Python, CSS, SQL, XML... Thực hiện config Blogger mode bật ON. Save và kiểm tra có lỗi Javascript hay không.

3. Thực hiện test bằng cách đơn giản nhất là dùng tag <pre>, tất nhiên là phải chuyển qua HTML code, xong copy source từ source file hay IDE hay text editor như Notepad++ qua. Nên bật ruler và tắt toolbar.

Set defaults như sau:
SyntaxHighlighter.defaults['tab-size'] = 4;
SyntaxHighlighter.defaults['toolbar'] = false;

Ngay sau khi gọi SyntaxHighlighter.all()

<pre class="brush: csharp; toolbar: false;">
using namespace System;
namespace Demo
{
    public class Pet
    {
        public string Name { get; set; }

        public Pet()
        {

        }
    }
}
</pre>

Kết quả như sau:

using namespace System;
namespace Demo
{
    public class Pet
    {
        public string Name { get; set; }

        public Pet()
        {

        }
    }
}

Cách thứ 2 là để trong tag script và bắt buộc có CDATA

<script type="syntaxhighlighter" class="brush: js"><![CDATA[
/**
 * SyntaxHighlighter
 */
function foo()
{
 if (counter <= 10) {
  return;
 }

 // it works!
}
]]></script>

Dùng first-line để chỉ định line number đầu tiên trên ruler và highlight dùng chỉ định highlight line number nào. Ví dụ:
<pre class="brush: php; toolbar: false; auto-links: false; first-line: 10; highlight: [11, 13]">
  /**
    * https://github.com/syntaxhighlighter
    */
  echo("https://github.com/syntaxhighlighter");
</pre>

Kết quả sẽ là

  /**
    * https://github.com/syntaxhighlighter
    */
  echo("https://github.com/syntaxhighlighter");

2016-11-30

Retained Fragment, headless Fragment là gì, setRetainInstance(true)?

Thực ra mình cũng định nhắc tới headless Fragment từ lâu. Cũng vài năm rồi, dạo gần đây có đụng lại Android, cần phải giải thích, có search 1 vòng nhưng vẫn không thấy một bài viết tiếng Việt nào có sẵn nên note luôn ở đây. Post này không bàn chi tiết về code, hay cụ thể trường hợp sử dụng headless Fragment nào chỉ focus chung vào đặc điểm của headless Fragment và một vài case thông dụng.

Headless Fragment là gì?

Đầu tiên là tên gọi headless Fragment? Nhiều developer khác gọi là viewless Fragment, UI-less Fragment, retained Fragment không có view hay nhiều khi còn gọi là retained "worker" Fragment lý do sẽ đề cập sau là Fragment này thông thường được sử dụng để manage một worker hay background operation.

Tất nhiên cái tên này làm liên tưởng nhiều đến kỵ sĩ không đầu headless horseman/knight.

Có nhiều developer thông tin rằng tên gọi này bắt nguồn từ tutorial của Lars Vogel tại
Multi-pane development in Android with Fragments - Tutorial#Headless Fragments.

Vậy headless Fragment cụ thể là gì? Mặc dù tên là headless Fragment nhưng tính năng đáng nói nhất lại là "retained" qua configuration change.

setRetainInstance(true)

Mặc định Fragment sẽ bị hủy (destroyed) và tạo lại (recreated) cùng với parent Activity. Việc sử dụng Fragment#setRetainInstance(true) sẽ giúp Fragment được giữ lại retained khi Activity được tạo lại (recreation).

LƯU Ý: điều này chỉ áp dụng với các Fragment KHÔNG NẰM TRONG BACK STACK.

Trạng thái của Fragment sẽ được retained (duy trì, giữ lại) khi configuration change. Điều này "retained" có nghĩa là Fragment sẽ không bị destroyed khi configuration changes. Cũng có nghĩa là Fragment sẽ được giữ lại ngay cả khi configuration change làm cho Activity bị destroyed.

Tất nhiên cần nói rõ thêm. Giống như Activity, Fragment vẫn có thể bị destroyed bởi hệ thống khi tài nguyên bộ nhớ xuống thấp. Khi đó dù có thiết lập "retained" hay không thì hệ thống cũng sẽ destroy các Fragment này khi rời khỏi Activity. Trong trường hợp rời khỏi Activity (ví dụ nhấn nút home), Fragment có thể có hoặc không bị hủy. Nhưng khi rời khởi Activity bằng nút back (việc đó sẽ gọi finish() và sẽ destroy Activity), tất cả các Fragment cũng sẽ bị destroy.

Xem thêm Understanding Fragment's setRetainInstance(boolean) trên Stackoverflow,
Handling configuration changes with Fragments của Alex Lockwood

UI-less + setRetainInstance(true)

Headless Fragment là Fragment không có/không định nghĩa UI hay có nghĩa không inflate một View nào. Tài liệu chính thức của Adroid nói về headless Fragment là Fragment without UI tại Fragments guide/Adding a fragment without a UI. Tuy nhiên trong đoạn này có một chỗ ko rõ ràng là 

"This adds the fragment, but, because it's not associated with a view in the activity layout, it does not receive a call to onCreateView(). So you don't need to implement that method".

Chính xác thì Android có gọi Fragment#onCreateView() nhưng kết quả trả về là null. Tức là thay vì không override Fragment#onCreateView() thì vẫn có thể implement trả về null.

Ví dụ đi kèm SDK là /APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java có thể xem online tại FragmentRetainInstance.

Nhưng chỉ headless không thì cũng không có ý nghĩa gì đặc biệt: đáng nói ở đây thông thường là kết hợp headless Fragment và setRetainInstance(true) còn gọi là retained headless Fragment.

Thực tế thì headless Fragment thường sẽ đi kèm với "retained" hay cũng sẽ là retained headless Fragment nên retained sẽ "vô tình" bị bỏ đi. Vì Fragment không có UI chỉ dùng với mục đích manage Object nào đó thường là background operation.

UI + setRetainInstance(true)

Việc Fragment có UI và sử dụng setRetainInstance(true) vẫn không có vấn đề gì dù trong trường hợp retained này có thể xảy ra một temporary memory leak.

Fragment có UI và developer cần thao tác với các UI. Việc thao tác thực hiện thông qua reference tới các UI/View dùng findViewById chẳng hạn. Với retained Fragment, các reference cũng được "retained" kéo theo View cũng sẽ được "retained". Do đó có thể gây temporary memory leak vì View internal giữ Context của Activity. Giả sử configuration change từ "portrait" sang "landscape". Fragment giữ Context của "portrait" Activity và 1 text box (View) cũng giữ Context của "portrait" Activity. Khi configuration change hoàn thành reference tới Activity sẽ được update lại, ví dụ trong onViewCreated, text box sẽ reference tới với "landscape" Activity. Tức trước khi việc này xảy ra, text box vẫn giữ reference của "portrait" Activity. Việc này có thể ngăn cản "portrait" Activity cũ được thu hồi bởi GC. Hiển nhiên, nếu không cẩn thận, ví dụ giữ một reference tới chính activity trong Fragment thì memory leak thật sự có thể xảy ra.

Đó là lý do "retained" mới là tính năng quan trọng hơn là headless. Headless chỉ là tính năng phụ kéo theo khi Fragment không cần xử lý UI.

Usage

Headless Fragment rất hữu dụng khi nó là "worker" Fragment khi nó giữ các object như Thread, AsyncTask, Socket, etc ...

Ví dụ thông thường là retain một AsyncTask qua configuration change sử dụng headless Fragment. Việc này sẽ bảo đảm rằng progress sẽ cập nhật và kết quả sẽ trả về cho currently displayed Activity instance (Activity đang hiển thị) và bảo đảm sẽ không bị leak leak AsyncTask khi configuration change.

Khi Activity tạo lại thì Fragment sẽ được hệ thống xác định theo ID hoặc tag (nếu không chỉ định cả hai hệ thống sẽ lấy theo ID của container view) để find/restore Fragment. Headless Fragment sẽ được thêm programmatically tức là thêm bằng code nên trong trường hợp của headless fragment unique identifier là tag. Đơn giản trong onCreate của Activity nếu không tìm thấy "retained" Fragment với findFragmentByTag thì  thực hiện add mới Fragment và start background operation. Reference tới Activity sẽ được update thông qua onAttach và onDetach.

Kết quả là headless Fragment có thể dùng để retain Presenter (MVP) do Presenter thường dùng long running background operation. Cách này cũng được Mosby 2 sử dụng.

Headless Fragment cũng có thể được sử dụng để tổ chức việc Ask runtime permission theo như bài viết trên Medium Use headless Fragment for Android M run-time permissions and to check network connectivity.