MójDroid.pl

#8 Twórz aplikacje na Androida z Mojdroid.pl - Bundle, czyli przekazywanie danych w aplikacji

2012-09-19
|
Damian P.

W naszej aplikacji może zdarzyć się sytuacja, w której będziemy chcieli przekazać kilka danych do innej części programu, na przykład do nowego Activity. Android od początku oferuje taką funkcjonalność pod nazwą Bundle i dziś tym się zajmiemy.
Informacja: Nie radzisz sobie z kodem? Coś Ci nie wychodzi lub nie działa? Zgubiłeś się? W tym miejscu zobaczysz pełen kod aplikacji, a tutaj go pobierzesz na dysk.

1. Bundle

Bundle to jeden z prostszych (w swojej budowie) elementów systemu Android. Pozwala on na wykonanie tylko jednej czynności i sprawdza się przy tym... tak sobie (ani dobrze, ani źle). Dzięki niemu możemy przesyłać liczby, znaki a nawet całe zdania i obiekty między poszczególnymi Activity. Ale na tym kończą się wszystkie jego zalety. Brakuje bowiem tutaj wiele rzeczy, takich jak sprawdzanie poprawności załączonych danych czy dodawanie złożonych typów (da się, ale trzeba kombinować), co może nam sprawić problemy, jeżeli korzystamy z większych elementów. Wracając jednak do obsługi tego elementu. Traktujcie Bundle jako pusty koszyk, do którego możemy włożyć dane, następnie je spakować i wysłać do innej części aplikacji. Ta może je odebrać, odtworzyć i odczytać w dokładnie takim samym stanie w jakim je wysłaliśmy. Oczywiście będą nam tutaj potrzebne dwa Activity, bo inaczej takiego kosza nie możemy przekazać. Aby więc przetestować działanie tego elementu stwórzmy dwa szablony (np. view_bundle_resultview_bundle), dwie klasy (np. View_Bundle_ResultView_Bundle) korzystające z Activity i dołączmy to wszystko do naszej prostej listy (to już robiliśmy wcześniej, pamiętacie?). Oto źródła poszczególnych szablonów: view_bundle.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/eT_bundle_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:lines="1"        
        android:maxLines="1"
        android:hint="Wpisz tekst dla drugiego Activity"
        android:layout_centerVertical="true"
        android:ems="10" >

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/bt_view_bundle_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/eT_bundle_text"
        android:layout_below="@+id/eT_bundle_text"
        android:layout_marginTop="15dp"
        android:text="Start" />

</RelativeLayout>
view_bundle_result.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tV_view_bundle_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Wynik" />

</RelativeLayout>
Layouty są bardzo proste - w pierwszym Activity będziemy wpisywać tekst (do pola EditText), który zostanie przekazany do kolejnego Activity (po kliknięciu przycisku) i tam odczytany oraz wyświetlony (w TextView). Jak to zrobić krok po kroku? Zaczynamy od opisania kolejnych Views w naszych layoutach, ot zwykła deklaracja EditTextu, ButtonaTextView oraz OnClickListenera: View_Bundle:
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class View_Bundle extends Activity implements OnClickListener {
    
    private EditText naszTekst;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.view_bundle);
	
	naszTekst = (EditText) findViewById(R.id.eT_bundle_text);
	Button przycisk = (Button) findViewById(R.id.bt_view_bundle_start);
	
	przycisk.setOnClickListener(this);
	
    }

    public void onClick(View v) {	
    }

}
View_Bundle_Result:
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class View_Bundle_Result extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.view_bundle_result);
	
	TextView rezultat = (TextView) findViewById(R.id.tV_view_bundle_result);	
    }

}
Idziemy dalej - po kliknięciu w przycisk tekst z pola EditText ma zostać pobrany, zapakowany w nasze omawiane Bundle oraz przekazany do kolejnego Activity. Robimy więc to w naszym View_Bundle:
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class View_Bundle extends Activity implements OnClickListener {
    
    private EditText naszTekst;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.view_bundle);
	
	naszTekst = (EditText) findViewById(R.id.eT_bundle_text);
	Button przycisk = (Button) findViewById(R.id.bt_view_bundle_start);
	
	przycisk.setOnClickListener(this);
	
    }

    public void onClick(View v) {
	// Pobieramy tekst z pola
	String wpisanyTekst = naszTekst.getText().toString();
	// Pakujemy go w Bundle
	Bundle koszyk = new Bundle();
	koszyk.putString("dane", wpisanyTekst);
	// Definiujemy cel
	Intent cel = new Intent(this, View_Bundle_Result.class);
	cel.putExtras(koszyk);
	// Wysyłamy
	startActivity(cel);
    }

}
Ciekawostka - nie musimy definiować przy wysłaniu nowego Bundle, całość możemy zapisać również w taki sposób:
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class View_Bundle extends Activity implements OnClickListener {
    
    private EditText naszTekst;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.view_bundle);
	
	naszTekst = (EditText) findViewById(R.id.eT_bundle_text);
	Button przycisk = (Button) findViewById(R.id.bt_view_bundle_start);
	
	przycisk.setOnClickListener(this);
	
    }

    public void onClick(View v) {
	// Pobieramy tekst z pola
	String wpisanyTekst = naszTekst.getText().toString();
	// Definiujemy cel
	Intent cel = new Intent(this, View_Bundle_Result.class);
	// Towrzymy Bundle od razu dodając informacje do Intentu
	cel.putExtra("dane", wpisanyTekst);
	// Wysyłamy
	startActivity(cel);
    }

}
Co jest tutaj ważne: aby przekazać jakieś dane należy wcześniej oznaczyć je jakimś kluczem. Jest to wymóg, ponieważ przy odczytywaniu Android musi wiedzieć, którą część ma przypisać do której zmiennej (lub od razu wypisać). W naszym przypadku ID nazwane zostało "dane". Pozostało nam jedynie opisać odbiór tych danych, tutaj Bundle jest już wymagane:
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class View_Bundle_Result extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.view_bundle_result);
	
	TextView rezultat = (TextView) findViewById(R.id.tV_view_bundle_result);	
	Bundle przekazanedane = getIntent().getExtras();
	String przekazanytekst = przekazanedane.getString("dane");
	
	rezultat.setText(przekazanytekst);
    }

}
Dzieje się to przez pobranie obecnego Intentu, odczyt wartości z niego i wybranie klucza. Proste, prawda? Efekt jest taki jak myślimy, sprawdźcie sami w swoich programach (po dodaniu elementu do listy i Manifestu, ale o tym już nie będę przypominał).

PS. Bundle zapisują również stan aplikacji przy jej wyjściu czy rozpoczęciu, spójrzcie na argumenty przyjmowane przez niektóre metody jak OnCreate.