Uygulama her zaman tek bir ekrandan oluşmuyor. Örneğin, biz çok yarattık faydalı program ve kullanıcı yazarın kim olduğunu bilmek ister. “Hakkında” düğmesine tıklar ve programın sürümü, yazar, site adresi, yazarın kaç kedisi olduğu vb. hakkında faydalı bilgilerin bulunduğu yeni bir ekrana gelir. Bir aktivite ekranını, başka bir sayfaya bağlantı içeren bir web sayfası olarak düşünün. Dosyadaki koda bakarsanız MainActivity.javaönceki derslerden, bizim sınıfımızın Ana aktivite için de geçerlidir Aktivite(veya mirasçıları) veya daha doğrusu ondan miras alınır.
Genel sınıf MainActivity, AppCompatActivity'yi genişletir
Tahmin edebileceğiniz gibi, şuna benzeyebilecek yeni bir sınıf oluşturmalıyız. Ana aktivite ve sonra bir şekilde düğmeye tıklayarak ona geçin.
Deney için ilk dersten programı alıp deneyler için (veya oluştur) butonunu kullanacağız. yeni proje ekrandaki bir düğme ile). Ardından, oluşturalım yeni form göstermek kullanışlı bilgi. Örneğin kullanıcıya kedinin sağa sola gittiğinde ne yaptığını gösterelim. Katılıyorum, çok önemli bilgi, bu da evreni çözmenin anahtarını verir.
Stüdyonun hazır şablonları olmasına rağmen manuel olarak yeni bir aktivite oluşturacağız. Ancak karmaşık bir şey yok ve daha iyi anlamak için her şeyi elle yapmakta fayda var.
Yeni bir XML biçimlendirme dosyası oluşturalım aktivite_about.xml klasörde res/düzen. Klasöre sağ tıklayın Yerleşim ve arasından seçim yap bağlam menüsü Yeni | Düzen kaynak dosyası. Bir iletişim kutusu belirecektir. İlk alana dosya adını girin aktivite_about. İkincisinde, kök öğeyi girmeniz gerekir. Varsayılan olarak orada Kısıtlama Düzeni. Metni silin ve girin kaydırma görünümü. Stüdyonun hazır seçenekler önermesi için birkaç karakter girmek yeterlidir, kelimenin tam girişini beklemeden hemen Enter tuşuna basabilirsiniz:
Elemanı yerleştirdiğimiz ilgili boşluğu alıyoruz Metin görünümü.
Bilgiler kaynaklardan, yani bir dizi kaynağından alınacaktır. about_text. Şimdi bilgi yokluğunu gösteren kırmızıyla vurgulanır. basılabilir Alt+Enter ve diyalog kutusuna metin girin. Ancak örneğimiz için, metnimiz kontrol karakterlerini kullanarak çok satırlı olacağından bu yöntem çalışmayacaktır. Öyleyse farklı yapalım. dosyayı açalım res/values/strings.xml ve aşağıdaki metni manuel olarak girin:
Gibi en basit HTML metin biçimlendirme etiketlerini kullandık , , . Örneğimiz için kediye ve hareket yönüne atıfta bulunan kelimeleri kalın yazmak yeterlidir. Metni şu dile çevirmek için Yeni hat sembolleri kullan \n. Yeni ekranın başlığı için başka bir string kaynağı ekleyelim:
İşaretleme ile anlaşıldı. Ardından, pencere için bir sınıf oluşturmanız gerekir. AboutActivity.java. Menüden seçin dosya | Yeni | Java sınıfı ve gerekli alanları doldurun. İlk başta sadece isim belirtmek yeterlidir. Sonra diğer alanlarla ilgilenin.
Gelelim hazırlığa.
Şimdi sınıf neredeyse boş. Kodu manuel olarak ekleyelim. Sınıf, soyut sınıftan miras almalıdır Aktivite veya akrabaları FragmentAktivite, AppCompatActivity vb. Ekleme aktiviteyi genişletir. Activity sınıfının bir metodu olmalıdır. onCreate(). Fare imlecini sınıfın içine getirin ve menüden seçin kod | Geçersiz Kılma Yöntemleri(Ctrl+O). İletişim kutusunda, istenen sınıfı arıyoruz, klavyede ilk karakterleri yazabilirsiniz. hızlı arama. Oluşturulan yöntemde, yöntemi çağırmanız gerekir. setContentView(), hazırlanan işaretlemeyi ekrana yükleyecektir. Böyle bir seçeneğimiz olacak.
Paket en.alexanderklimov.helloworld; android.app.Activity'yi içe aktar; android.os.Bundle'ı içe aktar; /** * Alexander Klimov tarafından 12/01/2014 tarihinde oluşturuldu. */ public class AboutActivity, Activity'yi genişletir ( @Override protected void onCreate(Bundle saveInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); ) )
Şimdi en önemli şey başlıyor. Görevimiz ilk ekranda bir buton tıklandığında yeni bir ekrana geçmektir. hadi sınıfa geri dönelim Ana aktivite. Düğme tıklama işleyicisini yazalım:
Public void onClick(Görünüm görünümü) ( Amaç amacı = new Intent(MainActivity.this, AboutActivity.class); startActivity(intent); )
Burada derste açıklanan düğme tıklama işleme yöntemini kullandım.
Yeni bir ekran başlatmak için sınıfın bir örneğini oluşturmanız gerekir. niyet ve ilk parametrede mevcut sınıfı ve ikinci parametrede geçiş sınıfını belirtin, buna sahibiz HakkındaEtkinlik. Bundan sonra, yöntem denir startActivity(), bu da yeni bir ekran başlatır.
Şimdi uygulamayı öykünücüde test etmeye çalışırsanız, bir hata mesajı alırsınız. Neyi yanlış yaptık? Önemli bir adımı atladık. Yeni kayıt olmanız gerekiyor Aktivite manifestoda AndroidManifest.xml. Projenizde bu dosyayı bulun ve üzerine çift tıklayın. Dosya düzenleme penceresi açılacaktır. Yeni bir etiket ekle
Dize kaynağının kullanışlı olduğu yer burasıdır. about_title. Uygulamayı çalıştırın, düğmeye tıklayın ve pencereyi alın Program hakkında. Böylece yeni bir pencerenin nasıl oluşturulacağını ve bir buton tıklamasıyla nasıl çağırılacağını öğrendik. Ve elimizde çok uygun bir program ortaya çıktı - şimdi kedinin sola gittiğinde ne yaptığına dair her zaman bir ipucu olacak.
Bir kez daha, oluşturulan ikinci aktivite sınıfının sınıftan miras alınması gerektiğine dikkatinizi çekiyorum. Aktivite veya benzeri ( ListActivity vb.), bir XML biçimlendirme dosyasına sahip (gerekirse) ve bildirimde yazılı olmalıdır.
Yöntemi çağırdıktan sonra startActivity() yeni bir aktivite başlayacak (bu durumda HakkındaEtkinlik), görünür hale gelecek ve çalışan bileşenleri içeren yığının en üstüne taşınacaktır. Bir yöntemi çağırırken bitiş() yeni aktiviteden (veya donanım geri al tuşuna basıldığında) kapatılacak ve yığından kaldırılacaktır. Geliştirici, aynı yöntemi kullanarak önceki (veya başka herhangi bir) etkinliğe de gidebilir. startActivity().
Üçüncü bir ekran oluşturmak - tembeller için bir yol
Programcılar, kediler gibi tembel yaratıklardır. Her zaman, aktivite için işaretleme ve miras alan bir sınıf oluşturmanız gerektiğini unutmayın. Aktivite, ve sonra sınıfı manifestoya kaydetmeyi unutmayın - oh iyi, ne olur.
Bu durumda, menüden seçin dosya | Yeni | aktivite | temel aktivite(veya başka bir desen). Ardından, yeni bir aktivite oluşturmak için tanıdık pencere görünecektir. Gerekli alanları doldurun.
düğmesine tıklayın Bitiş ve aktivite hazır olacaktır. Bunu doğrulamak için bildirim dosyasını açın ve yeni girişi kontrol edin. Sınıf dosyalarından ve işaretlemeden bahsetmiyorum, önünüzde görünecekler.
Ana aktivitenin ekranına kendiniz yeni bir buton ekleyin ve oluşturulan aktiviteye gitmek için kodu yazın.
İlk başta, sınıf, işaretleme ve manifest arasındaki ilişkiyi anlamak için yeni bir aktivite için gerekli tüm bileşenleri manuel olarak oluşturmanızı tavsiye ederim. Ve elinize aldığınızda, işleri hızlandırmak için etkinlik oluşturma sihirbazını kullanabilirsiniz.
Aktiviteler arasında veri aktarımı
En basit örneği başka bir etkinlik ekranını çağırmak için kullandık. Bazen sadece yeni bir ekranı çağırmak değil, aynı zamanda ona veri aktarmak da gerekir. Örneğin, kullanıcı adı. Bu durumda, özel bir alan kullanmanız gerekir. extraData, sınıfın sahip olduğu niyet.
Bölge extraData bir çift listesidir anahtar/değer, niyetle birlikte iletilir. Dizeler anahtar olarak kullanılır ve değerler için herhangi bir ilkel veri türünü, ilkel dizileri, sınıf nesnelerini kullanabilirsiniz. demet ve benzeri.
Verileri başka bir etkinliğe iletmek için yöntemi kullanın putExtra():
Intent.putExtra("Anahtar", "Değer");
Alma etkinliği bazı uygun yöntemleri çağırmalıdır: getIntExtra(), getStringExtra() vb.:
Int sayı = getIntent().getIntExtra("ad", 0);
Önceki örneği yeniden yapalım. Halihazırda üç etkinliğimiz var. İlk aktivitede iki metin alanı ve bir düğme olacaktır. Görünüm aşağıdaki gibi olabilir:
İkinci aktivitede İkinci Etkinlik elemanı ayarla Metin görünümü, burada ilk aktiviteden alınan metni görüntüleyeceğiz. Yöntem için aşağıdaki kodu yazalım onCreate() ikinci aktivitede.
@Override protected void onCreate(Bundle saveInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); String user = "Animal"; String Gift = "donuthole"; TextView infoTextView = (TextView)findViewById( R .id.textViewInfo); infoTextView.setText(kullanıcı + " , size verildi " + hediye); )
Şimdi programı çalıştırırsak ve makalenin ilk bölümünde açıklandığı gibi ikinci pencereyi çağırırsak, varsayılan yazıtı göreceğiz. ZhYvotnoe, sana bir çörek deliği verildi. Katılıyorum, bu tür mesajları almak oldukça utanç verici.
Durumu düzeltiyoruz. İlk aktiviteye kod ekleyin:
Public void onClick(Görünüm görünümü) ( EditText userEditText = (EditText) findViewById(R.id.editTextUser); EditText GiftEditText = (EditText) findViewById(R.id.editTextGift); Amaç niyet = yeni Amaç(MainActivity.this, SecondActivity. class); // ilk metin alanındaki metni kullanıcı adı anahtarına itinint.putExtra("username", userEditText.getText().toString()); // ikinci metin alanındaki metni hediye anahtarına itin Intent.putExtra("gift ", GiftEditText.getText().toString()); startActivity(intent); )
Özel bir nesne kabına yerleştirdik niyet metin alanlarından alınan değerlere sahip iki anahtar. Kullanıcı metin alanlarına veri girdiğinde bu kapsayıcıya düşecek ve ikinci aktiviteye geçilecektir.
İkinci aktivite, aşağıdaki gibi (kalın harflerle vurgulanmıştır) mesajları sıcak bir şekilde almaya hazır olmalıdır.
// Varsayılan değerler String user = "LIFE"; Dize hediyesi = "çörek deliği"; kullanıcı = getIntent().getExtras().getString("kullanıcı adı"); hediye = getIntent().getExtras().getString("hediye"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(kullanıcı + " , size verildi " + hediye);
Şimdi mesaj o kadar rahatsız edici görünmüyor, hatta bazıları için hoş görünüyor. Karmaşık örneklerde, veri işleme sırasında doğrulama eklenmesi istenir. Gibi boş verilerle ikinci bir aktivite başlattığınız durumlar vardır. hükümsüz, bu uygulamayı çökertebilir.
Bizim durumumuzda, bir dize değeri beklediğimizi biliyoruz, bu nedenle kod şu şekilde yeniden yazılabilir:
niyet niyet = getIntent(); kullanıcı=intent.getStringExtra("kullanıcı adı");
Kullanıcı = getIntent().getStringExtra("kullanıcı adı");
Programın bir dezavantajı var - kimden selam aldığımız belli değil. İyi huylu hiçbir maymun, anonim bir kaynaktan gelen hediyeyi kabul etmeyecektir. Bu nedenle ödev için, mesajı gönderen kullanıcının adını girmek için başka bir metin alanı ekleyin.
Google, anahtarlar için şu biçimi kullanmanızı önerir: önek olarak paket adınız, ardından anahtarın kendisi. Bu durumda, diğer uygulamalarla etkileşim kurarken anahtarın benzersiz olduğundan emin olabilirsiniz. Yaklaşık olarak şöyle:
Genel son statik String USER = "ru.alexanderklimov.myapp.USER";
Kedi Vaska'yı kim çerçeveledi - sonucu geri alıyoruz
Verileri başka bir etkinliğe iletmek her zaman yeterli değildir. Bazen başka bir aktivite kapatıldığında ondan bilgi almanız gerekir. Eğer yöntemi daha önce kullandıysak startActivity(Niyet amacı), o zaman ilgili bir yöntem var startActivityForResult(Niyet amacı, int RequestCode). Yöntemler arasındaki fark, ekstra parametrede yatmaktadır. istek kodu. Temelde sadece kendin hakkında düşünebileceğin bir tam sayı. Sonucun kimden geldiğini ayırt etmek için gereklidir. Diyelim ki beş ek ekranınız var ve bunlara 1'den 5'e kadar değerler atadınız ve bu koddan kimin sonucunu işlemeniz gerektiğini belirleyebilirsiniz. -1 değerini kullanabilirsiniz, o zaman yöntemi çağırmaya eşdeğer olacaktır. startActivity(), yani sonuç alamayacağız.
Eğer yöntemi kullanıyorsanız startActivityForResult(), ardından sonucu almak için koddaki yöntemi geçersiz kılmanız gerekir. onActivityResult() ve sonucu işleyin. Kafası karışmış? Bir örneğe bakalım.
Diyelim ki bir dedektifsiniz. Restorandaki nüfuzlu bir kişinin masasından iki parça sosis ve diğer ürünlerin çalındığı bilgisi alındı. Şüphe üç şüpheliye düştü - bir karga, lanet bir köpek ve kedi Vaska.
Ziyaretçilerden biri duba iPhone'undan bir dizi fotoğraf verdi:
Başka bir tanığın ifadesi de var: Ve Vaska dinler ve yer.
Yeni bir proje oluşturuyoruz Sherlock iki aktivite ile. İlk ekranda ikinci ekrana geçmek için bir buton ve hırsızın adını gösterecek bir metin etiketi olacaktır.
İkinci ekranda bir grup radyo düğmesi olacaktır:
İkinci ekrandan cevap bekleyeceğimiz için yöntemi kullanmamız gerekiyor. startActivityForResult() değişkeni geçeceğimiz ilk ekranda CHOOSE_THIEF parametre olarak istek kodu.
statik son özel int CHOOSE_THIEF = 0; public void onClick(View v) ( Intent QuestionIntent = new Intent(MainActivity.this, ChooseActivity.class); startActivityForResult(questionIntent, CHOOSE_THIEF); )
Koda bak. Butona tıklandığında ikinci ekran ile çalışacağız. Aktivite Seçin ve sonucu bekleyen ikinci ekranı başlatın.
İkinci ekrana geçiyoruz ve ikinci aktivitenin kodunu yazacağız.
Genel final statik String THIEF = "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick(View v) ( Intent answerIntent = new Intent(); switch (v.getId()) ( case R.id.radioDog: answerIntent.putExtra(THIEF, "Lanet Köpek"); break; case R.id .radioCrow: answerIntent.putExtra(THIEF, "Crow"); break; case R.id.radioCat: answerIntent.putExtra(THIEF, "Przewalski's Horse"); break; varsayılan: break; ) setResult(RESULT_OK, answerIntent); bitiş (); )
Burada her şey basit, dedektif suçlunun adını seçtiğinde, ardından yöntemle putExtra() anahtarın adını ve değerini iletiyoruz.
Kolaylık sağlamak için seçimden sonra hemen ikinci pencereyi kapatıyoruz ve kapatmadan önce değeri geçiyoruz RESULT_OK seçimin yapıldığını açıklığa kavuşturmak için. Kullanıcı Back butonu ile ekranı kapatırsa değer geçilecektir. SONUÇ_İPTAL EDİLDİ.
Yöntem setResult() iki parametre alır: sonuçtaki kod ve bir amaç olarak temsil edilen sonucun kendisi. Ortaya çıkan kod, etkinliğin hangi sonuçla sona erdiğini söyler, kural olarak, ya Activity.RESULT_OK, veya Activity.RESULT_CANCELED. Bazı durumlarda, uygulamaya özel seçenekleri işlemek için kendi dönüş kodunuzu kullanmanız gerekir. Yöntem setResult() herhangi bir tamsayı değerini destekler.
Verileri düğmeden açıkça iletecekseniz, bir yöntem eklemek güzel olurdu bitiş() ikinci etkinliği gereksiz olarak kapatmak için. Geçiş Geri düğmesi aracılığıyla gerçekleşirse, bu gerekli değildir.
Aktivite, donanım geri düğmesine basıldığında kullanıcı tarafından kapatılmışsa veya yöntem bitiş() yöntemden önce çağrıldı setResult(), ortaya çıkan kod şu şekilde ayarlanacaktır: SONUÇ_İPTAL EDİLDİ ve döndürülen niyet değeri gösterecek hükümsüz.
İlk ekrana dönüyoruz. İlk ekran ikinci ekrandan yanıt bekliyor bu yüzden koda bir method eklemeniz gerekiyor onActivityResult().
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) ( super.onActivityResult(requestCode, resultCode, data); TextView infoTextView = (TextView) findViewById(R.id.textViewInfo); if (requestCode == CHOOSE_THIEF) ( if (resultCode == RESULT_OK) ( String thiefname = data.getStringExtra(ChooseActivity.THIEF); infoTextView.setText(thiefname); )else ( infoTextView.setText(""); // metni sil ) ) )
Yöntem, gelen verileri kodla bekler CHOOSE_THIEF ve bu tür veriler gelirse, değeri anahtardan alır SelectActivity.THIEF yöntemi kullanmak getStringExtra. Ortaya çıkan değeri şu şekilde çıkarıyoruz Metin görünümü(değişken infoTextView). Geri butonu ile ekrana dönersek, sadece metni sileriz.
Alt aktivite ana bileşen içinde kapatıldığında, işleyici harekete geçer. onActivityResult(). işleyici onActivityResult() birden fazla parametre alır.
- İstek kodu. Sonucu döndüren etkinliği başlatmak için kullanılan kod
- Ortaya çıkan kod. Alt etkinlik tarafından ayarlanan ve alt etkinliğin nasıl sona erdiğini gösteren bir sonuç kodu. Herhangi bir tamsayı değeri olabilir, ancak genellikle Activity.RESULT_OK, veya Activity.RESULT_CANCELED
- Veri. Döndürülen verileri paketlemek için kullanılan amaç. Alt etkinliğin amacına bağlı olarak, seçilen içerik parçasını temsil eden bir URI yolu içerebilir. Alternatif olarak (veya ek olarak), bir alt aktivite, bilgileri bir amaç parametresine sarılmış basit değerler olarak döndürebilir. ekstralar
Alt aktivite beklenmedik bir şekilde sona erdiyse veya kapatmadan önce sonuç kodu belirtilmediyse, bu parametre şuna eşit olacaktır: Activity.RESULT_CANCELED.
Projeye başlıyoruz butona tıklıyoruz ve ikinci ekrana geçiyoruz. Orada seçeneklerden birini seçiyoruz. Bir karga seçerseniz ekran kapanacak ve ilk ekranda suçlunun adı görüntülenecektir. Bir köpek seçerseniz, adı görüntülenecektir.
Bu arada, bir kedi seçerseniz, adı görüntülenmez! Kontrol edin ve kendiniz görün. neden diye soracaksın İlköğretim Watson! Suçlu, önemli bir ayrıntıyı dikkate almadı. Restoran, video kameraların gözetimi altındaydı ve kayıt, sosisi kimin çaldığını ve kediyi çerçevelediğini gösterdi. Vaska, bekle!
not İlk başta bir şey anlaşılmaz görünüyorsa, uygulama ile çok şey netleşecektir. Uygulamalarda ekranlar arasında veri geçişi yaygındır ve örneği bir kereden fazla çalışacaksınız.
P.P.S. En iyi balık sosisdir. Bu zayıflığı bilerek, kediyi çerçevelemek zor değildi.
Filtreleri kullanma
Makalede, yöntemdeyken başka bir etkinliğe geçmenin yaygın bir yolunu gösterdim. startActivity() mevcut sınıf ve geçiş yapılacak sınıf belirtilir. Bu arada, aktivite sınıfının uygulamanızın bir parçası olması gerekmez. Bir sınıfın adını başka bir uygulamadan biliyorsanız, buna da geçebilirsiniz. Ancak farklı bir şekilde başka bir etkinliğe geçebilirsiniz.
Pratikte daha az yaygın, ancak kullanışlıdır. Diyelim ki zaten ikinci bir etkinliğiniz var. Manifest'te buna özel bir filtre ekleyin:
Ve bu şekilde bir butona tıklayarak ikinci aktiviteyi başlatıyoruz.
Public void onClick(Görünüm görünümü) ( startActivity(new Intent("ru.alexanderklimov.testapplication.SecondActivity"); )
Uzun bir dizeyi bir sabitle değiştirelim.
Genel statik final String ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick(Görünüm görünümü) ( startActivity(new Intent(ACTION_SECOND_ACTIVITY)); )
Peki biz ne yaptık. İkinci aktivite için bir filtre kaydettik ve bir isim belirledik. eylem nitelik olarak android:isim. Kolaylık olması için, aktivitenin tam adını ve paketin adını koydum. sınıf oluşturucu niyet birkaç aşırı yüklenmiş versiyona sahiptir. Bir sürümde, eylem için bir dize belirtebilirsiniz. İkinci aktivitede kayıtlı olan oluşturduğumuz eylemimizi belirttik. Sistem, çalışma sırasında kurulu tüm uygulamaların bildirimlerine bakar. Bir eşleşme ararken, sistem filtremizi bulur ve istenen etkinliği başlatır.
Aynı prensiple başka faaliyetlere de başlayabilirsiniz. Bir örneğe bakın. Örneği kendinize kopyalarsanız ve belgelere bakarsanız android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS, bu kodun bir dize sabitine karşılık geldiğini göreceksiniz. genel statik final Java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS". Kodumuzla karşılaştırın. Çevrimdışı mod için ayar etkinliğinin filtrede bu satırı olduğunu varsayabilirsiniz.
Kategori adını filtrele android.intent.category.DEFAULT sisteme, etkinliği başlatmak için varsayılan eylemi gerçekleştirmesini söyler. Henüz ilgimizi çekmeyen başka isimler de var.
Ve şimdi zor bir soru. Başka bir etkinlik oluşturup ikinci etkinlikle aynı filtreyi belirtirseniz ne olur? Ve kontrol edelim. Kendiniz için üçüncü bir aktivite oluşturun ve ikinci aktivitedeki filtreli bloğu ona kopyalayın.
İlk aktivitede butona tıklıyoruz. Sistem sizden istenen seçeneği seçmenizi isteyecektir.
öğeyi seçerseniz HER ZAMAN o zaman bir dahaki sefere seçim yapmak zorunda kalmayacaksın. Seçimi sıfırlamak için Ayarlar'da uygulama özelliklerine gidin ve düğmeyi bulun. varsayılanları temizle.
Adına göre bir aktivite başlatmak
yapıcıda niyetİkinci parametre sınıftır. Ancak, etkinliklerin adlarının belirtildiği bir tür veritabanı olduğunu ve istenen etkinliği adıyla başlatmamız gerektiğini varsayalım. Dize değişkenine göre sınıfın kendisini alabilir ve aktiviteyi başlatabiliriz.
Deneyin ( // Aktivite sınıfının tam adı String ActivityName = "ru.alexanderklimov.testapplication.SecondActivity"; // Class Class nesnesini alın>myClass = Class.forName(etkinlikAdı); Amaç amacı = yeni Amaç(bu, benimSınıfım); startActivity(niyet); ) yakalama (ClassNotFoundException e) ( e.printStackTrace(); )
Bir şekilde hizmetten aktiviteye veri aktarma görevim vardı. Standart SDK'da çözüm arayışları başladı ancak vakit olmadığı için veri tabanı kullanmak şeklinde kötü bir karar verdim. Ancak soru açıktı ve bir süre sonra SDK'da olan daha doğru bir yol buldum - Message, Handler, Messenger sınıflarını kullanarak.
Fikir
Faaliyetten hizmete veri aktarmamız gerekiyor ve bunun tersi de geçerli. Nasıl yapabiliriz? Sorunumuzu çözmek için ihtiyacımız olan her şeye zaten sahibiz. Tüm gereken, servisi bindService kullanarak aktiviteye bağlamak, gerekli parametreleri iletmek ve Message sınıflarını kullanma şeklinde biraz sihir. Ve sihir, Mesaj örneği değişkenlerini ve özellikle de answerTo'yu kullanmaktır. Aktiviteden Messanger servis örneğine ve aktivitenin Messanger örneğine hizmette başvurabilmemiz için bu değişkene ihtiyacımız var. Aslında, o kadar basit değil. En azından benim yetenekli olmayan zihnime. Kısmen zaten var olan belgeleri iyileştiriyorum - Hizmetler Ayrıca, StackOverflow'ta iyi bir örnek var. Her durumda, makalenin en azından birileri için faydalı olacağını umuyorum ve boşuna çalışmadım.
Örnek
Örnek olarak, TextView'da, aktivitede sayacın değerini artıracak ve azaltacak ve sonucu döndürecek bir hizmeti uygulayacağız. Düzen kodunu atlayacağım, çünkü iki düğme ve bir metin alanı var - her şey basit.
uygulama
İşte tam aktivasyon kodu:
Genel sınıf MainActivity, Aktiviteyi genişletir ( public static final String TAG = "TestService"; TestServiceConnection testServConn; TextView testTxt; final haberci haberci= new Messenger(new IncomingHandler()); Messenger'dan ServiceMessenger'a; @Override public void onCreate(Bundle saveInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); testTxt = (TextView)findViewById(R.id.test_txt); bindService(new Intent(bu, TestService.class) ), (testServConn = new TestServiceConnection()), Context.BIND_AUTO_CREATE); ) @Override public void onDestroy()( super.onDestroy(); unbindService(testServConn); ) public void countIncrClick(Görüntüle düğmesi)( Mesaj msg = Message. get(null, TestService.COUNT_PLUS); msg.replyTo = messenger; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) public void countDecrClick(Görüntüle düğmesi)( Mesaj msg = Message.obtain(null, TestService.COUNT_MINUS); msg.replyTo = messenger; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) özel sınıf IncomingHandler, İşleyiciyi genişletir ( @Override public void handleMessage(Mesaj msj)( switch (msg.what) ( case TestServic e.GET_COUNT: Log.d(TAG, "(etkinlik)...sayımı al"); testTxt.setText(""+msg.arg1); kırmak; ) ) ) özel sınıf TestServiceConnection, ServiceConnection'ı uygular ( @Override public void onServiceConnected(ComponentName name, IBinder service) ( toServiceMessenger = new Messenger(service); //send başlangıç değeri sayaç Mesaj msj = Message.obtain(null, TestService.SET_COUNT); msg.replyTo = haberci; msg.arg1 = 0; // sayacımız deneyin ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) @Override public void onServiceDisconnected(ComponentName) ( ) )
Açıklamama izin ver. Bir aktivite oluştururken ServiceConnection arayüzünü uygulayarak hemen servise bağlanır ve içindeki “sayaç değerini ayarla” servisine bir mesaj göndeririz, sıfır geçer ve bir toServiceMessanger oluşturarak, IBinder arayüzünü yapıcıya iletiriz. Bu arada, bu örnek hizmette iade edilmelidir, aksi takdirde NPE olacaktır. Bu sınıf yardımıyla servise mesajlar gönderiyoruz. Ve burada sihirdir - answerTo değişkeninde, diğer Messenger örneğimizi kaydederiz - sunucudan bir yanıt alan ve etkinlikle iletişim bunun aracılığıyla gerçekleştirilecektir.
Hizmetten bir mesaj almak için İşleyicimizi kullanırız ve ihtiyacımız olan değişkenleri ararız ve bunlar üzerinde işlem yaparız. Düğme tıklamalarında (countIncrClick, countDecrClick yöntemleri) msg.what değişkeninde istenen eylemi belirterek hizmete istek göndeririz.
Paket com.example.servicetest; android.app.Service'i içe aktarın; android.content.* dosyasını içe aktarın; android.os.* içe aktar; android.os.Process'i içe aktar; android.util.Log'u içe aktar; public class TestService, Hizmeti genişletir ( public static final int COUNT_PLUS = 1; public static final int COUNT_MINUS = 2; public static final int SET_COUNT = 0; public static final int GET_COUNT = 3; int count = 0; IncomingHandler inHandler; Messenger messenger; Messenger toActivityMessenger; @Override public void onCreate()( super.onCreate(); HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); inHandler = new IncomingHandler(thread.getLooper()); messanger = new Messenger(inHandler); ) @Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); ) @Override public int onStartCommand(Niyet amacı, int flags, int startId) ( return START_STICKY; ) //mesaj işleyici aktivite özel sınıfı IncomingHandler, İşleyiciyi genişletir ( public IncomingHandler(Looper looper)( super(looper); ) @Override public void handleMessage(Mesaj msg)( //super.handleMessage(msg); toActivityMess enger = msg.replyTo; switch (msg.what) ( case SET_COUNT: sayı = msg.arg1; Log.d(MainActivity.TAG, "(service)...set count"); break; case COUNT_PLUS: sayı++; Log.d(MainActivity.TAG , "(hizmet)...sayım artı"); kesme; COUNT_MINUS vakası: Log.d(MainActivity.TAG, "(hizmet)...sayım eksi"); sayım--; kesme; ) //sayacın gönderilmesi aktivitedeki değer Message outMsg = Message.obtain(inHandler, GET_COUNT); outMsg.arg1 = sayı; outMsg.replyTo = haberci; dene ( if(toActivityMessenger != null) toActivityMessenger.send(outMsg); ) yakalama (RemoteException e) ( e.printStackTrace(); ) ) )
Hepsi aktivitedeki mantığa benzetilerek. Bir şeyi açıklamam gerekip gerekmediğini bile bilmiyorum. Tek nokta, bunun için sihirli answerTo değişkenini kullanarak ve yukarıda istenen Messenger'ı çekerek isteği hemen handleMessage'daki etkinliğe geri göndermemdir. Ve daha önce bahsettiğim ikinci nokta:
@Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); )
olmadan her şey düşecek. ServiceConnection'a aktarılacak olan bu arabirim örneğidir.
Çözüm
Neticede. Bir faaliyet ve bir hizmet arasındaki etkileşimin böylesine yapmacık bir örneği. Birisi için farklı görünse de, bana oldukça önemsiz bir etkileşim gibi görünüyor.
Sorular, açıklamalar vb. Herhangi bir konuda yanlışlıklar olabilir, bu yüzden yazmaktan ve düzeltmekten çekinmeyin.
Umarım yazı okuyucular için faydalı olmuştur.
Merhaba.
UART üzerinden alınan verilerin Aktiviteye aktarılması gerekmektedir. Bu, Activity içinde bir while (!isInterrupted()) döngüsünün düzenleneceği ve UART arabelleğinden verilerin okunacağı bir iş parçacığı oluşturarak yapılabilir. Daha sonra Activity - MainActivity.this.runOnUiThread(new Runnable()) nin UI thread'ını çağırarak bu Activity ile gerekli işlemleri gerçekleştiriyoruz.Fakat ana Activity'den diğer Activityleri çağırırsak organize thread geçişe izin vermiyor yeni oluşturulan Aktivitelere veri Akıştan gelen verilerin herhangi bir Aktiviteye aktarılması için akımın Aktivitede değil, Hizmette oluşturulması gerektiğini doğru anladıysam.
Soru: Veriler UART üzerinden geldi, (Servce'de oluşturulan) thread'de şu anda aktif olan Activity'e veri aktarmak gerekiyor, bu nasıl yapılabilir ve hiç yapılıyor mu?
1 cevap
Her Aktivitede bir İşleyici oluşturun. Bu Aktivitenin onResume() yönteminde bindService() yapılır. Burada parametrelerden biri ServiceConnection arabirimidir. En azından aynı Activity ile uygulayın. İçinde onServiceConnected() yöntemini uygulayın. Bu geri aramada Hizmetin kendisi parametrelerden biri olarak gelir. O halde bu Hizmeti kendi setHandler() yönteminiz olarak adlandırın. Mevcut Faaliyette bulunan İşleyiciyi oraya iletin. Ancak gelen verileri UART aracılığıyla bu İşleyicideki Hizmete atın. Bu arada, Handler geleneksel olarak ana iş parçacığında çalışır, bu nedenle runOnUiThread'in çalıştırılmasına gerek yoktur.