• Toast的另类应用及另类“拦截”Home键


            我们都知道Toast的几种用法,像什么居中啊,添加图片显示啊等等。不过这里我要说的是能够全屏显示和永远不会消失的另类Toast。全屏显示和之前大家了解的居中有点类似,只要修改setGravity(int gravity, int xOffset,int yOffset)中的第一个参数值为Gravity.FILL就ok了。麻烦的是要让Toast永远不消失,这里我们要用到反射机制。

            我们要了解一件事,那就是我们在弹出Toast的时候,必须加上.show()。顾名思义,大家可能都会以为,这里的.show()是去显示这个Toast。不过遗憾的是,事实并非如此。我们可以看看如下show()的源代码:

    public void show() {
        if (mNextView == null) {
            throw new RuntimeException("setView must have been called");
        }
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();
        TN tn = mTN;
        try {
            //  将当前Toast加入到Toast队列
            service.enqueueToast(pkg, tn, mDuration);
        } catch (RemoteException e) {
            // Empty
        }
    }
            正如service.enqueueToast(pkg, tn, mDuration);这一句所说,我们只是通过.show()来把当前Toast加入到Toast队列中,再由系统根据Toast队列来显示Toast信息提示框,并不是去显示当前Toast。因为我们不能去直接控制系统中要做的事,所以我们不能再去调用show()方法了。如果不调用show()方法,我们知道,Toast是不会显示出来的。所以,这里我们就要去自己写一个方法让我们当前的Toast显示出来。我们是用反射来解决这个问题的。关键代码如下:

    private Object mTN;
    	private Method mShow;
    	private Method mHide;
    	private Field mViewFeild;
    	private View mLayout;
    	private HomeKeyEventBroadCastReceiver receiver; // 监听HOME键
    
    	/**
    	 * 开启永不消失的Toast
    	 */
    	private void showForeverToast() {
    		mLayout = getLayoutInflater().inflate(R.layout.newtoast, null);
    		Toast toast = new Toast(getApplicationContext());
    		toast.setGravity(Gravity.FILL, 0, 0);
    		toast.setDuration(0);
    		Field field = null;
    		try {
    			field = toast.getClass().getDeclaredField("mTN");
    			field.setAccessible(true);
    			mTN = field.get(toast);
    			mShow = mTN.getClass().getDeclaredMethod("show");
    			mHide = mTN.getClass().getDeclaredMethod("hide");
    			mViewFeild = mTN.getClass().getDeclaredField("mNextView");
    			mViewFeild.setAccessible(true);
    		} catch (NoSuchFieldException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		} catch (IllegalArgumentException e) {
    			e.printStackTrace();
    		} catch (NoSuchMethodException e1) {
    			e1.printStackTrace();
    		}
    		
    		show(mLayout); // 显示Toast
    	}
    显示Toast的代码如下:

    private void show(View layout) {
    		try {
    			mViewFeild.set(mTN, layout);
    			mShow.invoke(mTN, new Object[] {});
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		} catch (IllegalArgumentException e) {
    			e.printStackTrace();
    		} catch (InvocationTargetException e) {
    			e.printStackTrace();
    		}
    	}
    隐藏Toast的代码如下:

    private void hide(View layout) {
    		try {
    			mHide.invoke(mTN, new Object[] {});
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		} catch (IllegalArgumentException e) {
    			e.printStackTrace();
    		} catch (InvocationTargetException e) {
    			e.printStackTrace();
    		}
    	}
    通过以上的代码就可以让我们的Toast全屏显示和永不消失了。

    下面我就来说说关于拦截Home键的方法。之前我也是找了很多关于拦截和屏蔽Home键的方法,自己都试过,根本行不通(当然也可能是我自己的问题,如果大家有什么好的方法,可以给我留言)。所以,这里我就取了个巧(其实是一个假的拦截和屏蔽),我是采用了当我们点击Home键的时候,退回桌面,同时程序转入后台,一定时间后程序再从后台转入前台。关键代码正下:

    class HomeKeyEventBroadCastReceiver extends BroadcastReceiver {
    		static final String SYSTEM_REASON = "reason";
    		static final String SYSTEM_HOME_KEY = "homekey"; // home key
    		static final String SYSTEM_RECENT_APPS = "recentapps"; // long home key
    
    		@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_REASON);
    				if (reason != null) {
    					if (reason.equals(SYSTEM_HOME_KEY)) {
    						// 从桌面启动app(利用RestartService过渡)
    						Intent newIntent = new Intent();
    	                    newIntent.setClass(context, RestartService.class);
    	                    context.startService(newIntent);
    	                    
    						showToastByHome();
    					} else if (reason.equals(SYSTEM_RECENT_APPS)) {
    						hideToastByHome();
    					}
    				}
    			}
    		}
    	}
    点击Home键后,弹出全屏的Toast.5秒后又自动消失:

    private void showToastByHome() {
    		showForeverToast(); // 显示全屏的Toast
    		if (mThread == null || !mThread.isAlive() || mThread.isInterrupted()) {
    			mThread = new Thread() {
    				@Override
    				public void run() {
    					try {
    						sleep(5000);
    						hide(mLayout);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			};
    			mThread.start();
    		}
    	}
    看上面的第一段代码,可以很容易地发现我是在退回桌面的同时,跳转到一个RestartService,这个Service会在5秒后再进行一次跳转(从Service跳转程序的前台Activity),这样就实现了假的拦截Home了,如果亲们对这个拦截Home键的功能比较急,要求又不是很苛刻的话,可以先用这样的方法顶一下。而Service中的代码也很简单,几句话,如下:

    public void onStart(Intent intent, int startId) {
            Intent newIntent = new Intent(getApplicationContext(), MainActivity.class);
            newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(newIntent);
            super.onStart(intent, startId);
        }
    这里是本篇博客的工程连接:http://download.csdn.net/detail/u013761665/8015397

    本博客参考博文:
    Android开发技巧:永不关闭的Toast信息框

    Android开发技巧:永不关闭的Toast信息框(修正版)android4.x



  • 相关阅读:
    北科的秋天
    最大子段和问题(dp)
    cmd应用
    问题 H: 抽奖活动(大数)
    大数算法
    模板整理(三)
    在CMD中建立一个不能删除的文件
    波利亚(Polya)罐子模型
    51nod-迷宫问题(Dijkstra算法)
    优先队列
  • 原文地址:https://www.cnblogs.com/fengju/p/6336140.html
Copyright © 2020-2023  润新知