android中api简介
1:DisplayMetrics Display 获取屏幕的基本信息
DisplayMetrics displayMetrics=new DisplayMetrics(); Display display=getWindowManager().getDefaultDisplay(); display.getMetrics(displayMetrics);Log.d(TAG, "onClick: densityDpi=="+displayMetrics.densityDpi+"--density=="+displayMetrics.density+"--heightPixels=="+displayMetrics.heightPixels+"--widthPixels=="+displayMetrics.widthPixels+"--xdpi=="+displayMetrics.xdpi+"-ydpi=="+displayMetrics.ydpi+"--=="+displayMetrics.scaledDensity);
2:keyEvent
//对应的键值,KeyEvent.KEYCODE_DPAD_LEFT;
keyEvent.getKeyCode(); //对应那种操作 按下或者抬起 KeyEvent.ACTION_DOWN;
keyEvent.getAction(); //获取按键事件触发的次数keyEvent.getRepeatCount(); //不准确 keyEvent.isLongPress();长按事件执行的流程:
长按事件执行顺序为先执行down事件getrepeatcount一直增加(判断是否为长按事件,只需要判断getrepeatcount是否大于零)
直到最后按键起来事件变为up事件getrepeatcount为0
activity里面dispatchKeyEvent相关逻辑,
event.dispatch(this, decor != null ? decor.getKeyDispatcherState() : null, this);这个时候我们将activity自身
class Activity extends ContextThemeWrapperimplements KeyEvent.Callback, activity自身实现了keyevent的callback回调接口 所以 在activity里面可以得到这些回调方法
public boolean dispatchKeyEvent(KeyEvent event) {
onUserInteraction();// Let action bars open menus in response to the menu key prioritized over // the window handling it if (event.getKeyCode() == KeyEvent.KEYCODE_MENU &&mActionBar != null && mActionBar.onMenuKeyEvent(event)) {return true;}Window win = getWindow();if (win.superDispatchKeyEvent(event)) {return true;}View decor = mDecor;if (decor == null) decor = win.getDecorView();return event.dispatch(this, decor != null ? decor.getKeyDispatcherState() : null, this); }
view同样如此:view除了可以回调实现的值按键信息,还可以通过主动监听的方式实现及
but.setOnKeyListener(new View.OnKeyListener() {@Override public boolean onKey(View v, int keyCode, KeyEvent event) {return false;} });
3:LayoutInflater.Factory
实现换肤效果:主题切换
http://blog.csdn.net/llew2011/article/details/51287391
4:SurfaceHolder 是一个接口
SurfaceHolder.Callback
surfaceview
TextureView
GLSurfaceView
SurfaceTexture
5: ViewTreeObserver
视图树滚动等发生改变时,ViewTreeObserver都会收到通知,ViewTreeObserver不能被实例化,可以调用
View.getViewTreeObserver()来获得。
通过ViewTreeObserver .addOnPreDrawListener来获得宽高,在执行onDraw之前已经执行了
onLayout()和onMeasure(),可以得到宽高了,当获得正确的宽高后,请移除这个观察者,
否则回调会多次执行
//获得ViewTreeObserver
ViewTreeObserver observer=view.getViewTreeObserver();
//注册观察者,监听变化
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override public boolean onPreDraw()
{
if(observer.isAlive()){ observer.removeOnDrawListener(this);
}
//获得宽高
int viewWidth=view.getMeasuredWidth();
int viewHeight=view.getMeasuredHeight();
return true; } });
6:Context获取各种系统服务:
public abstract Object getSystemService(@ServiceName @NonNull String name);
WINDOW_SERVICE = "window";
windowManager= (WindowManager) getSystemService(Context.WINDOW_SERVICE);
7: Window PhoneWindow https://www.jianshu.com/p/9da7bfe18374 详细流程
DecorView是当前Activity所有View的祖先,它并不会向用户呈现任何东西,它主要有如下几个功能,可能不全:
- A. Dispatch ViewRoot分发来的key、touch、trackball等外部事件;
- B. DecorView有一个直接的子View,我们称之为System Layout,这个View是从系统的Layout.xml中解析出的,
- 它包含当前UI的风格,如是否带title、是否带process bar等。可以称这些属性为Window decorations。
- C. 作为PhoneWindow与ViewRoot之间的桥梁,ViewRoot通过DecorView设置窗口属性。
- //可以这样获取 View view = getWindow().getDecorView();
- DecorView只有一个子元素为LinearLayout。代表整个Window界面,包含通知栏,标题栏,内容显示栏三块区域。
- DecorView里面TitleView:标题,可以设置requestWindowFeature(Window.FEATURE_NO_TITLE)
- 取消掉ContentView:是一个id为content的FrameLayout。
- 我们平常在Activity使用的setContentView就是设置在这里,也就是在FrameLayout上
ViewGroup viewone= (ViewGroup) getWindow().getDecorView();Log.d(TAG, "onCreate: getChildCount=="+viewone.getChildCount());ViewGroup viewThree= (ViewGroup) viewone.getChildAt(0);if(viewThree instanceof LinearLayout){Log.d(TAG, "onCreate: LinearLayout");}Log.d(TAG, "onCreate: getChildCount=="+viewThree.getChildCount());ViewGroup viewfour= (ViewGroup) viewThree.getChildAt(1);if(viewfour instanceof FrameLayout){Log.d(TAG, "onCreate: FrameLayout");} // 就是我们setContentView使用的view View viewTwo= findViewById(android.R.id.content);if(viewTwo instanceof FrameLayout){Log.d(TAG, "onCreate: FrameLayout");}if(viewTwo.equals(viewfour)){Log.d(TAG, "onCreate: 同一个对象");}// D/MainActivity: onCreate: getChildCount==1 // /MainActivity: onCreate: LinearLayout // D/MainActivity: onCreate: getChildCount==2 // D/MainActivity: onCreate: FrameLayout // D/MainActivity: onCreate: FrameLayout // D/MainActivity: onCreate: 同一个对象
关键看Window的实现类PhoneWindow
setContentView源码简单介绍:
getWindow().setContentView(layoutResID);
installDecor();
创建decorview 获取我们设置的feature 就是为什么我们需要在setContentView之前
调用设置feature的api
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
启动一个Activity流程:
ViewManager接口:
add and remove child views to an Activity 也是一个系统manager 通过getSystemService()获取 addView UpdateViewLayout RemoveView
WindowManager:窗体管理器 实现了ViewManager接口
WindowManagerImpl:WindowManager实现类
Window窗体
ViewGroup也实现了ViewManager
而且Window也与WindowManager绑定。而mWindow,和mWindowManager则是Activity的成员变量。
可以看到这里WindiwManager的创建是context.getSystemService(Context.WINDOW_SERVICE)
在创建号Activity之后 会创建Window和WindowManager
mWindow = new PhoneWindow(this);
mWindow.setWindowManager( (WindowManager)context.getSystemService
(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
来创建Activity以及Activity所需要的Context,Window,调用了Activity的onCreate,onStart方法,
而接下来调用了handleResumeActivity方法
performResumeActivity则是让Activity调用onResume方法
r.window = r.activity.getWindow();
//赋值
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
//把当前的DecorView与WindowManager绑定一起 wm.addView(decor, l);
}
当前Activity的Window进而获取到DecorView,再获取当前Activity的WindowManager,将DecorView与WindowManager绑定一起。
详细流程图
WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
View通过ViewRootImpl来绘制
前面说到,ViewRootImpl调用到requestLayout()来完成View的绘制操作,我们看下源码
@Overridepublic void requestLayout() {if (!mHandlingLayoutInLayoutRequest) {checkThread();mLayoutRequested = true;scheduleTraversals();}}
View绘制,先判断当前线程
void checkThread() {if (mThread != Thread.currentThread()) {throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");}}
scheduleTraversals中会通过handler去异步调用mTraversalRunnable接口
final class TraversalRunnable implements Runnable {@Overridepublic void run() {doTraversal();}}
可以看到,最后真正调用绘制的是performTraversals()方法,这个方法很长核心便是
private void performTraversals() { ...... performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);...performLayout(lp, desiredWindowWidth, desiredWindowHeight);...... performDraw();}...... }
View与WindowManager联系
那么View和WindowManager之间是怎么通过ViewRootImpl联系的呢。
从第三篇文章中我们知道,WindowManager是继承于ViewManager接口的,而ViewManager提供了添加View,删除View,更新View的方法。就拿setContentView来说,当Activity的onCreate调用到了setContentView后,view就会被绘制了吗?肯定不是,setContentView只是把需要添加的View的结构添加保存在DecorView中。此时的DecorView还并没有被绘制(没有触发view.measure,layout,draw)。
DecorView真正的绘制显示是在activity.handleResumeActivity方法中DecorView被添加到WindowManager时候,也就是调用到windowManager.addView(decorView)。而在windowManager.addView方法中调用到windowManagerGlobal.addView,开始创建初始化ViewRootImpl,再调用到viewRootImpl.setView,最后是调用到viewRootImpl的performTraversals来进行view的绘制(measure,layout,draw),这个时候View才真正被绘制出来。
这也就是为什么我们在onCreate方法中调用view.getMeasureHeight() = 0的原因,我们知道activity.handleResumeActivity最后调用到的是activity的onResume方法,但是按上面所说在onResume方法中调用就可以得到了吗,答案肯定是否定的,因为ViewRootImpl绘制View并非是同步的,而是异步(Handler)。
难道就没有得监听了吗?相信大家以前获取使用的大多是
view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {// TODO Auto-generated method stub}
});
没错,的确是这个,为什么呢,因为在viewRootImpl的performTraversals的绘制最后,调用了
{if (triggerGlobalLayoutListener) {mAttachInfo.mRecomputeGlobalAttributes = false;mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();}...performDraw();
}
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView) findViewById(R.id.tv);new Thread(new Runnable() {@Overridepublic void run() {tv.setText("Hohohong Test");}}).start();}
我是在onCreate里面的子线程去更新UI的,那么会报错吗?测试后你就会知道不会报错,如果你放置个Button点击再去调用的话则会弹出报错。为什么会这样?
答案就是跟ViewRootImpl的初始化有关,因为在onCreate的时候此时View还没被绘制出来,ViewRootImpl还未创建出来,它的创建是在activity.handleResumeActivity的调用到windowManager.addView(decorView)时候,如前面说的ViewRootImpl才被创建起来
而这个AttachInfo则是View里面一个静态内部类,它的构造方法
AttachInfo(IWindowSession session, IWindow window, Display display,ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {mSession = session;mWindow = window;mWindowToken = window.asBinder();mDisplay = display;mViewRootImpl = viewRootImpl;mHandler = handler;mRootCallbacks = effectPlayer;}
可以看到viewRootImpl在它的构造方法里赋值了,那么这个方法肯定是在ViewRootImpl创建时创建的,而ViewRootImpl的创建是在调用WindowManagerGlobal.addView的时候
root = new ViewRootImpl(view.getContext(), display);
而构造方法中
public ViewRootImpl(Context context, Display display) {mContext = context;mWindowSession = WindowManagerGlobal.getWindowSession();...mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);...}
可以看到View与ViewRootImpl绑定一起了。
之后就可以通过view.getViewRootImpl获取到,而在Window里面也可以获取到ViewRootImpl,因为Window里面有DecorView(这里说的Window都是讲它的实现类PhoneWindo),前三篇已经介绍过了,通过DecorView来获取到ViewRootImpl
private ViewRootImpl getViewRootImpl() {if (mDecor != null) {ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();if (viewRootImpl != null) {return viewRootImpl;}}throw new IllegalStateException("view not added");}
另外,一个View会对应一个ViewRootImpl吗?我们做个测试,在一个布局中打印两个不同控件的ViewRootImpl的内存地址
小结
- 之所以说ViewRoot是View和WindowManager的桥梁,是因为在真正操控绘制View的是ViewRootImpl,View通过WindowManager来转接调用ViewRootImpl
- 在ViewRootImpl未初始化创建的时候是可以进行子线程更新UI的,而它创建是在activity.handleResumeActivity方法调用,即DecorView被添加到WindowManager的时候
- ViewRootImpl绘制View的时候会先检查当前线程是否是主线程,是才能继续绘制下去
10:
ViewGroup.LayoutParams
最基本的布局类, 只能设置组件的宽和高。
ViewGroup.LayoutParams lp=new ViewGroup.LayoutParams(0,0); lp.width; lp.height;
MarginLayoutParams extends ViewGroup.LayoutParams
MarginLayotuParams 布局参数可以设置边距。
ViewGroup.MarginLayoutParams lp=new ViewGroup.MarginLayoutParams(0,0); lp.rightMargin; lp.bottomMargin; lp.height; lp.width; lp.setMargins(); lp.leftMargin;
class LayoutParams extends ViewGroup.MarginLayoutParams
RelativeLayout.LayoutParams 是继承于MarginLayoutParams
android中api简介相关推荐
- 【Android】 Android中适配器简介
1. BaseAdapter的使用实例 BaseAdapter baseAdapter = new BaseAdapter() {@Overridepublic View getView(int po ...
- Android中Context简介(通俗易懂)
Context字面意思是上下文,位于framework package的android.content.Context中,其实该类为LONG型,类似Win32中的Handle句柄.很多方法需要通过 C ...
- Android中Context简介
Context字面意思是上下文,位于framework package的android.content.Context中,其实该类为LONG型,类似Win32中的Handle句柄.很多方法需要通过 C ...
- Android中GPS简介及其应用
随时随地技术实战干货,获取项目源码.学习资料,请关注源代码社区公众号(ydmsq666) GPS是Global Positioning System(全球定位系统)的简称,它的作用就是为全球的物体提供 ...
- Android高级开发第二讲--Android中API翻译之Activity
博客出自:刘兆贤的博客_CSDN博客-Java高级,Android旅行,Android基础领域博主,转载注明出处! All Rights Reserved ! Activity主要用来展示给用户,让用 ...
- [android] 多媒体播放api简介
界面布局,水平方向四个按钮平均分布,使用权重,定义android:layout_width="0dp",定义layout_weight="1"这个属性全都一致就 ...
- 从源码角度解析Android中APK安装过程
从源码角度解析Android中APK的安装过程 1. Android中APK简介 Android应用Apk的安装有如下四种方式: 1.1 系统应用安装 没有安装界面,在开机时自动完成 1.2 网络下载 ...
- android 序列化存储对象,android中对象序列化存储
项目中要存储一些数据为了提高不必要的网络请求,提高效率,用到数据持久化的知识点,针对这个问题,解决办法其实有很多,以前在项目中是服务获取到webservice的xml,然后直接将xml保存在本地,之后 ...
- Android中基于心知天气API获取天气信息
Android中基于心知天气获取天气信息 JSON JSON简介 JSON对象 JSON数组 JSON解析 Android中获取天气 获取天气的流程 获取心知天气的API key 获取心知天气的API ...
最新文章
- curl模拟多线程抓取网页(优化)
- Java之String类
- Centos 安装 NodeJS
- python3 的 zip
- 初试牛刀---css中的小细节
- python练习之析构函数
- 设置在VS2005的IDE中迅速打开xaml文件
- 前端学习(2955):项目中组件的全局注册
- python常用正则表达式_Python3常用正则表达式
- 后端工程师的「跨域」之旅
- 中fifo算法_java线程池,工作窃取算法
- tomcat遇到jre\lib\ext\localedata.pack 时出错
- 图像去雾算法(一)相关研究及链接
- CPython中多线程的限制
- 2022年高压电工操作证考试题库及在线模拟考试
- PX4从放弃到精通(一):开源飞控PX4简介+系列文章大纲
- .Net学习平台有很多,最快捷的是在这里?
- JavaScript数组filter方法
- 生命科学计算机科学结合,生命科学与计算机科学的结合发展研究.docx
- 南京考公上岸经验分享