編輯:關於Android編程
在Activity,Service,Window中監聽Home鍵和返回鍵的一些思考,如何把事件傳遞出來的做法!
其實像按鍵的監聽,我相信很多人都很熟練了,我肯定也不會說這些基礎的東西,所以,前期,還是一筆帶過一下,我們重點說下後半部分吧
這個其實大家都知道,首先我們要了解流程,你要屏蔽這個返回鍵,那你就要拿到這個返回鍵的事件了,所以我們要監聽了,而在Activity中,有兩種做法,首先,系統是提供了返回鍵的監聽的
/** * 返回鍵監聽 */ @Override public void onBackPressed() { //super.onBackPressed(); }
我們只要不讓使用父類的onBackPressed方法,那返回鍵就沒作用了,還有一種辦法就是系統提供的按鍵監聽的方法了
/** * 按鍵監聽 * @param keyCode * @param event * @return */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: //返回鍵 Toast.makeText(this,"返回鍵",Toast.LENGTH_SHORT).show(); break; } return super.onKeyDown(keyCode, event); }
onKeyDown是按下的動作,鍵盤按下的動作就可以,他可以監聽到很多的按鍵,比如數字鍵,當然,現在數字鍵的手機還是比較少的,KeyEvent 為我們封裝了絕大多數的監聽,我們來看一下演示的效果
onKeyDown中有監聽Home鍵的方法,但是你會發現監聽起來是無效的,這裡其實可以通過廣播的形式來監聽Home鍵,不光適用在Service,同樣的也可以適用在Activity中,我們新建一個HomeService
package com.liuguilin.keyevevtsample; /* * 項目名: KeyEvevtSample * 包名: com.liuguilin.keyevevtsample * 文件名: HomeService * 創建者: LGL * 創建時間: 2016/8/20 11:00 * 描述: Home鍵監聽 */ import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.IBinder; import android.widget.Toast; public class HomeService extends Service { //監聽Home private HomeWatcherReceiver mHomeKeyReceiver; public static final String SYSTEM_DIALOG_REASON_KEY = "reason"; public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); //注冊Home監聽廣播 mHomeKeyReceiver = new HomeWatcherReceiver(); final IntentFilter homeFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); registerReceiver(mHomeKeyReceiver, homeFilter); } @Override public void onDestroy() { super.onDestroy(); //取消監聽 unregisterReceiver(mHomeKeyReceiver); } /** * 監聽Home鍵 */ class HomeWatcherReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY); if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) { Toast.makeText(context, "Home按鍵", Toast.LENGTH_SHORT).show(); } } } } }
OK,為了測試,我們加上兩個button
同時增加兩個點擊事件
findViewById(R.id.openHome).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startService(new Intent(MainActivity.this,HomeService.class)); } }); findViewById(R.id.closeHome).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { stopService(new Intent(MainActivity.this,HomeService.class)); } });
對了,別忘記了注冊一下Service
好的,我們來檢驗一下效果吧
OK<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjwvYmxvY2txdW90ZT4NCjxoMiBpZD0="三在window中監聽返回鍵">三.在Window中監聽返回鍵
這裡,其實也是我項目中的一個需求,首選,我們先不說邏輯,先把window寫好,我們為了閱讀性,我們再新建一個Service——WindowService,同時去注冊一下
而我們的需求,就是啟動一個service,service裡加載一個window,但是這樣做其實是拿不到我們的按鍵時間的,都給其他人拿走了,但是這些都是後話了,我們先把window的代碼寫好
package com.liuguilin.keyevevtsample; /* * 項目名: KeyEvevtSample * 包名: com.liuguilin.keyevevtsample * 文件名: WindowService * 創建者: LGL * 創建時間: 2016/8/20 11:11 * 描述: 窗口服務 */ import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; import android.os.IBinder; import android.view.View; import android.view.WindowManager; import android.widget.Button; public class WindowService extends Service implements View.OnClickListener { //窗口管理器 private WindowManager wm; //view private View mView; //布局參數 private WindowManager.LayoutParams layoutParams; //取消window private Button btnCloseWindow; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); initWindow(); } /** * 初始化Window */ private void initWindow() { //窗口管理器 wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); //布局參數 layoutParams = new WindowManager.LayoutParams(); layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; layoutParams.flags = //WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | 不能觸摸 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; //格式 layoutParams.format = PixelFormat.TRANSLUCENT; //類型 layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; mView = View.inflate(getApplicationContext(), R.layout.layout_window_item, null); btnCloseWindow = (Button) mView.findViewById(R.id.btnCloseWindow); btnCloseWindow.setOnClickListener(this); } @Override public int onStartCommand(Intent intent, int flags, int startId) { //顯示window wm.addView(mView, layoutParams); return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); } /** * 點擊事件 * * @param view */ @Override public void onClick(View view) { switch (view.getId()) { case R.id.btnCloseWindow: //取消window wm.removeView(mView); break; } } }這裡有一點要注意的地方,首先,window是需要權限的
好的,為了測試,我們些個按鈕
同時給他加上點擊事件
findViewById(R.id.openWindow).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startService(new Intent(MainActivity.this, WindowService.class)); } });OK,到這裡,我們的window算是寫好了,但是寫好了,也就出來我們今天要探討的問題了
你這個Window,拿不到返回事件,所以我按返回鍵的時候Activity退出了,window還在,那window就是沒有拿到這個事件了,那我們應該怎麼去拿到這個事件呢?我們怎麼按返回鍵先退出Window再退出Activity呢?其實我們只要注意這行代碼
mView = View.inflate(getApplicationContext(), R.layout.layout_window_item, null);我們這裡也是有一個View的,我們可用把這個事件給攔截過來,這都是有可能的,想到了就去做,那我們最終要怎麼去做?我們可用重寫這個view,把事件通過接口的方式綁定在這個window上,如果不聽不明白,你可以跟我一起來看下這段代碼,我們這個view,我給他一個容器,那我們就重寫LinearLayout
package com.liuguilin.keyevevtsample; /* * 項目名: KeyEvevtSample * 包名: com.liuguilin.keyevevtsample * 文件名: SessionLinearLayout * 創建者: LGL * 創建時間: 2016/8/20 11:33 * 描述: 事件分發/攔截返回按鈕 */ import android.content.Context; import android.util.AttributeSet; import android.view.KeyEvent; import android.widget.LinearLayout; public class SessionLinearLayout extends LinearLayout { private DispatchKeyEventListener mDispatchKeyEventListener; public SessionLinearLayout(Context context) { super(context); } public SessionLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } public SessionLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean dispatchKeyEvent(KeyEvent event) { if (mDispatchKeyEventListener != null) { return mDispatchKeyEventListener.dispatchKeyEvent(event); } return super.dispatchKeyEvent(event); } public DispatchKeyEventListener getDispatchKeyEventListener() { return mDispatchKeyEventListener; } public void setDispatchKeyEventListener(DispatchKeyEventListener mDispatchKeyEventListener) { this.mDispatchKeyEventListener = mDispatchKeyEventListener; } //監聽接口 public static interface DispatchKeyEventListener { boolean dispatchKeyEvent(KeyEvent event); } }我在這裡,只是把他作為一個中轉站,把事件給傳遞出來就好了,那我們現在window加載的layout的根布局就是他了
那我們的View也是他了,我們直接來看詳細的代碼吧
package com.liuguilin.keyevevtsample; /* * 項目名: KeyEvevtSample * 包名: com.liuguilin.keyevevtsample * 文件名: WindowService * 創建者: LGL * 創建時間: 2016/8/20 11:11 * 描述: 窗口服務 */ import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; import android.os.IBinder; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; import android.widget.Button; public class WindowService extends Service implements View.OnClickListener { //窗口管理器 private WindowManager wm; //view private SessionLinearLayout mView; //布局參數 private WindowManager.LayoutParams layoutParams; //取消window private Button btnCloseWindow; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); initWindow(); } /** * 初始化Window */ private void initWindow() { //窗口管理器 wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); //布局參數 layoutParams = new WindowManager.LayoutParams(); layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; layoutParams.flags = //WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | 不能觸摸 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH ; //格式 layoutParams.format = PixelFormat.TRANSLUCENT; //類型 layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; mView = (SessionLinearLayout) View.inflate(getApplicationContext(), R.layout.layout_window_item, null); btnCloseWindow = (Button) mView.findViewById(R.id.btnCloseWindow); btnCloseWindow.setOnClickListener(this); //監聽返回鍵 mView.setDispatchKeyEventListener(mDispatchKeyEventListener); } /** * 返回鍵監聽 */ private SessionLinearLayout.DispatchKeyEventListener mDispatchKeyEventListener = new SessionLinearLayout.DispatchKeyEventListener() { @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { if (mView.getParent() != null) { wm.removeView(mView); } return true; } return false; } }; @Override public int onStartCommand(Intent intent, int flags, int startId) { //顯示window wm.addView(mView, layoutParams); return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); } /** * 點擊事件 * * @param view */ @Override public void onClick(View view) { switch (view.getId()) { case R.id.btnCloseWindow: //取消window wm.removeView(mView); break; } } }OK,我們這裡只是用了一個小技巧而已,但是在實際開發當中還是很實用的,我們直接來看效果
好的,本篇博文就先到這裡,感謝你的耐心閱讀,覺得不錯的haunted贊一個喲,有不足的地方也請指正
剛開始學習Service的時候以為它是一個線程的封裝,也可以執行耗時操作。其實不然,Service是運行在主線程的。直接執行耗時操作是會阻塞主線程的。長時間就直接ANR了
這篇文章主要介紹一下如何實現View的3D旋轉效果,實現的主要原理就是圍繞Y軸旋轉,同時在Z軸方面上有一個深入的縮放。演示的demo主要有以下幾個重點: 1,自定義旋轉動
首先看不正常的圖,點擊tracing_dialog按鈕彈出對話框然後看理論上的效果圖觀察兩張圖發現,不正常的圖最上方被狀態欄遮擋住了,而該問題存在於android4.4版
ACRA : Application crash report for android作用: 為自己的應用找bug 使用步驟:參考文檔自定義布局的實現:流程圖參照流程圖: