Andriod事件处理的方式
1.基于监听的事件处理
2.基于回调的事件处理
1. 基于监听的事件处理
1.1 监听的事件处理模型
Event Source:事件源,通常指事件发生的场所,即各个组件
Event:用户的一次操作
Event Listener:负责监听事件源发生的事件
该方式是委托式事件处理方式,组件将事件处理委托给监听器
1.2 实现方式
*
1)内部类作为监听器
public class MainActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
...
Button btn=findViewById(R.id.btn);
btn.setOnClickListener(new clickListener());
...
}
class clickListener implements View.OnclickListener{
...
}
}
无需传活动上下文对象给监听器,因为是内部类可以直接拿到。
2)外部类作为监听器‘
需要要传活动对象给外部类监听器
发短信案例:
public class MainActivity extends Activity
{
EditText address;
EditText content;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取页面中收件人地址、短信内容
address = (EditText)findViewById(R.id.address);
content = (EditText)findViewById(R.id.content);
Button bn = (Button)findViewById(R.id.send);
bn.setOnLongClickListener(new SendSmsListener(
this , address, content));
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.SEND_SMS)!=
PackageManager.PERMISSION_GRANTED){ //需要判断是否申请了权限
ActivityCompat.requestPermissions(MainActivity.this,new String[]{
Manifest.permission.SEND_SMS},1);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch(requestCode){
case 1:
if(grantResults.length>0&&grantResults[0]!=PackageManager.PERMISSION_GRANTED){
Toast.makeText(this,"你没有开启发短信权限",Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
break;
}
}
}
public class SendSmsListener implements OnLongClickListener
{
private Activity act;
private EditText address;
private EditText content;
public SendSmsListener(Activity act, EditText address
, EditText content)
{
this.act = act;
this.address = address;
this.content = content;
}
@Override
public boolean onLongClick(View source)
{
String addressStr = address.getText().toString();
String contentStr = content.getText().toString();
// 获取短信管理器
SmsManager smsManager = SmsManager.getDefault();
// 创建发送短信的PendingIntent
PendingIntent sentIntent = PendingIntent.getBroadcast(act
, 0, new Intent(), 0);
// 发送文本短信
smsManager.sendTextMessage(addressStr, null, contentStr
, sentIntent, null);
Toast.makeText(act, "短信发送完成", Toast.LENGTH_LONG).show();
return false;
}
}
注册活动,允许启用相应权限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.crazyit.event" >
<uses-permission android:name="android.permission.SEND_SMS"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
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>
3)活动自身作为监听器
public class MainActivity extends Activity implements View.OnclickListener{
...
btn.setOnClickListener(this);
text.setOnClickListener(this);
public void onClick(View v){
switch(vid){
case R.id.btn:
//
case R.id.text:
//
}
}
}
4)lambda表达式作为监听对象
btn.setOnClickListener(v->{
//具体处理
});
5)标定到标签
在活动布局文件中注册事件,在活动中复写对应事件处理方法
<Button andriod:onClick="click"/>
2.事件回调
组件无需注册监听器,复写组件预置的监听事件处理方法
如果组件自身重写了事件处理方法①,且注册了事件处理器②,同时活动也复写了事件处理方法③,则事件捕获顺序为:①->②->③
3.响应系统设置的事件
4.利用Handler传递消息
两个案例:
1.计算质数(主线程向子线程发消息)
2.打地鼠,主线程自己收发消息
public class DiglettActivity extends AppCompatActivity implements View.OnClickListener,View.OnTouchListener{
public static final int CODE = 123;
private TextView mResultTextView;
private ImageView mDiglettImageView;
private Button mStarrButton;
public int[][] mPosition = new int[][]{
{342,180},{432,880},
{521,256},{429,780},
{456,976},{145,665},
{123,678},{564,567},
};
private int mTotalCount;
private int mSuccessCount;
public static final int MAX_COUNT = 10;
private DiglettHandler mHandler = new DiglettHandler(this);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_diglett);
initView();
setTitle("打地鼠");
}
private void initView(){
mResultTextView = (TextView)findViewById(R.id.text_view);
mDiglettImageView = (ImageView)findViewById(R.id.image_view);
mStarrButton = (Button)findViewById(R.id.start_button);
mStarrButton.setOnClickListener(this);
mDiglettImageView.setOnTouchListener(this);
}
@Override
public void onClick(View v){
switch (v.getId()){
case R.id.start_button:
start();
break;
}
}
private void start(){
//发送消息 handler.sendmessagedelayer
mResultTextView.setText("开始啦");
mStarrButton.setText("游戏中.....");
mStarrButton.setEnabled(false);
next(0);
}
private void next(int delayTime){
int position = new Random().nextInt(mPosition.length);
Message message = Message.obtain();
message.what =CODE;
message.arg1 = position;
mHandler.sendMessageDelayed(message,delayTime);
mTotalCount ++;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
v.setVisibility(View.GONE);
mSuccessCount ++ ;
mResultTextView.setText("打到了"+ mSuccessCount +"只,共" + MAX_COUNT +"只.");
return false;
}
public static class DiglettHandler extends Handler{
public static final int RANDOM_NUBER = 500;
public final WeakReference<DiglettActivity> mWeakReference;
public DiglettHandler(DiglettActivity activity){
mWeakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
DiglettActivity activity = mWeakReference.get();
switch (msg.what){
case CODE:
if (activity.mTotalCount >MAX_COUNT){
activity.clear();
Toast.makeText(activity,"地鼠打完了!",Toast.LENGTH_LONG).show();
return;
}
int position = msg.arg1;
activity.mDiglettImageView.setX(activity.mPosition[position][0]);
activity.mDiglettImageView.setY(activity.mPosition[position][1]);
activity.mDiglettImageView.setVisibility(View.VISIBLE);
int randomTime = new Random().nextInt(RANDOM_NUBER) + RANDOM_NUBER;
activity.next(randomTime);
break;
}
}
}
private void clear(){
mTotalCount = 0;
mSuccessCount = 0;
mDiglettImageView.setVisibility(View.GONE);
mStarrButton.setText("点击开始");
mStarrButton.setEnabled(true);
}
}
5.利用异步任务处理耗时任务
1.只有主线程可以对UI操作,因此当新线程处理完耗时任务之后,可使用如下方法处理UI:
2.使用异步任务
异步下载代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
public static final int INIT_PROGRESS = 0;
public static final String APK_URL = "http://download.sj.qq.com/upload/connAssitantDownload/upload/MobileAssistant_1.apk";
public static final String FILE_NAME = "imooc.apk";
private ProgressBar mProgressBar;
private Button mDownloadButton;
private TextView mResultTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化视图
initView();
// 设置点击监听
setListener();
// 初始化UI数据
setData();
private void initView() {
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mDownloadButton = (Button) findViewById(R.id.button);
mResultTextView = (TextView) findViewById(R.id.textView);
}
private void setListener() {
mDownloadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO: 16/12/19 下载任务
DownloadAsyncTask asyncTask = new DownloadAsyncTask();
asyncTask.execute(APK_URL);
}
});
}
private void setData() {
mResultTextView.setText(R.string.download_text);
mDownloadButton.setText(R.string.click_download);
mProgressBar.setProgress(INIT_PROGRESS);
}
/**
* String 入参
* Integer 进度
* Boolean 返回值
*/
public class DownloadAsyncTask extends AsyncTask<String, Integer, Boolean> {
String mFilePath;
/**
* 在异步任务之前,在主线程中
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
// 可操作UI 类似淘米,之前的准备工作
mDownloadButton.setText(R.string.downloading);
mResultTextView.setText(R.string.downloading);
mProgressBar.setProgress(INIT_PROGRESS);
}
/**
* 在另外一个线程中处理事件
*
* @param params 入参 煮米
* @return 结果
*/
@Override
protected Boolean doInBackground(String... params) {
if(params != null && params.length > 0){
String apkUrl = params[0];
try {
// 构造URL
URL url = new URL(apkUrl);
// 构造连接,并打开
URLConnection urlConnection = url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
// 获取了下载内容的总长度
int contentLength = urlConnection.getContentLength();
// 下载地址准备
mFilePath = Environment.getExternalStorageDirectory()
+ File.separator + FILE_NAME;
// 对下载地址进行处理
File apkFile = new File(mFilePath);
if(apkFile.exists()){
boolean result = apkFile.delete();
if(!result){
return false;
}
}
// 已下载的大小
int downloadSize = 0;
// byte数组
byte[] bytes = new byte[1024];
int length;
// 创建一个输入管道
OutputStream outputStream = new FileOutputStream(mFilePath);
// 不断的一车一车挖土,走到挖不到为止
while ((length = inputStream.read(bytes)) != -1){
// 挖到的放到我们的文件管道里
outputStream.write(bytes, 0, length);
// 累加我们的大小
downloadSize += length;
// 发送进度
publishProgress(downloadSize * 100/contentLength);
}
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
} else {
return false;
}
return true;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
// 也是在主线程中 ,执行结果 处理
mDownloadButton.setText(result? getString(R.string.download_finish) : getString(R.string.download_finish));
mResultTextView.setText(result? getString(R.string.download_finish) + mFilePath: getString(R.string.download_finish));
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// 收到进度,然后处理: 也是在UI线程中。
if (values != null && values.length > 0) {
mProgressBar.setProgress(values[0]);
}
}
}
}