1 android事件處理概述 html
不管是桌面應用仍是手機應用程序,面對最多的就是用戶,常常須要處理用戶的動做-------也就是須要爲用戶動做提供響應,這種爲用戶動做提供響應的機制就是事件處理。android提供了兩套事件處理機制:java
主要作法就是爲Android界面組件綁定特定的事件監聽器;android還容許在界面佈局文件中爲UI組件的android:onClick屬性指定事件監聽方法,該方式須要開發者在activity中定義該事件監聽方法(該方法必須帶有一個View類型的形參,該形參表明被單擊的UI組件,當用戶單擊該組件時,系統將會激發android:onClick屬性所指定的方法)android
主要作法是重寫android組件特定的回調方法,或者重寫Activity的回調方法。(基於回調的事件處理能夠用於處理一些具備通用性的事件(業務邏輯比較固定),某些特定事件處理,仍需事件監聽機制。)程序員
2 基於監聽的事件處理編程
2.1 監聽的處理模型安全
2.1.1 事件監聽的處理模型中,主要涉及以下三類對象網絡
2.1.2 事件處理流程圖多線程
2.1.3 基於監聽的時間處理模型的編程步驟app
2.2 內部類做爲事件監聽器類異步
2.3 外部類做爲事件監聽器類
2.3.1 該形式比較少見,主要有兩點緣由:
2.3.2 若某個監聽器須要被多個GUI界面組件所共享,且主要是完成某種業務邏輯的實現,則可考慮外部類的形式
2.4 Activity自己做爲監聽器
直接用Activity自己做爲監聽器類,這種形式很是簡潔,但這種作法有兩個缺陷:
2.5 匿名內部類做爲事件監聽器
2.6 直接綁定到標籤
3 基於回調的事件處理
3.1 回調機制與監聽機制
3.2 android爲全部GUI組件都提供了一些事件處理的回調方法,以View爲例,該類包含如下方法:
3.3 基於回調的事件傳播
幾乎基於回調的事件處理方法都有一個boolean類型的返回值,該返回值用於標識該處理方法是否能徹底處理該事件:
3.4 兩種處理模型的區別
3.5 示例
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal"> <EditText android:id="@+id/address" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="請填寫收信號碼" /> <EditText android:id="@+id/content" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="請填寫短信內容" android:lines="3" /> <com.example.penghuster.myfirstapp.MyButton android:id="@+id/send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="發送" /> </LinearLayout>
import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.Button; import android.widget.EditText; public class MainActivity extends Activity { EditText address; EditText content; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); address = (EditText) findViewById(R.id.address); content = (EditText) findViewById(R.id.content); MyButton btn = (MyButton) findViewById(R.id.send); btn.requestFocus(); btn.setFocusableInTouchMode(true); btn.setOnKeyListener(new View.OnKeyListener() { public boolean onKey(View source, int value, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { Log.v("--Listener--", "the keydown "); } return false; } }); } public boolean onKeyDown(int keyCode, KeyEvent event){ super.onKeyDown(keyCode, event); Log.v("--activity---", "ddd"); return false; } } class MyButton extends Button{ public MyButton(Context context, AttributeSet set){ super(context, set); } public boolean onKeyDown(int keyCode, KeyEvent event){ super.onKeyDown(keyCode, event); Log.v("MyButton", "the onKeyDown in MyButton"); return false; } }
4 響應系統設置的事件
在開發Android應用時,有時可能須要讓應用程序隨系統設置而進行調整,好比判斷屏幕方向、判斷系統方向的方向導航設備等。除此以外,有時還須要讓應用程序監聽系統設置的更改,並做出響應。
4.1 Configuration類
4.1.1 簡介
4.1.2 重寫onConfigurationChanged響應系統設置更改
若是程序須要監聽系統設置的更改,則能夠考慮重寫Activity的onConfiguration(Configuration newConfig)方法,該方法是一個基於回調的事件處理方法,當系統設置發生更改時,該方法會被自動觸發。在程序中,能夠動態調用setRequestedOrientation(int)方法來修改屏幕方向
4.1.3 示例:監聽屏幕方向改變
Mainfest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.penghuster.myfirstapp" > <uses-sdk android:maxSdkVersion="12" android:minSdkVersion="10" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:configChanges="orientation|screenSize" android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
activity.java
import android.app.Activity; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity { EditText address; EditText content; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); address = (EditText) findViewById(R.id.address); content = (EditText) findViewById(R.id.content); MyButton btn = (MyButton) findViewById(R.id.send); btn.setOnClickListener(new View.OnClickListener() { public void onClick(View source) { Configuration cfg = getResources().getConfiguration(); if (cfg.orientation == Configuration.ORIENTATION_LANDSCAPE) MainActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); if (cfg.orientation == Configuration.ORIENTATION_PORTRAIT) MainActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } }); } public void onConfigurationChanged(Configuration configuration) { super.onConfigurationChanged(configuration); String screen = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE ? "橫向屏幕" : "豎向屏幕"; Toast.makeText(this, "系統屏幕方向改變\n" + "修改後屏幕方向爲:" + screen, Toast.LENGTH_LONG).show(); } }
5 Handler消息傳遞機制
5.1 UI線程
5.2 Handler類簡介
5.2.1 Handler類的主要做用
5.2.2 handler類消息處理原理
5.2.3 Handler類包含以下方法用於發送、處理消息
5.3 Handler、Loop、MessageQueue的工做原理
5.3.1 相關組件介紹
5.3.2 Looper對象的建立
因爲Looper對象沒有提供public構造器,可是Handler正常工做,必需要求當前線程中有一個Looper對象,爲了保證當前線程中有Looper對象,可分如下兩種狀況:
5.3.3 在新線程中使用Handler的步驟:
5.3.4 示例:使用新線程計算質數
import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends Activity { EditText address; EditText content; static final String UPPER_NUM = "upper"; CalThread calThread; class CalThread extends Thread { public Handler mHandler; public void run(){ Looper.prepare(); mHandler = new Handler(){ public void handleMessage(Message msg){ if (msg.what == 0x123){ int upper = msg.getData().getInt(UPPER_NUM); List<Integer> nums = new ArrayList<Integer>(); outer: for (int i=2; i<=upper; i++){ for (int j=2; j<=Math.sqrt(i); j++) if (i != 2 && i % j ==0) continue outer; nums.add(i); } Toast.makeText(MainActivity.this, nums.toString(), Toast.LENGTH_LONG).show(); } } }; Looper.loop(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); address = (EditText) findViewById(R.id.address); content = (EditText) findViewById(R.id.content); MyButton btn = (MyButton) findViewById(R.id.send); calThread = new CalThread(); calThread.start(); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Message msg = new Message(); msg.what = 0x123; Bundle bundle = new Bundle(); bundle.putInt(UPPER_NUM, Integer.parseInt(address.getText().toString())); msg.setData(bundle); calThread.mHandler.sendMessage(msg); } }); } }
6 異步任務
6.1 爲了解決新線程不能更新UI組件的問題,android提供了以下幾種解決方案。
6.2 AsyncTask(異步任務)
6.3 使用AsyncTask的步驟:
6.4 使用AsyncTask時必須遵照以下規則
6.5 示例:使用異步任務下載
import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; public class MainActivity extends Activity { TextView address; TextView content; class DownTask extends AsyncTask<URL, Integer, String> { ProgressDialog pDialog; int hasRead = 0; Context mContext; public DownTask(Context ctx) { mContext = ctx; } protected String doInBackground(URL... params) { StringBuilder sb = new StringBuilder(); try { URLConnection conn = params[0].openConnection(); BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); String line = null; while ((line = br.readLine()) != null) { sb.append(line + "\n"); hasRead++; publishProgress(hasRead); } return sb.toString(); } catch (Exception ex) { ex.printStackTrace(); } return null; } protected void onPostExecute(String result) { address.setText(result); pDialog.dismiss(); } protected void onPreExecute() { pDialog = new ProgressDialog(mContext); pDialog.setTitle("任務執行中"); pDialog.setMessage("任務執行中,敬請期待"); pDialog.setCancelable(false); pDialog.setMax(202); pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pDialog.setIndeterminate(true); pDialog.show(); } protected void onProgressUpdate(Integer... values) { content.setText("已經讀取了" + values[0] + "行!"); pDialog.setProgress(values[0]); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); address = (TextView) findViewById(R.id.address); content = (TextView) findViewById(R.id.content); MyButton btn = (MyButton) findViewById(R.id.send); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { DownTask task = new DownTask(MainActivity.this); task.execute(new URL("http://www.cnblogs.com/renqingping/archive/2012/10/25/Parcelable.html")); }catch (Exception e){ e.printStackTrace(); } } }); } }