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(); } } }); } }