程序猿的開心一刻###
以下誰是二進(jìn)制思想的最早提出者举哟?
a思劳,伏羲;b妨猩,姬昌潜叛;c,萊布尼茨壶硅;d威兜,柏拉圖。
請在評論區(qū)輸入答案庐椒,接下來進(jìn)入正題
一椒舵、簡介
本文將帶你學(xué)習(xí)Android中最基本的事件處理機(jī)制,了解什么是事件扼睬,怎樣來監(jiān)聽事件逮栅。隨后你將學(xué)習(xí)到什么是意圖悴势,以及通過一個實例來學(xué)習(xí)怎樣用意圖在Activity間傳遞信息窗宇。
知識點
- Android事件監(jiān)聽器
- Android事件處理者
- 事件監(jiān)聽器的注冊
- 在Activity之間傳遞數(shù)據(jù)
二、事件處理
對于應(yīng)用的交互而言特纤,事件是一個收集用戶交互信息的有效途徑军俊。這些事件包括按壓按鈕或者觸碰屏幕。Android的框架維護(hù)了一個基于先進(jìn)先出的事件隊列捧存,你可以在程序中捕獲這些事件粪躬,并針對每個需求,采取合適的行動昔穴。
下面有三個關(guān)于Android事件管理的概念:
-
事件監(jiān)聽器
:事件監(jiān)聽器是View類中的一個接口镰官,它包含了一個回調(diào)方法。當(dāng)用戶與UI組件進(jìn)行交互時吗货,相應(yīng)已注冊的監(jiān)聽器會被觸發(fā)泳唠,Android框架會調(diào)用這些方法。 -
事件監(jiān)聽器注冊
:事件注冊就是一個事件處理者通過事件監(jiān)聽器來注冊的過程宙搬。因此笨腥,事件監(jiān)聽器觸發(fā)事件時調(diào)用響應(yīng)的處理者(Handler
)。 -
事件處理者
:當(dāng)某個事件發(fā)生時勇垛,如果我們?yōu)樵撌录粤艘粋€事件監(jiān)聽器脖母,那么這個監(jiān)聽器就會調(diào)用事件處理者。后者為實際處理該事件的方法闲孤。
1. 事件監(jiān)聽器和事件處理者
以下為一些常見的事件處理者谆级,后面補(bǔ)充了它對應(yīng)的事件監(jiān)聽器和說明。
-
onClick()
:對應(yīng)的事件監(jiān)聽器是OnClickListener()
。當(dāng)用戶點擊哨苛、觸摸或者聚焦(給它焦點)與任何一個部件時(這些部件有按鈕鸽凶、文本和圖片等),該方法就會被調(diào)用建峭。你可以使用名為onCLick()
的事件處理者來處理這些事件玻侥。 -
onLongClick()
:對應(yīng)的事件監(jiān)聽器是OnLongClickListener()
。當(dāng)用戶長時間(一秒或者很多秒)點擊亿蒸、觸摸或聚焦于任何一個部件時凑兰,該方法會被調(diào)用。你可以使用名為onLongClick()
的事件處理者來處理這些事件边锁。 -
onFocusChange()
:對應(yīng)的事件監(jiān)聽器是OnFocusChangeListener()
姑食。有時當(dāng)用戶從某個視圖部件上移開關(guān)注時,這個部件就會失去焦點茅坛,此時該方法會被調(diào)用音半。你可以使用onFocusChange()
這個事件處理者來處理這些事件。 -
onKey()
:對應(yīng)的事件監(jiān)聽器是OnFocusChangeListener
贡蓖。當(dāng)用戶關(guān)注某個部件并且按壓(或釋放)了設(shè)備上的實體按鍵時曹鸠,該方法會被調(diào)用。你可以使用onKey()
事件處理者來處理這個事件斥铺。 -
onTouch()
:對應(yīng)的事件監(jiān)聽器是OnTouchListener()
彻桃。當(dāng)用戶按鍵、釋放按鍵或者在屏幕上任意移動手勢時晾蜘,會調(diào)用該方法邻眷。你可以使用onTouch()
事件處理者來處理這個事件。 -
onMenuItemClick
:對應(yīng)的事件監(jiān)聽器是onMenuItemCLickListener()
剔交。當(dāng)用戶選擇了一個菜單項時會調(diào)用該方法肆饶。你可以使用onMenuItemCLick()
事件處理者來處理這個事件。 -
onCreateContextMenu()
:對應(yīng)的事件監(jiān)聽器是OnCreateContextMenuItemListener()
岖常。當(dāng)上下文菜單正在建立時(持續(xù)的長按動作會觸發(fā)該事件)會調(diào)用該方法驯镊。
在View
類中,還有更多諸如OnHoverListener
腥椒、OnDragListener
之類的事件監(jiān)聽器可供使用阿宅。所以為了開發(fā)具有更加豐富功能的應(yīng)用,你需要去查閱和參考Android開發(fā)的官方文檔笼蛛。
2. 事件監(jiān)聽器注冊
前文提到過洒放,事件的注冊就是一個事件處理者注冊事件監(jiān)聽器的過程。盡管對于注冊監(jiān)聽器來說滨砍,有許多靈活的方法往湿,但在本文中只列出了其中最常用的3種方法妖异。在你的實際項目中,可以任意使用其中之一领追。
這些方法有:
- 使用匿名內(nèi)部類
- 在
Activity
類中實現(xiàn)Listener
的接口他膳。 - 在
activity_main.xml
(對應(yīng)的)布局文件中直接通過android:onClick
屬性指定事件處理者。
下面的內(nèi)容將為你逐一講解绒窑。
(1)使用匿名內(nèi)部類注冊事件監(jiān)聽器
以按鈕的點擊事件為例棕孙,首先要在xml布局文件中定義按鈕的id,然后在Activity類中實例化控件些膨,使用自定義的內(nèi)部類蟀俊,如下所示:
public class MainActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 此處寫其他代碼
// button是查找后賦值的按鈕對象
button.setOnClickListener(new MyOnClickListener();
}
// 自定義的匿名內(nèi)部類
Private final class MyOnClickListener implements OnClickListener{
Public void onClick(View view){
// 此處寫點擊功能的邏輯
}
}
}
(2)實現(xiàn)事件監(jiān)聽器接口
這種方法是讓當(dāng)前Activity實現(xiàn)OnClickListener
,并實現(xiàn)這個接口中的方法:onClick(View view)
:
public class MainActivity extends Activity implements OnClickListener{
// 當(dāng)然這兒應(yīng)該還有該類中的其他內(nèi)容
@Override
Public void onClick(View view){
// 此處填實現(xiàn)的細(xì)節(jié)
}
}
(3)在布局文件中指定事件處理者
以按鈕的點擊事件為例订雾,這種方法是在xml布局文件中肢预,在控件屬性里添加android:onClick
屬性,然后指明調(diào)用方法的名字洼哎,例如android:onClick="onAddClick"
烫映。
在對應(yīng)的Activity類中,也需要寫一個對應(yīng)的方法噩峦,方法名要與之對應(yīng)锭沟,如:
public void onAddClick(View view){
//這里填具體的邏輯
}
3. 觸碰模式
用戶可以通過實體按鍵、屏幕上的按鈕壕探,以及觸摸屏幕來和設(shè)備交互冈钦。觸摸屏幕能讓設(shè)備進(jìn)入觸碰模式郊丛,用戶可以通過屏幕上的虛擬按鈕李请、圖片來完成交互。你可以通過調(diào)用View
類的isInTouchMode()
方法來檢查設(shè)備是否處于觸碰模式厉熟。
這個流程圖如下所示:
4. 焦點
一個視圖或部件在處于獲得焦點狀態(tài)時导盅,通常會高亮顯示或者顯示一個閃爍的光標(biāo)。這個狀態(tài)意味著它已經(jīng)準(zhǔn)備好去接收用戶的輸入揍瑟。
所以對于狀態(tài)白翻,主要的檢查方法如下:
-
isFocusable()
:返回true
或者false
。 -
isFocusableInTouchMode()
:檢查某個組件(或視圖)在觸碰模式下是否可以獲得焦點(當(dāng)使用實體按鍵但設(shè)備不處于觸碰模式時绢片,一個視圖仍然是可以獲得焦點的)滤馍。
在XML文件中可以對這些組件設(shè)置如下的屬性,以確定是哪個組件可以獲得焦點:
android:focusUp="@+id/組件的ID"
5. 觸碰事件onTouchEvent()
對于觸碰事件的處理方式如下底循,請嘗試去閱讀代碼塊:
public boolean onTouchEvent(motionEvent event){
// 通常需要重寫這個onTouchEvent()方法來對指定的操作實現(xiàn)響應(yīng)
switch(event.getAction()){
// 對event對象傳入的多個動作巢株,使用getAction()方法獲得該動作的ID值(均是預(yù)定義好的常量),
// 然后進(jìn)行比較熙涤,在一些判斷中來執(zhí)行后續(xù)的操作阁苞。
// 本例使用了switch困檩,你可以根據(jù)實際情況選擇if、while并進(jìn)行條件判斷那槽。
case TOUCH_DOWN:
//TOUCH_DOWN指代了用戶的手指已經(jīng)按到屏幕上但還未抬起的這一動作悼沿。
Toast.makeText(this,"The Button has been clicked down.",Toast.LENTH_LONG).show();
//此處用了一個Toast提示框來顯示用戶執(zhí)行了何種操作,下同骚灸。
break();
case TOUCH_UP:
//TOUCH_UP指代了用戶的手指從屏幕上抬起的這一動作糟趾。
Toast.makeText(this,"The Button has been clicked up.",Toast.LENTH_LONG).show();
break;
case TOUCH_MOVE:
//TOUCH_MOVE指代了用戶的手指在屏幕上移動但還未抬起的這一動作。
Toast.makeText(this,"The Button has been clicked move."Toast.LENTH_LONG).show();
break;
}
return super.onTouchEvent(event) ;
}
三甚牲、內(nèi)部通信
當(dāng)某個Activity需要啟動另外一個Activity時拉讯,對于用于來說表現(xiàn)的是操作界面的切換,而對于應(yīng)用本身來說鳖藕,則需要通過意圖
(Intent
)來告訴系統(tǒng)自己想要啟動哪個Activity魔慷。
事實上,無論是啟動一個Activity還是一個Service著恩,或者一個BroadcastReceiver院尔,在Android中均需要用Intent來封裝這種調(diào)用的“意圖”。
而在這些組件切換的過程中喉誊,就可以使用Intent來傳遞信息邀摆。你可以將數(shù)據(jù)封裝成Bundle對象,然后用Intent把這個對象攜帶至其他地方伍茄,從而實現(xiàn)了系統(tǒng)內(nèi)部的一次數(shù)據(jù)交換栋盹。
以后經(jīng)常會用到startActivity(Intent intent)
、startService(Intent service)
和sendBroadcast(Intent intent)
等方法敷矫,這些方法就是使用了Intent來啟動不同的組件例获。
現(xiàn)在我們主要討論Intent操作Activity的相關(guān)知識。
意圖是對于將要執(zhí)行的操作的抽象描述曹仗。在startActivity()
方法中榨汤,可以用意圖來啟動一個Activity。意圖的本身是一個Intent對象怎茫,它是一個可傳遞的數(shù)據(jù)結(jié)構(gòu)收壕,存放了將要執(zhí)行的操作的抽象描述。
例如轨蛤,你在某個Activity中需要打開郵件客戶端并使用設(shè)備來發(fā)送給一封電子郵件蜜宪,那么在你的Activity中就要用合適的選擇器,發(fā)送一個ACTION_SEND
意圖給意圖解析器祥山。指定的選擇器將給予用戶合適的接口圃验,讓他選擇怎樣發(fā)送電子郵件數(shù)據(jù)(這一步有點類似于Windows系統(tǒng)中的打開方式,但它們并不是同一類東西)枪蘑。
實現(xiàn)這個功能的主要代碼如下:
Intent intent_sendEmail = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));
email.putExtra(Intent.EXTRA_EMAIL, 收件人的地址);
email.putExtra(Intent.EXTRA_SUBJECT, 郵件“主題”);
email.putExtra(Intent.EXTRA_TEXT, 郵件“正文”);
startActivity(Intent.createChooser(intent_sendEmail, "請選擇一個郵件客戶端以發(fā)送電子郵件…"));
再比如损谦,假設(shè)你需要一個Activity來打開設(shè)備上的瀏覽器應(yīng)用并訪問指定的URL岖免,你就需要在Activity中發(fā)送一個ACTION_WEB_SEARCH
意圖給Android意圖解析器,從而在瀏覽器中打開這個URL照捡。
意圖解析器解析了眾多的Activity颅湘,并且選中最適合當(dāng)前設(shè)定的那一個(例如本例中的瀏覽器Activity),然后意圖解析器會將網(wǎng)頁的URL傳遞給瀏覽器并訪問它栗精。
實現(xiàn)該功能的代碼樣例如下:
String keyword = "阿里巴巴";
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, keyword);
startActivity(intent);
上面這段代碼會在Android的搜索引擎中搜索shiyanlou
相關(guān)信息闯参。
對于在Activity中傳遞信息而言,則需要使用到Bundle悲立。我們稍后在實例中為你講解其詳細(xì)的使用方法鹿寨。
四、實例
下面通過一個實例薪夕,通過實現(xiàn)匿名類和XML中聲明兩種方法來注冊事件監(jiān)聽器脚草。
主要有以下步驟:
- 請使用Android Studio來創(chuàng)建一個項目。
- 除了
MainActivity
原献,請通過菜單再創(chuàng)建一個名為SecondActivity
的Activity馏慨。 - 在
res/layout/activity_main.xml
文件中的布局里,為MainActivity
添加兩個主要的控件:一個文本框EditText
姑隅、一個按鈕Button
写隶,并設(shè)置它們的屬性(詳細(xì)代碼請參考后文)。 - 在
res/layout/activity_second.xml
文件中的布局里讲仰,為SecondActivity
添加兩個主要的控件:一個按鈕Button
和一個文本標(biāo)簽TextView
慕趴,并設(shè)置它們的屬性(詳細(xì)代碼請參考后文)。特別注意在按鈕的屬性中添加一個android:onClick="show"
來注冊監(jiān)聽器鄙陡。 - 修改
MainActivity.java
文件冕房,在MainActivity
類中聲明剛剛添加的控件,在onCreate()
方法內(nèi)對它們進(jìn)行實例化(使用findViewById()
方法)柔吼,對按鈕以匿名內(nèi)部類的方式添加點擊事件監(jiān)聽器毒费,在onClick
方法中獲取文本框的輸入值丙唧,通過Bundle對象存入Intent愈魏,并以這個Intent對象啟動SecondActivity
。 - 修改
SecondActivity.java
文件中想际,實現(xiàn)已注冊的show
方法培漏,在其中獲取MainActivity
傳過來的值,并顯示在TextView中胡本。 - 檢查代碼牌柄,編譯并運(yùn)行這個應(yīng)用,在模擬器中查看運(yùn)行的過程侧甫,檢查其是否與設(shè)計的相一致珊佣。
下面是部分要用到的代碼:
首先是res/layout/activity_main.xml
中的內(nèi)容:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.work.eventtest.MainActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="60dp"
android:id="@+id/editText01"
android:layout_marginTop="20dp"
android:textSize="20sp"
android:background="@color/colorAccent"/>
<Button
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_below="@id/editText01"
android:layout_marginTop="50dp"
android:id="@+id/button1"
android:background="@color/colorPrimaryDark"
android:text="發(fā)送文本"/>
</RelativeLayout>
接下來是MainActivity.java
中的內(nèi)容蹋宦,建議你先按照自己的思路實現(xiàn),再來通過下面的代碼驗證自己的想法:
package com.example.work.eventtest;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
private Button button;
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//實例化控件
button = (Button) findViewById(R.id.button1);
editText = (EditText)findViewById(R.id.editText01);
// 通過匿名內(nèi)部類來為button注冊點擊事件監(jiān)聽器
button.setOnClickListener(new View.OnClickListener() {
// 重寫onCLick()方法咒锻,實現(xiàn)點擊事件處理者的功能
@Override
public void onClick(View v) {
// 創(chuàng)建一個字符串對象用于接收來自文本框的輸入內(nèi)容
String message = new String();
// 通過文本框的getText()方法獲取輸入內(nèi)容冷冗,賦予message字符串對象
message = editText.getText().toString();
// 創(chuàng)建一個“意圖”,用于從MainActivity跳轉(zhuǎn)到SecondActivity
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
// 創(chuàng)建一個Bundle對象惑艇,名為data蒿辙,用于在Activity之間傳遞信息
Bundle data = new Bundle();
// 向這個Bundle對象中存入內(nèi)容,因為是字符串滨巴,所以用putString()方法
// 參數(shù)的形式是key-value形式思灌,在另外一個Activity取出內(nèi)容的時候就是通過這個key
// 如果是其他的內(nèi)容,則根據(jù)不同的數(shù)據(jù)類型選用不同的存入方法
data.putString("mA",message);
// 最后將Bundle存入intent對象中恭取,讓后者攜帶到另外一個Activity中
intent.putExtras(data);
// 調(diào)用startActivity()方法泰偿,跳轉(zhuǎn)到另外一個Activity
startActivity(intent);
// 如果你想在啟動SecondActivity的過程中關(guān)閉現(xiàn)在這個Activity,
// 則可以使用finish()方法來結(jié)束當(dāng)前Activity蜈垮。
// MainActivity.this.finish();
}
});
}
}
接下來再創(chuàng)建一個SecondActivity
,下面是res/layout/activity_second.xml
中的內(nèi)容甜奄。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_second"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff00ff"
tools:context="com.example.work.eventtest.SecondActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="30dp"
android:background="#00aaee"
android:textSize="20sp"
android:id="@+id/textview1"/>
<Button
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_below="@id/textview1"
android:layout_marginTop="50dp"
android:background="#aa00e0"
android:text="顯示傳過來的文本"
android:onClick="show"
android:id="@+id/button2"/>
</RelativeLayout>
以下是SecondActivity.java
中的內(nèi)容,在這里面我們就沒有注冊按鈕的點擊事件監(jiān)聽器了窃款,而是實現(xiàn)了一個show()
方法用于承擔(dān)點擊事件處理者的職責(zé)课兄。
package com.example.work.eventtest;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class SecondActivity extends AppCompatActivity {
// 聲明一個文本標(biāo)簽控件
private TextView textView;
// 聲明一個字符串變量用于存放前一個Activity中傳過來的信息
private String message;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
// 實例化這個文本標(biāo)簽
textView = (TextView)findViewById(R.id.textview1);
// 通過getIntent()方法來獲得啟動當(dāng)前Activity的上一個Intent對象
Intent intent = getIntent();
// 從intent對象中通過getExtras()方法獲得其攜帶的消息,
// 接下來調(diào)用getString()方法來得到這個字符串晨继,注意該方法的參數(shù)為(字符串的key烟阐,默認(rèn)值)
message = intent.getExtras().getString("mA","null");
}
public void show(View view){
// 如果獲得了上個Activity傳過來的消息,則顯示在TextView中
if(message!=null){
textView.setText(message);
}
}
}
檢查一下代碼紊扬,編譯并運(yùn)行這個應(yīng)用蜒茄。等待應(yīng)用安裝至模擬器后,你會看到如下的畫面: