DialogFragment的使用与底层绘制

请尊重他人劳动成果,请勿随意剽窃,转载请注明,谢谢!转载请注明出处:http://blog.csdn.net/evan_man/article/details/51812678

DialogFrament是一类特定的Fragment,会将视图绘制在Activity视图的上方。一般使用场景就是展示一个警示对话框,确认对话框。使用DialogFragment而不是直接使用Dialog是一种比较推荐的方式。如果直接使用Dialog那么Dialog的生命周期是需要我们自己手动去管理的,而对于DialogFragment,它将自身交给FragmentManager进行管理,与Activity生命周期一致。比如当Activity销毁时,此时如果存在对话框,那么系统会自动销毁该对话框。而如果使用Dialog,很可能Activity已经销毁而Dialog依然存在,造成系统错误,程序出现异常。本文的大体脉络和之前博客一致,首先介绍DialogFragment如何在应用中使用,最后分析DialogFragment是如何一步一步的被绘制的屏幕上面的。

简单使用

一、重写一个类继承自android.support.v4.app.DialogFragment

对于Dialog准备采用自定义布局的需要重写onCreateView、onViewCreated方法

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.dialog_fragment_profile, container);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        //view中的控件进行一系列初始化
}

对于准备才用Android那几种内置的Dialog的需要只要重写onCreateDialog方法

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
        String title = getArguments().getString("title"); //之前通过setArguments传入的参数
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
        alertDialogBuilder.setTitle(title);
        alertDialogBuilder.setMessage("Are you sure?");
        alertDialogBuilder.setPositiveButton("OK",  new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // on success
            }
        });
        alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        return alertDialogBuilder.create();
}

二、定义DialogFragment的样式

DialogFragment是动态创建的,不是在xml布局文件中定义的。因此它的样式基本上都是通过所属Context的theme来指定的。下面是一个简单范例,内容出现在工程项目中的style.xml文件中。

<style name="AppTheme" parent="Theme.AppCompat.Light">
    <!-- Apply default style for dialogs -->
    <item name="android:dialogTheme">@style/AppDialogTheme</item>
</style>

<style name="EvanBaseDialogTheme" parent="Theme.AppCompat.Light.Dialog">
        <!--此处的值也控制ActionBar背景-->
        <item name="colorPrimary">@color/colorPrimary</item>
        <!--此处的值也控制ActionBar上面显示电量、信号那行视图的背景-->
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <!--控制比如editText被选中状态下下面那条线的颜色-->
        <item name="colorAccent">@color/red</item>
        <!--控制比如editText中长按选中的那部分文字的颜色,一般对其进行复制粘贴操作-->
        <item name="android:textColorHighlight">@color/purple</item>
        <!--控制比如editText正常状态下下面那条线的颜色-->
        <item name="colorControlNormal">@color/white</item>

        <!-- Define window properties as desired -->
        <item name="android:windowNoTitle">false</item>
        <item name="android:windowTitleStyle">@style/EvanBaseDialogWindowTitle</item>

        <item name="android:windowFullscreen">false</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowCloseOnTouchOutside">true</item>
        <!--此处设置为真则背景是灰色,没有阴影效果-->
        <item name="android:windowIsTranslucent">true</item>
        <!--整个对话框的背景颜色-->
        <item name="android:windowBackground">@drawable/white_corners_background</item>
</style>

<style name="EvanBaseDialogWindowTitle"  parent="Base.DialogWindowTitle.AppCompat">
        <item name="android:layout_gravity">center</item>
        <item name="android:gravity">center</item>
        <!--整个title部分的背景颜色-->
        <item name="android:background">@color/white</item>
        <!--title文字显示的样子 大小等-->
        <item name="android:textAppearance">@style/EvanBaseDialogWindowTitleText</item>
    </style>
    <style name="EvanBaseDialogWindowTitleText" parent="@android:style/TextAppearance.DialogWindowTitle">
        <item name="android:textSize">@dimen/big_textSize</item>
 </style>

三、Activity中创建DialogFragment对象,并显示出来

FragmentManager fm = mActivity.getSupportFragmentManager();
 MyDialogFragment mDialog = MyDialogFragment.newInstance("Some title"); //DialogFragment的创建一般都是通过getInstance方法创建。
 mDialog.show(fm, "fragment_tag");

四、其它DialogFragment的简单使用

AlertDialog:可以修改的内容有一个标题、一个Message、三个Button。其它使用与前面介绍的一致。

ProgressDialog:可以修改的内容有一个标题、一个Message、Progress样式。Reference:http://www.quicktips.in/show-progressdialog-android/

ProgressDialog pd = new ProgressDialog(context);
pd.setTitle("Loading...");
pd.setMessage("Please wait.");
pd.setCancelable(false);
pd.show();  or  pd.dismiss();

更多DialogFragment用法参考:http://guides.codepath.com/android/Using-DialogFragment

深入分析

分析目的在于了解DialogFragment视图如何动态添加View到屏幕上,跟PopupWindows一样?我们从android.support.v4.app.DialogFragment的show方法入手。

DialogFragment.class

public class DialogFragment extends Fragment

show()@DialogFragment.class

public void show(FragmentManager manager, String tag) {
        mDismissed = false;
        mShownByMe = true;
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag); //note1
        ft.commit();
}

1、添加的Fragment是没有containerID的。onCreateView方法的参数ViewGroup container为null,表明onCreateView所创建出来的View显示到所属Activity的布局中的某个View中。既然如此,那肯定是DialogFrament通过重写父类Fragment的生命周期中的某些方法,在方法内部动态向手机屏幕上显示对话框视图,往下我们就对Fragment中的方法进行说明。对于Fragment的生命周期等感兴趣的可以参考本人另外一篇博客:http://blog.csdn.net/evan_man/article/details/51329320

简单回顾一下Fragment的生命周期先后调用的方法有:onAttach、onCreate、onCreateView、onViewCreated、onActivityCreated、onStart、onResume、onPause 、onStop、onDestroyView、onDestory、
onDetach。

下面我们依次来分析一下DialogFrament的这些方法。

常用域以及其初始化@DialogFrament.class

public static final int STYLE_NORMAL = 0;
public static final int STYLE_NO_TITLE = 1;
public static final int STYLE_NO_FRAME = 2;
public static final int STYLE_NO_INPUT = 3;

int mStyle = STYLE_NORMAL;
int mTheme = 0;
boolean mCancelable = true;
boolean mShowsDialog = true;
int mBackStackId = -1;

Dialog mDialog;   //Dialog显示的关键
boolean mViewDestroyed;
boolean mDismissed;
boolean mShownByMe;

onAttach方法执行之前正常情况下会先执行DialogFragment的show方法,而该方法会执行如下了内容:mDismissed = false; mShownByMe = true;

onAttach()@DialogFrament.class

@Override
 public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (!mShownByMe) { //正常情况不会跳转到这里
            mDismissed = false;
        }
 }

onCreate()@DialogFrament.class

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

       mShowsDialog = mContainerId == 0; //note1
        if (savedInstanceState != null) { //恢复之前的设置,第一次创建将不会进入到这里
            mStyle = savedInstanceState.getInt(SAVED_STYLE, STYLE_NORMAL);
            mTheme = savedInstanceState.getInt(SAVED_THEME, 0);
            mCancelable = savedInstanceState.getBoolean(SAVED_CANCELABLE, true);
            mShowsDialog = savedInstanceState.getBoolean(SAVED_SHOWS_DIALOG, mShowsDialog);
            mBackStackId = savedInstanceState.getInt(SAVED_BACK_STACK_ID, -1);
        }

}

1、正常情况这里mShowsDialog为真,mContainerId属性来自于Fragment值为0

往下就要分析onCreateView方法,但是根据博客http://blog.csdn.net/evan_man/article/details/51329320的分析,在onCreateView方法的第一个参数(LayoutInflater
inflater)通过调用Fragment的getLayoutInflater()方法获得,因此执行顺序是先getLayoutInflater()之后再onCreateView方法。DialogFragment重写了Fragment的getLayoutInflater()方法没有重写onCreateView方法。

getLayoutInflater()@DialogFrament.class

public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
        if (!mShowsDialog) { //根据前面的分析正常情况下mShowsDialog为真
            return super.getLayoutInflater(savedInstanceState);
        }

        mDialog = onCreateDialog(savedInstanceState); //note1
        if (mDialog != null) {
            setupDialog(mDialog, mStyle); //note2
            return (LayoutInflater) mDialog.getContext().getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE); //返回所属dialog的LayoutInflate对象,用于解析onCreateView中的xml布局文件
        }

        return (LayoutInflater) mHost.getContext().getSystemService(
                Context.LAYOUT_INFLATER_SERVICE); //返回所属context的LayoutInflate对象,用于解析onCreateView中的xml布局文件
}

1、调用onCreateDialog方法创建一个特定的Dialog对象

@NonNull

public Dialog onCreateDialog(Bundle savedInstanceState) {

return new Dialog(getActivity(), getTheme()); //参数分别为当前DialogFragment所属Context、以及自身属性int mTheme = 0;

}

创建了一个android.app.Dialog对象

2、调用setupDialog方法,针对不同的style 对dialog进行相关的设置,默认style是normal,这里不进行特别处理。

public void setupDialog(Dialog dialog, int style) {

switch (style) {

case STYLE_NO_INPUT:

dialog.getWindow().addFlags(

WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |

WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

case STYLE_NO_FRAME:

case STYLE_NO_TITLE:

dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);

}

}

往下分析onViewCreated,但是DialogFragment没有重写该方法,因此分析onActivityCreated方法。这里补充一下Fragment的onActivityCreated和onStart方法会在Activity的onStart方法中被先后调用。

onActivityCreated()@DialogFragment.class

public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        if (!mShowsDialog) {
            return;
        }

        View view = getView(); //onCreateView创建出来的view
        if (view != null) {
            if (view.getParent() != null) {
                throw new IllegalStateException("DialogFragment can not be attached to a container view");
            }
            mDialog.setContentView(view); //将view交给dialog显示
        }
        mDialog.setOwnerActivity(getActivity());
        mDialog.setCancelable(mCancelable);
        mDialog.setOnCancelListener(this);
        mDialog.setOnDismissListener(this);
        if (savedInstanceState != null) { //同样的初次启动不会进入到这里的代码
            Bundle dialogState = savedInstanceState.getBundle(SAVED_DIALOG_STATE_TAG);
            if (dialogState != null) {
                mDialog.onRestoreInstanceState(dialogState);
            }
        }
}

这个方法的功能也就是对前面getLayoutInflater方法中创建的dialog进行设置、将onCreateView方法创建的View进行绑定、设置监听器等。

onActivityCreated方法执行完成后接着就是执行DialogFragment的onStart方法

onStart()@DialogFragment.class

@Override
public void onStart() {
        super.onStart();
        if (mDialog != null) {
            mViewDestroyed = false;
            mDialog.show(); //note1
        }
}

1、调用dialog的show方法进行视图真正的显示

DialogFramet没有重写Fragment的onResume方法,因此对于一个Dialog的显示就到此为止。相应的DialogFragment重写的Fragment的onStop、onDestroyView、 onDetach方法具体代码如下

onStop()@DialogFragment.class

@Override
public void onStop() {
        super.onStop();
        if (mDialog != null) {
            mDialog.hide();
        }
 }

onDestroyView()@DialogFragment.class

@Override
public void onDestroyView() {
        super.onDestroyView();
        if (mDialog != null) {
            mViewDestroyed = true;
            mDialog.dismiss();
            mDialog = null;
        }
 }

onDetach()@DialogFragment.class

@Override
public void onDetach() {
        super.onDetach();
        if (!mShownByMe && !mDismissed) {
            mDismissed = true;
        }
}

上面代码很简单就不具体介绍了,通过前面的分析大体得出如下结论DialogFragment,之所以继承自Fragment而不是直接使用Dialog目的在于使用FragmentManager管理其生命周期。FragmentManager只是对Dialog的生命周期进行管理,而具体的视图显示工作还是交给android.app.Dialog进行处理,如调用Dialog的show、hide、dismiss方法对对话框进行显示、隐藏、销毁

下面我们探究一下Dialog是如何显示到屏幕上的,回顾前面用到的方法,大体有如下几个:

//创建Dialog

mDialog = new Dialog(getActivity(), getTheme());  //第二个参数正常情况为0

  • mDialog.setContentView(view);
  • mDialog.setOwnerActivity(getActivity());
  • mDialog.setCancelable(mCancelable);
  • mDialog.setOnCancelListener(this);
  • mDialog.setOnDismissListener(this);

//显示、隐藏和销毁Dialog

mDialog.show();

mDialog.hide();

mDialog.dismiss();

根据这几个方法我们来分析一下Dialog的显示原理

Dialog.class

(android.app.Dialog)

final Context mContext;
final WindowManager mWindowManager;
Window mWindow;
private Handler mListenersHandler;

Dialog()@Dialog.class

public Dialog(@NonNull Context context, @StyleRes int themeResId) {
        this(context, themeResId, true);
}
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (themeResId == 0) { //通过DialogFragment创建的一般都是这种情况
                final TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true); //从context的主题中获取到dialogTheme属性
                themeResId = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, themeResId); //利用初始化mContext带主题
        } else {
            mContext = context;
        }

        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); //负责窗口管理服务

        final Window w = new PhoneWindow(mContext); //创建PhoneWindow,用于具体显示
        mWindow = w;
        w.setCallback(this); //dialog实现了Window.Callback接口,里面定义了如dispatchKeyEvent等处理用户点击事件的操作
        w.setOnWindowDismissedCallback(this);  //处理窗口销毁时的接口
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);

        mListenersHandler = new ListenersHandler(this);
}

构造器主要完成功能就是获得context的WindowManager引用;创建一个PhoneWindow,并对其进行一定初始化操作。

setContentView()@Dialog.class

public void setContentView(View view) {
        mWindow.setContentView(view); //调用PhoneWindow的同名方法
}

setOwnerActivity()@Dialog.class

private Activity mOwnerActivity;
public final void setOwnerActivity(Activity activity) {
        mOwnerActivity = activity;
        mWindow.setVolumeControlStream(mOwnerActivity.getVolumeControlStream());
 }

setCancelable()@Dialog.class

protected boolean mCancelable = true;
public void setCancelable(boolean flag) {
        mCancelable = flag;
}

setOnCancelListener()@Dialog.class

private String mCancelAndDismissTaken;
private Message mCancelMessage; //用于存储一个取消Message,在Dialog销毁时将该Message交给Handler处理
public void setOnCancelListener(final OnCancelListener listener) {
        if (mCancelAndDismissTaken != null) {
            throw new IllegalStateException(
                    "OnCancelListener is already taken by "
                    + mCancelAndDismissTaken + " and can not be replaced.");
        }
        if (listener != null) {
            mCancelMessage = mListenersHandler.obtainMessage(CANCEL, listener);
        } else {
            mCancelMessage = null;
        }
  }

setOnDismissListener()@Dialog.class

private Message mDismissMessage;
public void setOnDismissListener(final OnDismissListener listener) {
        if (mCancelAndDismissTaken != null) {
            throw new IllegalStateException(
                    "OnDismissListener is already taken by "
                    + mCancelAndDismissTaken + " and can not be replaced.");
        }
        if (listener != null) {
            mDismissMessage = mListenersHandler.obtainMessage(DISMISS, listener);
        } else {
            mDismissMessage = null;
        }
}

与前面的setOnCancelListener()方法类似,也是包装成一个Message后期交给handler去处理。

show()@Dialog.class

private boolean mShowing = false;
private boolean mCreated = false;
View mDecor;
public void show() {
        if (mShowing) { //第一次调用不会进入到这里
            if (mDecor != null) {
                if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                    mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                }
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }
        mCanceled = false;

        if (!mCreated) { //第一次调用会执行下面的代码
            dispatchOnCreate(null); //note1
        }
        onStart(); //note2
        mDecor = mWindow.getDecorView(); //从PhoneWindows中获取DecorView
        if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { //ActionBar为null,同时当前PhoneWindow拥有标题栏
            final ApplicationInfo info = mContext.getApplicationInfo();
            mWindow.setDefaultIcon(info.icon);
            mWindow.setDefaultLogo(info.logo);
            mActionBar = new WindowDecorActionBar(this);
        }

        WindowManager.LayoutParams l = mWindow.getAttributes();
        if ((l.softInputMode
                & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
            WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
            nl.copyFrom(l);
            nl.softInputMode |=
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            l = nl;
        }
        try {
            mWindowManager.addView(mDecor, l); //note3
            mShowing = true;

            sendShowMessage(); //note4
        } finally {
        }
    }

1、进行一些初始化操作,但是Dialog并没有在里面进行任何操作除了将mCreatd属性设置为true

void dispatchOnCreate(Bundle savedInstanceState) {

if (!mCreated) {

onCreate(savedInstanceState);

mCreated = true;

}

}

protected void onCreate(Bundle savedInstanceState) { }

2、该start方法对AcitonBar设置隐藏动画使能

protected void onStart() {

if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);

}

3、将得到的DecorView添加到WindowManger进行显示。

4、将showMessage发送给Handler去处理,showMessage是在setOnShowListener(OnShowListener listener)时传入的,用于监听窗口显示时的动作,与OnDismissListener和onCancelListener类似。如果没有设置该监听器那么下面的方法就不会其任何作用。

private void sendShowMessage() {

if (mShowMessage != null) {

Message.obtain(mShowMessage).sendToTarget();

}

}

hide()@Dialog.class

public void hide() {
        if (mDecor != null) {
            mDecor.setVisibility(View.GONE);
        }
}

dismiss()@Dialog.class

@Override
public void dismiss() {
        if (Looper.myLooper() == mHandler.getLooper()) {
            dismissDialog();
        } else {
            mHandler.post(mDismissAction); //如果不是UI线程则将dismiss交给handler去处理
        }
}
dismissDialog()@Dialog.class
void dismissDialog() {
        if (mDecor == null || !mShowing) {
            return;
        }
        if (mWindow.isDestroyed()) {
            Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!");
            return;
        }
        try {
            mWindowManager.removeViewImmediate(mDecor); //从WindowManager中remove DecorView
        } finally {
            if (mActionMode != null) {
                mActionMode.finish(); .//销毁ActionBar
            }
            mDecor = null;
            mWindow.closeAllPanels();
            onStop();
            mShowing = false;
            sendDismissMessage(); //触发dismiss监听器
        }
}

综上我们对Dialog的分析可以知道,首先根据Context和Theme得到一个新的Context,随后根据Context得到一个WindowManager,并根据context创建一个PhoneWindow,随后通过PhoneWindow.setContentView(view)将自定义的View传给PhoneWindow。show方法中则从PhoneWindow中获得一个DecorView(DecorView是PhoneView的内部类),最后将该DecoreView添加到WindowManager中。hide方法最为简单就是调用mDecor.setVisibility(View.GONE),设置view为不可见状态。而dismiss就是类似show的逆过程,将DecorView从WindowManager中移除出去。

补充:如果以前有对Android系统底层有过分析的话可以知道这里的过程与Activity中创建View的过程类似,也是先后创建PhoneWindow和DecorWindow,最后通过WindowManager.addView方法将DecorView交给WindowManagerService进行显示。Activity的setContentView方法如下

[email protected]

public void setContentView(@LayoutRes int layoutResID) {

mWindow.setContentView(layoutResID);

initWindowDecorActionBar(); //对ActionBar进行一些初始化

}

private Window mWindow = new PhoneWindow(this);

可以发现跟这里的流程基本都是一样的,OnCreate中创建PhoneWindow然后得到Decorview,最后在onResume方法中将Decorview交给WindowManager去处理,其实最终是交给WindowManagerService进行管理,后者负责显示视图和传递用户的事件。

到此为止我们沿着DialogFragment->Dialog->PhoneWindow DecoreView WindowManager的轨迹分析了DialogFragment的显示流程。最后如果对PhoneWindow如何显示感兴趣,那就需要查看com.android.internal.policy.impl.PhoneWindow的setContentView以及getDecorView两个方法,以及android.view.WindowManager的addView方法进行探究。这部分内容留待后面有机会再来分析。

时间: 2024-10-12 21:04:51

DialogFragment的使用与底层绘制的相关文章

NGUI所见即所得之深入剖析UIPanel,UIWidget,UIDrawCall底层原理

NGUI所见即所得之深入剖析UIPanel,UIWidget,UIDrawCall底层原理 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 之前项目中用的NGUI的版本是3.0.7 f3,开始的时候感觉没有什么问题,直达最近项目UI的完成度比较高时,就突然出现掉帧很严重的现象,即使只有一个UI打开(其他都是active = false的情况下),打开profier,发现UIPanel LateUpdate 竟然占了CPU使用率的50%左右

浅谈混合开发与Android,JS数据交互

本文是作者原创,如转载请注明出处! 一.概论 现在时代已经走过了移动互联网的超级火爆阶段,市场上移动开发人员已经趋于饱和,显然,只会原生APP的开发已不能满足市场的需求,随着H5的兴起与火爆,H5在原生APP中的使用越来越广泛,也就是我们常说的混合开发(Hybrid APP).最新很火的微信小程序相信大家都是知道的,实际上微信小程序加载的界面就是一个HTML5的界面,HTML5界面在一些电商类的APP中主要承担展示数据的作用,但是他的作用并不仅限于此,最起码js调用原生方法和原生调用js的方法是

聊聊移动端跨平台开发的各种技术

介绍 最近出现的 React Native 再次让跨平台移动端开发这个话题火起来了,曾经大家以为在手机上可以像桌面那样通过 Web 技术来实现跨平台开发,却大多因为性能或功能问题而放弃,不得不针对不同平台开发多个版本. 但这并没有阻止人们对跨平台开发技术的探索,毕竟谁不想降低开发成本,一次编写就处处运行呢?除了 React Native,这几年还出现过许多其它解决方案,本文我将会对这些方案进行技术分析,供感兴趣的读者参考. 为了方便讨论,我将它们分为了以下 4 大流派: Web 流:也被称为 H

关于Android中为什么主线程不会因为Looper.loop()里的死循环卡死?引发的思考,事实可能不是一个 epoll 那么 简单。

( 转载请务必标明出处:http://www.cnblogs.com/linguanh/, 本文出自:[林冠宏(指尖下的幽灵)的博客]) 前序 本文将会把一下三个问题阐述清楚以及一个网上的普遍观点的补充: 1,安卓 APP 启动过程,对于Activity 的 onCreate 等生命周期的函数为什么不会因为 Looper.loop()里的死循环卡死而永无机会执行. 2,在 1 的基础上,View 的绘制到底是怎样完成的,它又为什么不会因为 Looper.loop()里的死循环卡死而永无机会刷新.

Android 浮窗开发之窗口层级

很多人都知道如何去实现一个简单的浮窗,但是却很少有人去深入的研究背后的流程机制,由于项目中浮窗交互比较复杂,遇到了些坑查看了很多资料,故总结浮窗涉及到的知识点: 窗口层级关系(浮窗是如何"浮"的)? 浮窗有哪些限制,如何越过用户授权实现浮窗功能? 窗口与用户输入系统(Activity是如何接收到touch事件?). 本章我们来研究第一个问题:浮窗为何会浮. 浮窗之所以叫浮窗,是因为它能悬浮于应用或者桌面窗口之上,能脱离Activity而存在.为了研究其中区别,我们先来看看我们最熟悉的A

HT图形组件设计之道(二)

上一篇我们自定义CPU和内存的展示界面效果,这篇我们将继续采用HT完成一个新任务:实现一个能进行展开和合并切换动作的刀闸控件.对于电力SCADA和工业控制等领域的人机交互界面常需要预定义一堆的行业标准控件,以便用户能做可视化编辑器里,通过拖拽方式快速搭建具体电力网络或工控环境的场景,并设置好设备对应后台编号等参数信息,将拓扑图形与图元信息一并保存到后台,实际运行环境中将打开编辑好的网络拓扑图信息,连接后台实时数据库,接下来就是接受实时数据库发送过来的采集信息进行界面实时动态刷新,包括用户通过客户

聊聊移动端跨平台开发的几种流派

最近出现的 React Native 再次让跨平台移动端开发这个话题火起来了,曾经大家以为在手机上可以像桌面那样通过 Web 技术来实现跨平台开发,却大多因为性能或功能问题而放弃,不得不针对不同平台开发多个版本. 但这并没有阻止人们对跨平台开发技术的探索,毕竟谁不想降低开发成本,一次编写就处处运行呢?除了 React Native,这几年还出现过许多其它解决方案,本文我将会对这些方案进行技术分析,供感兴趣的读者参考. 为了方便讨论,我将它们分为了以下 4 大流派: Web 流:也被称为 Hybr

第1部分: 游戏引擎介绍, 渲染和构造3D世界

原文作者:Jake Simpson译者: 向海Email:[email protected] ------------------------------------------------------------第1部分: 游戏引擎介绍, 渲染和构造3D世界 介绍 自Doom游戏时代以来我们已经走了很远. DOOM不只是一款伟大的游戏,它同时也开创了一种新的游戏编程模式: 游戏 "引擎". 这种模块化,可伸缩和扩展的设计观念可以让游戏玩家和程序设计者深入到游戏核心,用新的模型,场景和

【Xamarin挖墙脚系列:使用Xamarin进行Hybrid应用开发】

官方地址:https://developer.xamarin.com/guides/cross-platform/advanced/razor_html_templates/ 使用Xamarin进行网页形式的本地APP开发,感觉有点不爽,不过为前端开发人员提供了开发APP的入口. 呈现引擎支持HTML  和ASP.NET MVC3的Razor引擎! Razor引擎是个好同志! 不过,创建Hybrid应用的框架不仅仅是Xamarin.大名鼎鼎的Phonegape的   Apache Cordova