Sierpień 8, 2011
Intent Podstawowe komponenty Tutoriale
Filtry Intencji w Androidzie są bardzo ważnym elementem, który pozwala decydować systemowi jaki komponent (Aktywność, Usługa, Odbiorca treści) ma zostać wywołany dla Intencji posiadającej konkretną akcję lub dane. Daje nam to ogromne możliwości, bowiem w ten sposób możemy definiować zachowanie całego systemu operacyjnego.
Przykład
Mamy aplikację, w której klikamy na link jakiejś strony internetowej. I teraz, zamiast otwierać konkretną przeglądarkę z adresem przekazanym w argumencie, wysyłana jest intencja posiadająca dwa składniki:
Dzięki Filtrom Intencji system teraz dobierze najbardziej pasującą aplikację, która obsłuży powyższą intencję. Daje nam to możliwość nie tylko wybrania ustawionej przez nas przeglądarki, ale np. otwarcia czytnika RSS dla adresu URL prowadzącego do tego typu danych.
Inny przykład
Potrzebujemy pobrać konkretną pozycję z listy kontaktów. Nie obchodzi nas jaka aplikacja to zrobi, ważne byśmy otrzymali oczekiwany wynik, w związku z czym wysyłamy intencję z:
Dzięki temu system otworzy domyślną aplikację, w której wybierzemy konkretny kontakt. A my (programiści) nie musimy się martwić czy aplikacja, którą w innym wypadku musielibyśmy wskazać, jest zainstalowana na telefonie czy nie.
Aby zarejestrować nasz komponent do obsługi konkretnej intencji w pliku AndroidManifest.xml, wewnątrz elementu <activity> (lub service, receiver) musimy dodać element <intent-filter> . Oto przykładowy szkielet takiego kodu:
Co ważne – każdy z powyższych elementów (włącznie z <intent-filter>) może być wykorzystany wielokrotnie (dzięki temu możemy dokładnie sprecyzować jakie intencje będziemy obsługiwać).
Konfiguracja obsługiwanych intencji sprowadza się do edycji atrybutów elementów <action>, <category>, <data>.
Element <action> posiada jeden atrybut – android:name, w którym podajemy unikalny ciąg znaków identyfikujący akcję. Możemy tutaj wykorzystać gotowe wzory zapisane pod android.intent.action.* (wszystkie dostępne akcje można znaleźć w dokumentacji) lub tworzyć swoje (np za pomocą publicznych pól statycznych). Przy tworzeniu własnych nazw zalecane jest używanie ciągów znaków wzorowanych na nazwach paczek w Javie (np. com.example.appname.action.DOIT).
Przy użyciu wielu elementów <action /> w danym filtrze, wystarczy by pasowała tylko jedna aby system wziął nasz komponent pod uwagę.
<category> również posiada tylko jeden atrybut: android:name. Ciąg znaków, który podajemy tutaj możemy pobrać z android.intent.category.* (ten sam link do dokumentacji) . Niektóre ciekawsze kategorie to:
System przy dopasowywaniu bierze pod uwagę wszystkie kategorie na raz. Dlatego by dopasować Intencję, musi ona pasować do wszystkich kategorii w obrębie filtru.
<data> jest elementem, która wskazuje jaki typ danych ma obsługiwać nasz komponent. W przeciwieństwie do powyższych elementów posiada kilka atrybutów pozwalających dokładnie określić typ danych:
Jak widać za pomocą powyższych atrybutów jesteśmy w stanie obsłużyć każdy adres URI.
Stworzymy teraz aplikację, w której zademonstrowane zostaną 3 przykłady Filtrów Intencji. Nie będziemy jednak zagłębiać się w nieco przydługawy kod źródłowy poszczególnych komponentów, a jedynie działanie i opis konkretnych filtrów.
Z pierwszym przykładem wykorzystania filtrów intencji mamy do czynienia tak naprawdę przy każdym projekcie aplikacji Androidowej. W dodatku bez pisania dodatkowego kodu.
Filtrem tym jest oczywiście kod wskazujący na to, że dana Aktywność jest główną w konkretnej aplikacji:
Powyższy kod generowany jest oczywiście w pliku AndroidManifest.xml. W tym wypadku wskazuje on na to, że Aktywność MainActivity ma odpowiadać na akcję uruchomienia aplikacji (*.action.MAIN) oraz, że wywoływana jest wtedy, gdy system wybiera pierwszą ze szczytu Aktywności w danej aplikacji (*.category.LAUNCHER).
Stworzymy teraz Aktywność, która będzie uruchamiana tylko w momencie gdy będziemy chcieli podejrzeć zawartość adresu URL, którego hostem będzie www.google.pl.
Oto kod źródłowy wszystkich wykorzystanych plików:
main.xml
link_server.xml
MainActivity.java
LinkServer.java
W kodzie Aktywności LinkServer dodana została funkcjonalność wykorzystująca metodę startMatchingActivity(Intent intent). Pozwala ona na przesłanie Intencji do kolejnego komponentu, który według systemu do niej pasuje.
Filtr Intencji dla tego przykładu wygląda tak:
Działanie przykładu
Wpisujemy adres URL z http:// na początku. Jeżeli jest to adres, który nie zawiera w hoście www.google.pl wtedy system odsyła naszą Intencję do domyślnej przeglądarki systemu.
Jeżeli jednak wpiszemy adres zawierający www.google.pl (np. http://www.google.pl/abc) system odeśle naszą Intencję do aktywności LinkServer. Kiedy natomiast w tej Aktywności klikniemy na przycisk wywołujący startNextMatchingActivity(Intent) – system wybierze następny komponent systemu pasujący do naszej Intencji, dzięki czemu wywołana zostanie domyślna przeglądarka.
Zrzuty ekranu
Dla adresu www.google.pl
Dla innego adresu
W ostatnim przykładzie zasada działania jest taka, że filtr reaguje tylko na Intencję z akcją PICK, i adresem content://browser. Uruchomiona Aktywność powinna zwrócić wybraną przez nas zakładkę.
Oto kod źródłowy wszystkich wykorzystanych plików:
bookmarks.xml
MainActivity.java
BookmarkPicker.java
Filtr intencji dla powyższego przykładu:
Zrzuty ekranu
Cały projekt dostępny jest na naszym githubie – HelloIntentFilters.
AndroidManifest.xml
Zaloguj się lub skorzystaj z profilu:
Możesz również zostawić komentarz bez rejestracji, korzystając z poniższego formularza:
Musisz być zalogowany aby móc pisać komentarze.
Intent Filters, przypisywanie komponentów do konkretnych akcji lub danych
Powiązane linki
Tworzenie Filtrów Intencji
Przykładowa aplikacja
Kompletny kod źródłowy
Komentarze (0)
Prześlij komentarz
<action />
<category />
<data />
Przykład 1
Przykład 2
Przykład 3
- dane (adres strony)
- akcję do przeprowadzanie na danych (wyświetl zawartość znajdującą się pod powyższym adresem).
- akcją (pobierz kontakt)
- danymi (adres Uri do listy kontaktów – w Androidzie content://contact/)
- BROWSABLE – do obsługiwania danych „przeglądarkowych”. Do dopasowania akcji kliknięcia na link, adres e-mail itp. Dodatkowo – dane wychodzące z przeglądarki w telefonie do obsłużenia zawsze wymagają filtru z kategorią BROWSABLE.
- DEFAULT – jeżeli komponent jest kandydatem do bycia domyślną aplikacją dla konkretnych danych. Jeżeli w systemie jest więcej domyślnych komponentów dla takich samych danych, po wysłaniu Intencji system prosi nas o wybranie aplikacji, która ją obsłuży.
- LAUNCHER – za pomocą tej kategorii wskazujemy, która aktywność ma być tą główną w danej aplikacji.
- HOME – tutaj Aktywność jest kandydatem do bycia główną aktywnością telefonu (czyli tym co jest uruchamiane po kliknięciu przycisku HOME).
- ALTERNATIVE – wskazuje na to, że aktywność/usługa powinna być alternatywą do konkretnych danych. Nie jest tym samym co DEFALUT, ponieważ ALTERNATIVE dostarcza nam możliwości wskazania nowej akcji dla konkretnych danych (np. dotychczas można było jedynie wyświetlić listę kontaktów, a my dostarczamy akcji do ich usuwania).
- android:scheme – schemat (protokół) adresu Uri (np. http, ftp, content)
- android:host – czyli… host (np www.google.com)
- android:port – port
- android:path – ścieżka do pliku (np. /contacts/people)
- android:mimetype – typ danych z jakimi ma być powiązany nasz element
<activity android:label="@string/app_name" android:name=".MyActivity">
<intent-filter>
<action />
<category />
<data />
</intent-filter>
</activity><!-- MainActivity --> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <EditText android:id="@+id/etLink" android:layout_width="fill_parent" android:layout_height="wrap_content" android:inputType="textUri" android:hint="Type site address with http://" /> <Button android:id="@+id/btnServeSpecifyLink" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Serve address" /> <Button android:id="@+id/btnPickBookmark" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Pick from bookmarks" /> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/tvLinkServer" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btnStartNextMatching" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Start next matching Activity" /> </LinearLayout>
package pl.froger.hello.intentfilters;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Browser.BookmarkColumns;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity {
public static final int BOOKMARK_PICK = 1234;
private EditText etLink;
private Button btnServeSpecifyLink;
private Button btnPickBookmark;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etLink = (EditText) findViewById(R.id.etLink);
btnServeSpecifyLink = (Button) findViewById(R.id.btnServeSpecifyLink);
btnPickBookmark = (Button) findViewById(R.id.btnPickBookmark);
initButtonsOnClick();
}
private void initButtonsOnClick() {
OnClickListener listener = new OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnServeSpecifyLink:
serveLinkFromEditText();
break;
case R.id.btnPickBookmark:
pickBookmark();
break;
default:
break;
}
}
};
btnServeSpecifyLink.setOnClickListener(listener);
btnPickBookmark.setOnClickListener(listener);
}
private void serveLinkFromEditText() {
Uri uri = Uri.parse(etLink.getText().toString());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
private void pickBookmark() {
Intent intent = new Intent(Intent.ACTION_PICK, Uri.parse("content://browser"));
startActivityForResult(intent, BOOKMARK_PICK);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case BOOKMARK_PICK:
if (resultCode == Activity.RESULT_OK) {
Uri bookmarkUri = data.getData();
String[] bookmarks = new String[] { BookmarkColumns.URL };
Cursor cursor = managedQuery(
bookmarkUri,
bookmarks,
null,
null,
null);
cursor.moveToFirst();
String url = cursor.getString(cursor.getColumnIndexOrThrow(BookmarkColumns.URL));
etLink.setText(url);
}
break;
default:
break;
}
}
}package pl.froger.hello.intentfilters;
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.TextView;
public class LinkServer extends Activity {
private TextView tvLinkServer;
private Button btnStartNextMatching;
private Intent incomingIntent;
String intentData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getDataFromIntent();
setContentView(R.layout.link_server);
tvLinkServer = (TextView) findViewById(R.id.tvLinkServer);
btnStartNextMatching = (Button) findViewById(R.id.btnStartNextMatching);
btnStartNextMatching.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
startNextMatchingActivity(incomingIntent);
finish();
}
});
tvLinkServer.setText("Obsługujesz adres: " + intentData);
}
private void getDataFromIntent() {
intentData = "";
incomingIntent = getIntent();
if (incomingIntent != null) {
intentData = incomingIntent.getDataString();
}
}
}<!-- LinkServer Activity --> <activity android:name=".LinkServer"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="andorid.intent.category.BROWSABLE" /> <data android:scheme="http" android:host="www.google.pl" /> </intent-filter> </activity>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ListView android:id="@+id/lvBookmarksList" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
package pl.froger.hello.intentfilters;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Browser.BookmarkColumns;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity {
public static final int BOOKMARK_PICK = 1234;
private EditText etLink;
private Button btnServeSpecifyLink;
private Button btnPickBookmark;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etLink = (EditText) findViewById(R.id.etLink);
btnServeSpecifyLink = (Button) findViewById(R.id.btnServeSpecifyLink);
btnPickBookmark = (Button) findViewById(R.id.btnPickBookmark);
initButtonsOnClick();
}
private void initButtonsOnClick() {
OnClickListener listener = new OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnServeSpecifyLink:
serveLinkFromEditText();
break;
case R.id.btnPickBookmark:
pickBookmark();
break;
default:
break;
}
}
};
btnServeSpecifyLink.setOnClickListener(listener);
btnPickBookmark.setOnClickListener(listener);
}
private void serveLinkFromEditText() {
Uri uri = Uri.parse(etLink.getText().toString());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
private void pickBookmark() {
Intent intent = new Intent(Intent.ACTION_PICK, Uri.parse("content://browser"));
startActivityForResult(intent, BOOKMARK_PICK);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case BOOKMARK_PICK:
if (resultCode == Activity.RESULT_OK) {
Uri bookmarkUri = data.getData();
String[] bookmarks = new String[] { BookmarkColumns.URL };
Cursor cursor = managedQuery(
bookmarkUri,
bookmarks,
null,
null,
null);
cursor.moveToFirst();
String url = cursor.getString(cursor.getColumnIndexOrThrow(BookmarkColumns.URL));
etLink.setText(url);
}
break;
default:
break;
}
}
}package pl.froger.hello.intentfilters;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Browser.BookmarkColumns;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity {
public static final int BOOKMARK_PICK = 1234;
private EditText etLink;
private Button btnServeSpecifyLink;
private Button btnPickBookmark;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etLink = (EditText) findViewById(R.id.etLink);
btnServeSpecifyLink = (Button) findViewById(R.id.btnServeSpecifyLink);
btnPickBookmark = (Button) findViewById(R.id.btnPickBookmark);
initButtonsOnClick();
}
private void initButtonsOnClick() {
OnClickListener listener = new OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnServeSpecifyLink:
serveLinkFromEditText();
break;
case R.id.btnPickBookmark:
pickBookmark();
break;
default:
break;
}
}
};
btnServeSpecifyLink.setOnClickListener(listener);
btnPickBookmark.setOnClickListener(listener);
}
private void serveLinkFromEditText() {
Uri uri = Uri.parse(etLink.getText().toString());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
private void pickBookmark() {
Intent intent = new Intent(Intent.ACTION_PICK, Uri.parse("content://browser"));
startActivityForResult(intent, BOOKMARK_PICK);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case BOOKMARK_PICK:
if (resultCode == Activity.RESULT_OK) {
Uri bookmarkUri = data.getData();
String[] bookmarks = new String[] { BookmarkColumns.URL };
Cursor cursor = managedQuery(
bookmarkUri,
bookmarks,
null,
null,
null);
cursor.moveToFirst();
String url = cursor.getString(cursor.getColumnIndexOrThrow(BookmarkColumns.URL));
etLink.setText(url);
}
break;
default:
break;
}
}
}<!-- BookmarkPicker Activity --> <activity android:name=".BookmarkPicker"> <intent-filter> <action android:name="android.intent.action.PICK" /> <category android:name="android.intent.category.DEFAULT" /> <data android:path="browser" android:scheme="content" /> </intent-filter> </activity>
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="pl.froger.hello.intentfilters" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <!-- MainActivity --> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- LinkServer Activity --> <activity android:name=".LinkServer"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="andorid.intent.category.BROWSABLE" /> <data android:scheme="http" android:host="www.google.pl" /> </intent-filter> </activity> <!-- BookmarkPicker Activity --> <activity android:name=".BookmarkPicker"> <intent-filter> <action android:name="android.intent.action.PICK" /> <category android:name="android.intent.category.DEFAULT" /> <data android:path="browser" android:scheme="content" /> </intent-filter> </activity> </application> <uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" /> <uses-permission android:name="com.android.broswer.permission.WRITE_HISTORY_BOOKMARKS" /> </manifest>