Verilerin kalıcı olması için Android Uygulama sınıfını kullanma


112

Uygulama hakkında biraz büyük miktarda veri gerektiren oldukça karmaşık bir Android uygulaması üzerinde çalışıyorum (toplam yaklaşık 500KB diyebilirim - bir mobil cihaz için bu kadar büyük mü?). Söyleyebileceğim kadarıyla, uygulamadaki herhangi bir yönelim değişikliği (daha kesin olmak gerekirse, faaliyette), faaliyetin tamamen yok olmasına ve yeniden yaratılmasına neden olur. Bulgularıma göre, Uygulama sınıfı aynı yaşam döngüsüne sahip değildir (yani, tüm amaç ve amaçlar için her zaman somutlaştırılmıştır). Durum bilgisini uygulama sınıfının içinde saklamak ve ardından Aktiviteden buna referans vermek mantıklı mıdır, yoksa mobil cihazlardaki bellek kısıtlamaları nedeniyle bu genellikle "kabul edilebilir" yöntem değil midir? Bu konudaki herhangi bir tavsiyeyi gerçekten takdir ediyorum. Teşekkürler!


8
Uygulamanızın arka plana geçmesi durumunda Uygulamanızdaki verilerin yine de silinebileceğini unutmayın; bu nedenle, bu, her zaman geri almak istediğiniz verileri kalıcı hale getirmek için bir çözüm değildir. Pahalı nesneleri sık sık yeniden yaratmak zorunda olmamanın bir yöntemi olarak hizmet eder.
Cheryl Simon

2
Mayra; Uygulamanın "genellikle" silinmiş olduğunu sanmıyorum (yine de, birisinin bu ileti dizisinde daha sonra işaret ettiği gibi, "olabilir"). Muhtemelen verileri depolamak ve yüklemek için uygulamayı kullanmanın bir tür "karma" yaklaşımını kullanacağım, ancak daha sonra, normal davranışını geçersiz kılmak için bildirim dosyasındaki etkinlikte "android: yönelim" özniteliğini kullanacağım. aktiviteyi yıkmak ve yeniden inşa etmek. Elbette tüm bunlar, uygulamanın "ne zaman" yok edileceğini belirleyebileceğini varsayar, böylece veriler kalıcı olabilir.
Dave

Yanıtlar:


134

500kb'nin o kadar büyük bir anlaşma olacağını sanmıyorum.

Tanımladığınız şey, bir faaliyetteki veri kaybı sorunumla tam olarak nasıl başa çıktığım. Application sınıfında global bir singleton oluşturdum ve kullandığım aktivitelerden ona erişebildim.

Çok fazla kullanılacaksa, verileri Global Singleton'da iletebilirsiniz.

public class YourApplication extends Application 
{     
     public SomeDataClass data = new SomeDataClass();
}

Ardından herhangi bir aktivitede şu şekilde arayın:

YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.

Bunu burada blog yazımda "Global Singleton" bölümünde tartışıyorum .


1
Maalesef söz konusu blog yazısı artık bu adreste mevcut değil.
mikebabcock

1
Sitemde bir şeyler hareket ettiriyorum. Düzeltilene kadar, archive.org'da burada bulabilirsiniz: web.archive.org/web/20130818035631/http://www.bryandenny.com/…
Bryan Denny

1
Bunun eski bir gönderi olduğunu biliyorum ama bunun çözebileceği bir sorunla karşılaştım, ancak bu sınıfın bir şekilde manifestte açıklanması gerekiyor, değil mi? Sınıfa katılamıyorum, bu yüzden eksik olduğum şey buymuş gibi hissediyorum ...
Ziv Kesten

1
@ZivKesten Manifest içindeki uygulama etiketine name = niteliğini eklemeye ne dersiniz?
MikeC

@mgc teşekkür ederim bir süredir ve evet, sonunda bu şekilde çalıştım, ayrıca bu sınıfa bir oyuncu kadrosuyla getApplicationContext () vererek o sınıfın örneklerini de yarattım
Ziv Kesten

57

Güvenebilir yapanlar Applicationörneği yanlıştır. İlk başta, Applicationtüm uygulama süreci var olduğu sürece varmış gibi görünebilir, ancak bu yanlış bir varsayımdır.

İşletim sistemi, süreçleri gerektiği gibi öldürebilir. Tüm işlemler, belgede belirtilen "öldürülebilirliğin" 5 seviyesine bölünmüştür. .

Örneğin, kullanıcının gelen bir çağrıyı yanıtlaması nedeniyle uygulamanız arka planda çalışıyorsa, RAM'in durumuna bağlı olarak işletim sistemi sürecinizi sonlandırabilir (veya kesmeyebilir) (işlemdeki vakayı yok ederek Application) .

Bence daha iyi bir yaklaşım , verilerinizi dahili depolama dosyasında saklamak ve ardından etkinliğiniz devam ettiğinde okumaktır.

GÜNCELLEME:

Pek çok olumsuz geri bildirim aldım, bu yüzden bir açıklama eklemenin zamanı geldi. :) Başlangıçta, durumun uygulama için gerçekten önemli olduğuna dair yanlış bir varsayım kullandım. Bununla birlikte, uygulamanız bazen durum kaybolacak kadar iyi ise (sadece yeniden okunacak / yeniden indirilecek bazı resimler olabilir), o zaman bir üyesi olarak tutmak tamamen uygundur Application.


14
Uygulama öldürülürse, kimin umurunda, değil mi? Uygulama gitti. Anladığım kadarıyla Android, Etkinlikler gibi bellek içeren süreçleri geri kazanacak. Uygulamayı içeren işlem öldürülürse (Android bunu bile yapacaksa?), Bu aslında uygulamayı öldürmek gibidir. Kullanıcının uygulamayı tekrar başlatması gerekecek ve bu noktada kimin umurunda? Bu, uygulamanın yeni bir örneğidir.
Andrew

14
Bu, üretimde bizim için istenmeyen bir sürprizdi. İnanın bana Android süreçleri öldürür, bu sadece RAM durumuna ve belgelerde açıklanan diğer faktörlere bağlıdır. Bizim için bir kabustu, bu yüzden sadece gerçek deneyimlerimi paylaşıyorum. Emülatörlerde buna sahip değildik, ancak gerçek dünyada bazı cihazlar uygulamalarla 'aşırı yüklenmiş', bu nedenle bir arka plan sürecini öldürmek normal bir durumdur. Evet, kullanıcı daha sonra uygulamayı ön plana çıkarmaya karar verirse - işletim sistemi, Applicationörnek dahil yığınını geri yükler , ancak siz ısrar etmedikçe, hesaba katacağınız statik verileriniz olmayacaktır.
Vit Khudenko

2
Sanırım muhtemelen hibrit bir yaklaşım kullanacağım. Oryantasyon değişikliğini geçersiz kılmak için açık bir numarayı zaten biliyordum (başka faydaları da var). Uygulama bir oyun olduğu için, lansmanlar arasında verilerin kalıcı olmasının yeterince "önemli" olduğundan emin değilim; ancak verilerin çoğu serileştirilebileceği için muhtemelen çok zor olmayacaktır (her yönelim değişikliği arasında serileştirmek ve serileştirmek istemem). Giriş için kesinlikle minnettarım. Uygulama örneğine bağlı olanların "yanlış" olduğunu söyleyemem. Çok şey uygulamaya bağlıdır :).
Dave

1
@Arhimed Cevabınızı çok fazla genelliyorsunuz. Ve varsayımınıza dayalı olarak dar bir yaklaşım öneriyor. Yanlış Varsayım: Statik değişkenlerde tutulan verilerin uygulamanın oturumları boyunca saklanması gerekir. Verilerin önemsiz olduğu ve hemen saklanması gerekmeyen çok sayıda kullanım durumu olabilir.
Mandar Limaye

2
Karmaşık yapıya sahip yaklaşık 1mb veriye sahibim. Seri hale getirme / seri durumdan çıkarma, cihaz işle aşırı yüklendiğinde bana 2-3 saniyeye mal olabilir. Aktiviteler arasında kaydetme / yükleme fikri çok fazla zamana mal olur. Uygulamayı depolama olarak kullanıyorum. Elbette, uygulama örneğinde depolanan veri sınıfım her yöntemi kontrol ediyor - veriler hala canlı mı yoksa yüklenmesi gerekiyor mu. Bu yüzden Dave'in şunları yapması gerekir: 1. yükleme / kaydetme fonksiyonları sağlama 2. verileri uygulamada tutma. 3. Verilere erişim için üçlü kontrol mantığı.
Kostadin

6

Bir faaliyetin dışında "Global Singleton" a erişmek istiyorsanız Contextve singleton'u elde etmek için ilgili tüm nesnelerin üzerinden geçmek istemiyorsanız , uygulama sınıfınızda referansı tutan statik bir öznitelik tanımlayabilirsiniz. kendisi. Sadece onCreate()yöntemdeki özniteliği başlatın.

Örneğin:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

    public static ApplicationController getAppCtrl()
    {
         return _appCtrl;
    }
}

Çünkü alt sınıfları Application da Kaynakları alabildiğinden, bunlara yalnızca aşağıdaki gibi döndüren statik bir yöntem tanımladığınızda erişebilirsiniz:

public static Resources getAppResources()
{
    return _appCtrl.getResources();
}

Ancak, bellek sızıntılarını önlemek için Bağlam referanslarının etrafından dolaşırken çok dikkatli olun .


6
Sınıfın başlatılması için bildiriminizdeki uygulama etiketinin android: name = ". ApplicationController" xml niteliğini eklemeniz gerektiğini unuttunuz.
eggie5

Bunu yapmak için aslında uzatmanıza Applicationgerek yok. Bunu yapmak için herhangi bir sınıfta statik bir üye değişken bildirebilirsiniz .
David Wasser

2

Dave, bu ne tür veriler? Uygulamayla bir bütün olarak ilgili genel verilerse (örnek: kullanıcı verileri), Uygulama sınıfını genişletin ve orada saklayın. Veriler Activity ile ilgiliyse, verileri ekran döndürmede kalıcı hale getirmek için onSaveInstanceState ve onRestoreInstanceState işleyicilerini kullanmanız gerekir.


Ya veriler bir Parselde saklanacak kadar büyükse? Aldığım şey bu: android.os.TransactionTooLargeException: veri paketi boyutu 838396 bayt
Arjun Issar

1

Etkinliğinizin yok edilmediğinden ve yeniden oluşturulmadığından emin olmak için aslında yönlendirme işlevini geçersiz kılabilirsiniz. Buraya bak .


16
Bir çok şey yapabilirsiniz. İyi fikir oldukları anlamına gelmez. Bu iyi bir fikir değil.
Andrew

Ekran yönünü değiştirerek test etmek, uygulamanızın Android'in yapacağını varsaydığı şeyi yaptığından emin olmanın en kolay yoludur.
18446744073709551615

0

Uygulama sınıfı oluşturabilir ve tüm verilerinizi, uygulamanızın herhangi bir yerinde kullanmak için bu cals'lara kaydedebilirsiniz.


0

Bunun çok eski bir soru olduğunu biliyorum, ancak jetpack bileşenlerinden ViewModel'i kullanmak, Activity rotasyonu arasında verileri korumanın en iyi yoludur.

ViewModel sınıfı, UI ile ilgili verileri yaşam döngüsü bilinçli bir şekilde depolamak ve yönetmek için tasarlanmıştır. ViewModel sınıfı, verilerin ekran dönüşleri gibi yapılandırma değişikliklerinden kurtulmasına olanak tanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.