Android 窗口添加机制系列3-代码实例

原创 2015年11月21日 19:12:46

有了上两篇做基础,那么来点干货

WindowManager.LayoutParams分析引出的应用层开发常用经典实例

这里的案例直接引用 Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析 这里的例子

Part1:开发APP时设置Activity全屏常亮的一种办法(设置Activity也就是Activity的Window)

public class MainActivity extends ActionBarActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //设置Activity的Window为全屏,当然也可以在xml中设置
        Window window = getWindow();
        WindowManager.LayoutParams windowAttributes = window.getAttributes();
        windowAttributes.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN | windowAttributes.flags;
        window.setAttributes(windowAttributes);
        //设置Activity的Window为保持屏幕亮
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.activity_main);
    }
}

Part2:App开发中弹出软键盘时下面的输入框被软件盘挡住问题的解决办法
在Activity中的onCreate中setContentView之前写如下代码:

//你也可以在xml文件中设置,一样的效果
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE|WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

Part3:创建悬浮窗口(仿IPhone的小圆点或者魅族的小白点或者360手机卫士的小浮标),退出当前Activity依旧可见的一种实现方法

/**
 * Author       : yanbo
 * Time         : 14:47
 * Description  : 手机屏幕悬浮窗,仿IPhone小圆点
 *               (未完全实现,只提供思路,如需请自行实现)
 * Notice       : <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
 */
public class WindowService extends Service {
    private WindowManager mWindowManager;
    private ImageView mImageView;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //创建悬浮窗
        createFloatWindow();
    }

    private void createFloatWindow() {
        //这里的参数设置上面刚刚讲过,不再说明
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        mWindowManager = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE);
        //设置window的type
        layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        //设置效果为背景透明
        layoutParams.format = PixelFormat.RGBA_8888;
        //设置浮动窗口不可聚焦
        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        layoutParams.gravity = Gravity.BOTTOM | Gravity.RIGHT;
        layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        layoutParams.x = -50;
        layoutParams.y = -50;

        mImageView = new ImageView(this);
        mImageView.setImageResource(android.R.drawable.ic_menu_add);
        //添加到Window
        mWindowManager.addView(mImageView, layoutParams);
        //设置监听
        mImageView.setOnTouchListener(touchListener);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mImageView != null) {
            //讲WindowManager时说过,add,remove成对出现,所以需要remove
            mWindowManager.removeView(mImageView);
        }
    }

    private View.OnTouchListener touchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            //模拟触摸触发的事件
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            return false;
        }
    };
}

此时在就算该进程退到后台,那么在手机屏幕的右下角也会有个图标,如果点击该图标,就会启动隐式的activity呢。

单例的toast

上篇文章说过了

有时候我们会发现Toast弹出过多就会延迟显示,因为上面源码分析可以看见Toast.makeText是一个静态工厂方法,每次调用这个方法都会产生一个新的Toast对象,当我们在这个新new的对象上调用show方法就会使这个对象加入到NotificationManagerService管理的mToastQueue消息显示队列里排队等候显示;所以如果我们不每次都产生一个新的Toast对象(使用单例来处理)就不需要排队,也就能及时更新了

    private int count = 0;
    @OnClick(R.id.but)
    void onClick() {
        String content = "Toast ID:" + count;
        Toast.makeText(this, content, Toast.LENGTH_SHORT).show();
        count++;
    }

连续点击多次10次,那么10个toast依次出现,只有等上一个toast消失了,才显示下一个toast。同时此时可能发生内存泄漏,如果此时点击10次之后,立马退出app,那么这个activity便不能被GC回收,一直需要等到10个toast全部显示完,为了防止内存泄漏,此时可以把this,换成getApplicationContext()

解决方案:
单例的SingleToast,内部持有Toast对象引用

为了防止内存泄漏,不管makeText方法传进来的是context,还是ApplicationContext,都把它转换为应用程序上下文context.getApplicationContext(),所以可以有效的防止内存泄漏

/**
 * Created by liaobinbin on 2015/11/21.
 */
public class SingleToast {

    private static Toast toast;
    private static SingleToast singleToast;

    private SingleToast(Context context, String text, int duration) {
        toast = Toast.makeText(context.getApplicationContext(), text, duration);
    }

    public static SingleToast makeText(Context context, String text, int duration) {
        if (singleToast == null) {
            synchronized (SingleToast.class) {
                if (singleToast == null) {
                    singleToast = new SingleToast(context, text, duration);
                }
            }
        }
        if (toast != null) {
            toast.setText(text);
        }
        return singleToast;
    }

    public void show() {
        if (toast != null) {
            toast.show();
        }
    }
}

使用SingleToast.makeText(getApplicationContext(), content, Toast.LENGTH_LONG).show(); 因为使用的是同一个单例的toast,所以可以做到toast快速的刷新,而不需要一个个排队显示了

    private int count = 0;
    private Toast toast;
    @OnClick(R.id.but)
    void onClick() {
        String content = "Toast ID:" + count;
        /*if (toast == null) {
            toast = Toast.makeText(getApplicationContext(), content, Toast.LENGTH_LONG);
        }else{
            toast.setText(content);
        }
        toast.show();*/
        SingleToast.makeText(getApplicationContext(), content, Toast.LENGTH_LONG).show();
        count++;
    }

子线程中显示dialog/toast

正常情况下,子线程中显示dialog/toast都会有以下异常
java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()

本质原因: dialog/toast内部都持有handler引用

    private final Handler mHandler = new Handler();
    public Handler(Callback callback, boolean async) {
        ........
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        ........
    }

子线程内部,如果没做任何处理,所以Looper.myLooper()当然是null了,所以报异常

解决方案:

    void showDialog() {
        new Thread("MyThread") {
            @Override
            public void run() {
                Looper.prepare(); //当然线程中调用Looper.myLooper()就不会为null了,此时为当前线程绑定了一个looper对象
                dialog = new AlertDialog.Builder(MainActivity.this).setTitle("标题").setMessage("内容").create(); //0.477
                dialog.show();
                Toast.makeText(MainActivity.this, "haha", Toast.LENGTH_SHORT).show();
                Looper.loop(); //别忘了这句,要不然拿不到消息啊,toast/dialog就显示不出来了
                //不要在这后面做任何事情,因为执行不到,Looper.loop();内部while循环
            }
        }.start();
    }

缺点:
这样的话,MyThread线程的话,一直就停止不了,被一直阻塞在Looper.loop();了,内部while循环

版权声明:本文为博主原创文章,转载请注明出处,http://blog.csdn.net/mr_liabill

相关文章推荐

Android的window类的常用方法

window类简介: Abstract base class for a top-level window look and behavior policy. An instance of this...

Android应用程序窗口(Activity)的窗口对象(Window) 的创建过程分析

每一个Activity组件都有一个关联的ContextImpl对象,同时,它还关联有一个Window对象,用来描述一个具体的应用程序窗口。由此又可知,Activity只不过是一个高度抽象的UI组件,它...

C#温故而知新学习系列之.NET运行机制—3-.NET中托管代码是指什么?

托管代码   托管代码就是基于.NET元数据格式的代码,运行于.NET平台之上,所有的与操作系统的交换由.NET平台来完成,就像是把这些功能委托给.NET,所以称之为托管代码   由公共语言运行库...

S3C2416裸机开发系列九_GCC启动代码工程应用实例

S3C2416裸机开发系列九 GCC启动代码工程应用实例 象棋小子    1048272975 GNU是一个自由软件工程项目,目标在于创建一个完全兼容于UNIX的自由软件环境。GNU已经开发出了...

Android中利用反射机制创建实例的代码

反射机制创建对象的最大优点是利用了Java语言的多态性,这样使得代码更加灵活。在观看源码的时候有这样一段代码就是典型的例子,可以借鉴: 出自SystemServiceManager的startSer...

Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析 《一》

浅析 Android 窗口的加载机制 以及Dialog PopWindow Toast显示机制

Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析 《三》-Dialog

Dialog的需要主要的问题 以及实现机制

Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析

【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重劳动成果】1 背景之所以写这一篇博客的原因是因为之前有写过一篇《Android应用setContentV...
  • yanbober
  • yanbober
  • 2015年06月08日 20:50
  • 33339

Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析 《五》-Toast

5 Android应用Toast窗口添加显示机制源码 5-1 基础知识准备在开始分析这几个窗口之前需要脑补一点东东,我们从应用层开发来直观脑补,这样下面分析源码时就不蛋疼了。如下是一个我们写的两个应...

Android OpenCV 实例笔记3 -- 摄像头竖屏全屏的设置,更新完整代码

Android OpenCV 实例笔记3 -- 摄像头竖屏全屏的设置    Feemic 2016年08月07日 未完结,更新中   Android终端下,OPENCV打开摄像头后,默认为横屏输...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android 窗口添加机制系列3-代码实例
举报原因:
原因补充:

(最多只允许输入30个字)