13 Ağustos 2018 Pazartesi

Android Fragment Caching

Uygulamanızda birden çok fragment olduğunu ve aynı fragmentları tekrar tekrar kullandığınızı varsayın. Yapmak istediğimiz ise kullanılan fragmentları cachelemek ve tekrar oluşturma maaliyetinden kurtulmak, bellek yönetimiyle uğraşmamak. Bunun Fragment API da bulunan için hali hazırda bir sınıf var. FragmentManager.

NEDEN

Örnek olarak instagram uygulamasında 5 tane tab var ve her sayfa kendi içinde scroll edildiğinde aynı data ve aynı pozisyonda kaldıkları yerden devam edebiliyor. Bizim yapmak istediğimizde bu şekilde hem data hem de UI hiç bozulmadan kaldığı yerden devam edebilecek bir yapı inşa etmek. 

NASIL

1.Adım

add methodunu kullanarak sürekli yeni fragment oluşturmuş oluruz. Yani ne datayı ne de UI saklamış oluruz. Yani yapmamız gereken replace i kullanmak. 

FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
Fragment frStack = manager.findFragmentByTag("Tag");


if (frStack == null) {
    transaction.replace(R.id.main_fl, frNew, "Tag");
} else {
    transaction.replace(R.id.main_fl, frStack);
}
transaction.addToBackStack(null);
transaction.commit();


Yukarıda yapmak istediğimiz yeni oluşturulacak olan fragment stackte var mı(findFragmentByTag). Eğer yoksa yeni fragmentı ekle varsa eski mevcutta oluşturulmuş olan fragmentı.

2.Adım

Ama replace ile çağırdığımızda da göreceksiniz ki oncreateview onresume … methodlarına tekrar girecek (bakınız fragment lyfecycle ). Yapmamız gereken ne oncreateview() veya onresume methodunda çağırdığınız fonksiyonları tekrardan çağırmadan sadece rootview i return etmek.

private View view;
private boolean isLoaded;

@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup cntr,Bundle savedInstanceState) {

    if (isLoaded == false) {
        view = inflater.inflate(R.layout.fragment_scroll, cntr);
...
        service call, findbyViewIds ...
...
        isLoaded = true;
    }

    return view;
}

2.adımı farklı yöntemlerle de yapabilirsiniz! Önemli olan sayfa ilk açıldığında yapılması gereken işlemlerin -servis çağrısı, setonclick işlemleri gibi- replace de yapılmaması. 

SONUÇ

Aşağıdaki ekran görüntüsünden tüm fragmentların durumlarını koruduğunu görebilirisniz. Örnek proje linkte mevcut.
DİPNOT1

Burada show()-hide() yolunu da izleyebilir, caching neden gerekli diyebilirsiniz. Ama bu yöntem tüm fragmentlarınızı ayakta tutar yani hepsi aslında onresume da kalır. Replace ettiğiniz fragmentler ise sırasıyla pause stop… methodlarından geçer yani container dan tamamen o fragmentı sökmüş olursunuz. Replace etmek “hide ardından show etme” işlemi göre daha maaliyetli olmasına karşın memory den kazandırma gibi önemli bir kozu var. Hide ettikten sonra ayakta kalan tüm fragmentlarınızın heap te kaldığını ve outofmemory hatası alabileceğinizi göz önünde bulundurmalısınız. 

DİPNOT2

transaction.addToBackStack(null);

addtobackstack methodu yaptığımız replace işleminin stackte bir karşılığı olduğunu belirtiyor. Aksi halde tablar arası geçişte cachte ten hiçbirşey gelmediğini ve geri butonunda tüm fragmentlarınızın tek seferde kaybolduğunu göreceksiniz.