android2.3 View视图框架源码分析之一:android是如何创建一个view的?

View是所有控件的一个基类,无论是布局(Layout),还是控件(Widget)都是继承自View类。只不过layout是一个特殊的view,它里面创建一个view的数组可以包含其他的view而已。 
这一篇文章把所有的layout和widget都统称为view,那么android是如何创建一个view的呢?

一。在代码中直接new出来。 
比如说你要创建一个TextView的实例,那么你可以这样写:

Java代码  

  1. TextView text = new TextView(c);  //c为context对象,表明textview是在此对象中运行的。


二。把控件写在xml文件中然后通过LayoutInflater初始化一个view。
 
注意:下面的内容不是顺序的看的而是交替的看的。否则可能弄迷糊。 
可以通过

Java代码  

  1. //通过系统提供的实例获得一个LayoutInflater对象
  2. LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  3. //第一个参数为xml文件中view的id,第二个参数为此view的父组件,可以为null,android会自动寻找它是否拥有父组件
  4. View view = inflater.inflate(R.layout.resourceid, null);

这样也得到了一个view的实例,让我们一步一步来看,这个view是怎么new出来的。 
看类android.view.LayoutInflater

Java代码  

  1. public View inflate(int resource, ViewGroup root) {
  2. return inflate(resource, root, root != null);
  3. }
  4. public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
  5. /*可以看到通过resource id返回了一个XmlResourceParser,通过类名就可以猜测
  6. 这是一个xml的解析类。但点进去一看,发现它只是一个接口,它继承自 XmlPullParser用于pull方式解析xml的接口。和AttributeSet用于获取此view的所有属性。
  7. 那么需要能找到它的实现类。先看下面resource类。
  8. */
  9. XmlResourceParser parser = getContext().getResources().getLayout(resource);
  10. try {
  11. return inflate(parser, root, attachToRoot);
  12. } finally {
  13. parser.close();
  14. }
  15. }
  16. /**
  17. * 终于到了重点,获取一个这个View的实例
  18. */
  19. public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
  20. synchronized (mConstructorArgs) {
  21. /**
  22. * 获取一个实现此AttributeSet的实例。因为此XmlPullParser是继承自AttributeSet
  23. * 的,所以parser对象可以直接作为一个AttributeSet对象。也可以用组合的方式
  24. * 把parser传递给另外一个实现自AttributeSet的对象,来获取一个AttributeSet实例。
  25. **/
  26. final AttributeSet attrs = Xml.asAttributeSet(parser);
  27. mConstructorArgs[0] = mContext;      //构造函数的参数,第一个值是此view运行所在的对象context
  28. View result = root;
  29. try {
  30. // parser同时也继承了xmlPullParser,所以可以用pull解析来获取此view的根节点
  31. int type;
  32. while ((type = parser.next()) != XmlPullParser.START_TAG &&
  33. type != XmlPullParser.END_DOCUMENT) {
  34. // Empty
  35. }
  36. if (type != XmlPullParser.START_TAG) {
  37. throw new InflateException(parser.getPositionDescription()
  38. + ": No start tag found!");
  39. }
  40. //获得根节点标签的名字
  41. final String name = parser.getName();
  42. //如果它的根节点是一个merge对象,则必须手动设置此view的父节点,否则抛出异常
  43. //因为由merge创建的xml文件,常常被其他layout所包含
  44. if (TAG_MERGE.equals(name)) {
  45. if (root == null || !attachToRoot) {
  46. throw new InflateException("<merge /> can be used only with a valid "
  47. + "ViewGroup root and attachToRoot=true");
  48. }
  49. rInflate(parser, root, attrs);
  50. } else {
  51. // 此inflate的xml文件中的root view。即我们通过inflate返回得到的view
  52. View temp = createViewFromTag(name, attrs);
  53. ViewGroup.LayoutParams params = null;
  54. if (root != null) {
  55. // Create layout params that match root, if supplied
  56. params = root.generateLayoutParams(attrs);
  57. if (!attachToRoot) {
  58. // Set the layout params for temp if we are not
  59. // attaching. (If we are, we use addView, below)
  60. temp.setLayoutParams(params);
  61. }
  62. }
  63. // 加载temp下所有的子view
  64. rInflate(parser, temp, attrs);
  65. //如果给出了root,则把此view添加到root中去
  66. if (root != null && attachToRoot) {
  67. root.addView(temp, params);
  68. }
  69. // Decide whether to return the root that was passed in or the
  70. // top view found in xml.
  71. if (root == null || !attachToRoot) {
  72. result = temp;
  73. }
  74. }
  75. } catch (XmlPullParserException e) {
  76. InflateException ex = new InflateException(e.getMessage());
  77. ex.initCause(e);
  78. throw ex;
  79. } catch (IOException e) {
  80. InflateException ex = new InflateException(
  81. parser.getPositionDescription()
  82. + ": " + e.getMessage());
  83. ex.initCause(e);
  84. throw ex;
  85. }
  86. return result;
  87. }
  88. }
  89. /**
  90. *
  91. * 有上至下递归的初始化所有子view和子view的子view。在此方法被调用完成后
  92. * 会调用此view的parent view的onFinishInflate方法。表明其子view全部加载完毕
  93. */
  94. private void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs)
  95. throws XmlPullParserException, IOException {
  96. final int depth = parser.getDepth();
  97. int type;
  98. while (((type = parser.next()) != XmlPullParser.END_TAG ||
  99. parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
  100. if (type != XmlPullParser.START_TAG) {
  101. continue;
  102. }
  103. final String name = parser.getName();
  104. if (TAG_REQUEST_FOCUS.equals(name)) {
  105. parseRequestFocus(parser, parent);
  106. } else if (TAG_INCLUDE.equals(name)) {
  107. if (parser.getDepth() == 0) {
  108. throw new InflateException("<include /> cannot be the root element");
  109. }
  110. parseInclude(parser, parent, attrs);
  111. } else if (TAG_MERGE.equals(name)) {
  112. throw new InflateException("<merge /> must be the root element");
  113. } else {         //看这里,创建view的方法。而且这里已经重新获得了它的
  114. final View view = createViewFromTag(name, attrs);
  115. final ViewGroup viewGroup = (ViewGroup) parent;
  116. final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
  117. rInflate(parser, view, attrs);
  118. viewGroup.addView(view, params);
  119. }
  120. }
  121. parent.onFinishInflate();
  122. }
  123. View createViewFromTag(String name, AttributeSet attrs) {
  124. if (name.equals("view")) {
  125. name = attrs.getAttributeValue(null, "class");
  126. }
  127. if (DEBUG) System.out.println("******** Creating view: " + name);
  128. try {
  129. View view = (mFactory == null) ? null : mFactory.onCreateView(name,
  130. mContext, attrs);
  131. if (view == null) {
  132. if (-1 == name.indexOf(‘.‘)) {       //这里只是为了判断xml文件中tag的属性是否加了包名
  133. view = onCreateView(name, attrs);
  134. } else {
  135. view = createView(name, null, attrs);
  136. }
  137. }
  138. if (DEBUG) System.out.println("Created view is: " + view);
  139. return view;
  140. } catch (InflateException e) {
  141. throw e;
  142. } catch (ClassNotFoundException e) {
  143. InflateException ie = new InflateException(attrs.getPositionDescription()
  144. + ": Error inflating class " + name);
  145. ie.initCause(e);
  146. throw ie;
  147. } catch (Exception e) {
  148. InflateException ie = new InflateException(attrs.getPositionDescription()
  149. + ": Error inflating class " + name);
  150. ie.initCause(e);
  151. throw ie;
  152. }
  153. }
  154. /**
  155. * 真正创建一个view的方法,
  156. * 此方法是用反射获取构造器来实例对象而不是直接new出来这是为了处于性能优化考虑,
  157. * 同一个类名的不同对象,可以直接得到缓存的构造器直接获取一个构造器对象实例。而不需要
  158. * 重复进行new操作。
  159. *
  160. * @param name 此View的全名
  161. * @param prefix 前缀,值为 "android.view."其实就是是否包含包名
  162. * @param attrs 此view的属性值,传递给此view的构造函数
  163. */
  164. public final View createView(String name, String prefix, AttributeSet attrs)
  165. throws ClassNotFoundException, InflateException {
  166. Constructor constructor = sConstructorMap.get(name); //缓存中是否已经有了一个构造函数
  167. Class clazz = null;
  168. try {
  169. if (constructor == null) {
  170. //通过类名获得一个class对象
  171. clazz = mContext.getClassLoader().loadClass(
  172. prefix != null ? (prefix + name) : name);
  173. if (mFilter != null && clazz != null) {
  174. boolean allowed = mFilter.onLoadClass(clazz);
  175. if (!allowed) {
  176. failNotAllowed(name, prefix, attrs);
  177. }
  178. }
  179. //通过参数类型获得一个构造器,参数列表为context,attrs
  180. constructor = clazz.getConstructor(mConstructorSignature);
  181. sConstructorMap.put(name, constructor);      //把此构造器缓存起来
  182. } else {
  183. // If we have a filter, apply it to cached constructor
  184. if (mFilter != null) {
  185. // Have we seen this name before?
  186. Boolean allowedState = mFilterMap.get(name);
  187. if (allowedState == null) {
  188. // New class -- remember whether it is allowed
  189. clazz = mContext.getClassLoader().loadClass(
  190. prefix != null ? (prefix + name) : name);
  191. boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
  192. mFilterMap.put(name, allowed);
  193. if (!allowed) {
  194. failNotAllowed(name, prefix, attrs);
  195. }
  196. } else if (allowedState.equals(Boolean.FALSE)) {
  197. failNotAllowed(name, prefix, attrs);
  198. }
  199. }
  200. }
  201. Object[] args = mConstructorArgs;
  202. args[1] = attrs;     //args[0]已经在前面初始好了。这里只要初始化args[1]
  203. return (View) constructor.newInstance(args);     //通过反射new出一个对象。。大功告成
  204. } catch (NoSuchMethodException e) {
  205. InflateException ie = new InflateException(attrs.getPositionDescription()
  206. + ": Error inflating class "
  207. + (prefix != null ? (prefix + name) : name));
  208. ie.initCause(e);
  209. throw ie;
  210. } catch (ClassNotFoundException e) {
  211. // If loadClass fails, we should propagate the exception.
  212. throw e;
  213. } catch (Exception e) {
  214. InflateException ie = new InflateException(attrs.getPositionDescription()
  215. + ": Error inflating class "
  216. + (clazz == null ? "<unknown>" : clazz.getName()));
  217. ie.initCause(e);
  218. throw ie;
  219. }
  220. }

在类android.content.res.Resources类中获取XmlResourceParser对象;

Java代码  

  1. public XmlResourceParser getLayout(int id) throws NotFoundException {
  2. return loadXmlResourceParser(id, "layout");
  3. }
  4. ackage*/ XmlResourceParser loadXmlResourceParser(int id, String type)
  5. throws NotFoundException {
  6. synchronized (mTmpValue) {
  7. /*TypedValue对象保存了一些有关resource 的数据值,比如说,对于一个view来说,在xml
  8. 文件中可以定义许多属性,TypedValue保存了其中一个属性的相关信息,包括此属性的值的类型
  9. type,是boolean还是color还是reference还是String,这些在attr.xml文件下都有定义。
  10. 它的值的字符串名称;一个属性有多个值时,它从xml文件中获取的值它的顺序data;如果此属性的值
  11. 的类型是一个reference则保存它的resource id的等等。
  12. */
  13. TypedValue value = mTmpValue;
  14. getValue(id, value, true);
  15. if (value.type == TypedValue.TYPE_STRING) {
  16. return loadXmlResourceParser(value.string.toString(), id,
  17. value.assetCookie, type);
  18. }
  19. throw new NotFoundException(
  20. "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
  21. + Integer.toHexString(value.type) + " is not valid");
  22. }
  23. }
  24. /**
  25. *  getValue方法,id表示要查找的控件的 id,outValue是一个对象,用于保存一些属性相关信息
  26. *  resolveRefs为true表明,当通过属性id找到xml文件中的标签时,比如是一个<Button  android:id="@+id/button"/>
  27. * 它的值是一个引用reference,则继续解析获得这个id的值。这里看AssetManager类的实现*/
  28. public void getValue(int id, TypedValue outValue, boolean resolveRefs)
  29. throws NotFoundException {
  30. boolean found = mAssets.getResourceValue(id, outValue, resolveRefs);
  31. if (found) {
  32. return;
  33. }
  34. throw new NotFoundException("Resource ID #0x"
  35. + Integer.toHexString(id));
  36. }
  37. /*package*/ XmlResourceParser loadXmlResourceParser(String file, int id,
  38. int assetCookie, String type) throws NotFoundException {
  39. if (id != 0) {
  40. try {
  41. //取缓存
  42. synchronized (mCachedXmlBlockIds) {
  43. // First see if this block is in our cache.
  44. final int num = mCachedXmlBlockIds.length;
  45. for (int i=0; i<num; i++) {
  46. if (mCachedXmlBlockIds[i] == id) {
  47. //System.out.println("**** REUSING XML BLOCK!  id="
  48. //                   + id + ", index=" + i);
  49. return mCachedXmlBlocks[i].newParser();
  50. }
  51. }
  52. //第一次加载时,会打开这个文件获取一个xml数据块对象。
  53. // 这里先看AssetManager类的实现
  54. XmlBlock block = mAssets.openXmlBlockAsset(
  55. assetCookie, file);
  56. //下面会把此xmlBlock对象缓存起来,保存id和block,
  57. //以后如果是同样的id,直接在缓存中取XmlBlock。
  58. //这样就不用再在本地方法中打开文件创建解析树了。
  59. if (block != null) {
  60. int pos = mLastCachedXmlBlockIndex+1;
  61. if (pos >= num) pos = 0;
  62. mLastCachedXmlBlockIndex = pos;
  63. XmlBlock oldBlock = mCachedXmlBlocks[pos];
  64. if (oldBlock != null) {
  65. oldBlock.close();
  66. }
  67. mCachedXmlBlockIds[pos] = id;
  68. mCachedXmlBlocks[pos] = block;
  69. //返回的内部类继承了XmlResourceParser,在APi中此类是隐藏的
  70. return block.newParser();
  71. }
  72. }
  73. } catch (Exception e) {
  74. NotFoundException rnf = new NotFoundException(
  75. "File " + file + " from xml type " + type + " resource ID #0x"
  76. + Integer.toHexString(id));
  77. rnf.initCause(e);
  78. throw rnf;
  79. }
  80. }
  81. throw new NotFoundException(
  82. "File " + file + " from xml type " + type + " resource ID #0x"
  83. + Integer.toHexString(id));
  84. }

android.content.res.AssetManager类

Java代码  

  1. /*package*/ final boolean getResourceValue(int ident,
  2. TypedValue outValue,
  3. boolean resolveRefs)
  4. {
  5. int block = loadResourceValue(ident, outValue, resolveRefs);
  6. if (block >= 0) {
  7. if (outValue.type != TypedValue.TYPE_STRING) {
  8. return true;
  9. }
  10. //mStringBlocks通过本地方法保存所有布局文件的文件名
  11. outValue.string = mStringBlocks[block].get(outValue.data);
  12. return true;
  13. }
  14. return false;
  15. }
  16. //这是一个本地方法,是在本地方法中获取这个控件信息,返回通过此控件的id找到的文件名
  17. //的位置,由于个人对c++不是很了解,只初略的解释本地方法的一些功能。
  18. //对于的JNI文件位于:\frameworks\base\core\jni\android_util_AssetManager.cpp
  19. private native final int loadResourceValue(int ident, TypedValue outValue,
  20. boolean resolve);
  21. /**
  22. * 通过文件名,在本地方法中找到这个xml文件,并且在本地方法中生成一个xml解析对象。
  23. * 返回一个id,这个id对应java中的xmlBlock对象。这样xml文件就被load进了内存。
  24. * 也就是android所说的预编译,以后再访问只要直接去取数据即可
  25. */
  26. /*package*/ final XmlBlock openXmlBlockAsset(int cookie, String fileName)
  27. throws IOException {
  28. synchronized (this) {
  29. if (!mOpen) {
  30. throw new RuntimeException("Assetmanager has been closed");
  31. }
  32. int xmlBlock = openXmlAssetNative(cookie, fileName);
  33. if (xmlBlock != 0) {
  34. /*
  35. * 在XmlBlock对象中,终于到找了实现XmlResourceParser接口的类
  36. * Parser,它是XmlBlock的一个内部类。这里面可以获取所有xml文件中的内容。
  37. * 不管是属性还是Tag标签。这里xmlBlock是用来与本地类中的解析树对象对应的。
  38. * 所有的解析方法,其实都是调用的本地xml解析树中的方法。所以此类中有大量的
  39. * 本地方法。
  40. */
  41. XmlBlock res = new XmlBlock(this, xmlBlock);
  42. incRefsLocked(res.hashCode());
  43. return res;
  44. }
  45. }
  46. throw new FileNotFoundException("Asset XML file: " + fileName);
  47. }

三 。通过view.findViewById(resourceid)获得一个view的实例 
android.View.View类中

Java代码  

  1. //调用了通过id检索view的方法
  2. public final View findViewById(int id) {
  3. if (id < 0) {
  4. return null;
  5. }
  6. return findViewTraversal(id);
  7. }
  8. //不是吧,这不是坑爹吗?猜想肯定是被viewgroup重写了
  9. protected View findViewTraversal(int id) {
  10. if (id == mID) {
  11. return this;
  12. }
  13. return null;
  14. }

android.View.ViewGroup类中

Java代码  

  1. //哈哈,果然重写了此方法。其实就是在viewgroup包含的
  2. //子view数组中进行遍历。那么view是什么时候被加入进
  3. //viewgroup中的呢?如果是在代码中写,肯定是直接使用
  4. //addView方法把view加入viewGroup。如果写在xml布局文件
  5. //中,其实是在第二种方法中被加入view的。inflate加载父view
  6. //时会同时把其所有的子view加载完,同时addView到父view中
  7. protected View findViewTraversal(int id) {
  8. if (id == mID) {
  9. return this;
  10. }
  11. final View[] where = mChildren;
  12. final int len = mChildrenCount;
  13. for (int i = 0; i < len; i++) {
  14. View v = where[i];
  15. if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
  16. v = v.findViewById(id);
  17. if (v != null) {
  18. return v;
  19. }
  20. }
  21. }
  22. return null;
  23. }

四。通过activity的setContentView方法和findViewById获取一个view的实例。 
它是通过 
getWindow().setContentView(layoutResID);设置window对象的view 
再来看看window对象是在哪里获得到的,在类Activity中找到 
mWindow = PolicyManager.makeNewWindow(this); 
它是由PolicyManager生成的。 
找到com.android.internal.policy.PolicyManager,找到方法

Java代码  

  1. //window是由sPolicy对象创建的
  2. public static Window makeNewWindow(Context context) {
  3. return sPolicy.makeNewWindow(context);
  4. }
  5. //sPolicy对象是通过反射,获取的一个实例
  6. //此类的实现在com.android.internal.policy.impl.Policy中
  7. private static final String POLICY_IMPL_CLASS_NAME =
  8. "com.android.internal.policy.impl.Policy";
  9. private static final IPolicy sPolicy;
  10. static {
  11. // Pull in the actual implementation of the policy at run-time
  12. try {
  13. Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
  14. sPolicy = (IPolicy)policyClass.newInstance();
  15. } catch (ClassNotFoundException ex) {
  16. throw new RuntimeException(
  17. POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
  18. } catch (InstantiationException ex) {
  19. throw new RuntimeException(
  20. POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
  21. } catch (IllegalAccessException ex) {
  22. throw new RuntimeException(
  23. POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
  24. }
  25. }

找到com.android.internal.policy.impl.Policy类

Java代码  

  1. public PhoneWindow makeNewWindow(Context context) {
  2. return new PhoneWindow(context);
  3. }

它其实是一个phoneWindow对象,继承自window对象 
找到com.android.internal.policy.impl.phoneWindow 看它内部是如何把resourceid加载成一个view的

Java代码  

    1. private ViewGroup mContentParent;
    2. //这是window的顶层视图,它包含一些窗口的装饰,比图title bar,状态栏等等
    3. private DecorView mDecor;
    4. //这里的layoutResID也是由mLayoutInflater进行加载的,加载的方式与第二种方法一样。
    5. //只不过这里把的到的view变成了mContentParent的子view
    6. @Override
    7. public void setContentView(int layoutResID) {
    8. if (mContentParent == null) {
    9. installDecor();
    10. } else {
    11. mContentParent.removeAllViews();
    12. }
    13. mLayoutInflater.inflate(layoutResID, mContentParent);
    14. final Callback cb = getCallback();
    15. if (cb != null) {        //这是回调方法,表明mContentParent的子view已经发生改变
    16. cb.onContentChanged();
    17. }
    18. }
    19. //再来看看mContentParent究竟是何物,它肯定是一个viewGroup
    20. private void installDecor() {
    21. if (mDecor == null) {
    22. mDecor = generateDecor();
    23. mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
    24. mDecor.setIsRootNamespace(true);
    25. }
    26. if (mContentParent == null) {
    27. mContentParent = generateLayout(mDecor);
    28. mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
    29. if (mTitleView != null) {        //这里设置的是是否隐藏titleContainer,即头部titlebar
    30. if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
    31. View titleContainer = findViewById(com.android.internal.R.id.title_container);
    32. if (titleContainer != null) {
    33. titleContainer.setVisibility(View.GONE);
    34. } else {
    35. mTitleView.setVisibility(View.GONE);
    36. }
    37. if (mContentParent instanceof FrameLayout) {
    38. ((FrameLayout)mContentParent).setForeground(null);
    39. }
    40. } else {
    41. mTitleView.setText(mTitle);
    42. }
    43. }
    44. }
    45. }
    46. //当顶层view为null是,new了一个DecorView
    47. protected DecorView generateDecor() {
    48. return new DecorView(getContext(), -1);
    49. }
    50. //这里生成了mContentParent。
    51. protected ViewGroup generateLayout(DecorView decor) {
    52. mDecor.startChanging();
    53. //根据window的不同参数选择layoutResource
    54. View in = mLayoutInflater.inflate(layoutResource, null);
    55. decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    56. ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    57. if (contentParent == null) {
    58. throw new RuntimeException("Window couldn‘t find content container view");
    59. }
    60. return contentParent;
    61. }
    62. //顶层view是一个framelayout
    63. private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
    64. public DecorView(Context context, int featureId) {
    65. super(context);
    66. mFeatureId = featureId;
    67. }
    68. }
    69. //下面说明findVIewById
    70. //首先是获取顶层view,即继承自FrameLayout的viewgorup
    71. @Override
    72. public final View getDecorView() {
    73. if (mDecor == null) {
    74. installDecor();
    75. }
    76. return mDecor;
    77. }
    78. //然后mDecor.findViewById根据id获取它的子view
    79. //这里就是通过第三种方法获取它的子view
时间: 2024-07-28 15:29:00

android2.3 View视图框架源码分析之一:android是如何创建一个view的?的相关文章

android 网络框架 源码分析

android 网络框架 源码分析 导语: 最近想开发一个协议分析工具,来监控android app 所有的网络操作行为, 由于android 开发分为Java层,和Native层, 对于Native层我们只要对linux下所有网络I/O接口进行拦截即可,对于java 层,笔者对android 网络框架不是很了解,所以这个工具开发之前,笔者需要对android 的网络框架进行一个简单的分析. 分析结论: 1. android 的网络框架都是基于Socket类实现的 2. java 层Socket

YII框架源码分析(百度PHP大牛创作-原版-无广告无水印)

                        YII 框架源码分析             百度联盟事业部--黄银锋   目 录 1. 引言 3 1.1.Yii 简介 3 1.2.本文内容与结构 3 2.组件化与模块化 4 2.1.框架加载和运行流程 4 2.2.YiiBase 静态类 5 2.3.组件 6 2.4.模块 9 2.5 .App 应用   10 2.6 .WebApp 应用   11 3.系统组件 13 3.1.日志路由组件  13 3.2.Url 管理组件  15 3.3.异常

iOS常用框架源码分析

SDWebImage NSCache 类似可变字典,线程安全,使用可变字典自定义实现缓存时需要考虑加锁和释放锁 在内存不足时NSCache会自动释放存储的对象,不需要手动干预 NSCache的key不会被复制,所以key不需要实现NSCopying协议 第三方框架 网络 1.PPNetworkHelper 对AFNetworking 3.x 与YYCache的二次封装 简单易用,包含了缓存机制,控制台可以直接打印json中文字符 2..YTKNetwork 猿题库研发团队基于AFNetworki

携程DynamicAPK插件化框架源码分析

携程DynamicAPK插件化框架源码分析 Author:莫川 插件核心思想 1.aapt的改造 分别对不同的插件项目分配不同的packageId,然后对各个插件的资源进行编译,生成R文件,然后与宿主项目的R文件进行id的合并. 要求:由于最终会将所有的资源文件id进行合并,因此,所有的资源名称均不能相同. 2.运行ClassLoader加载各Bundle 和MultiDex的思路是一样的,所有的插件都被加载到同一个ClassLoader当中,因此,不同插件中的Class必须保持包名和类名的唯一

介绍开源的.net通信框架NetworkComms框架 源码分析

原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 售价249英镑 我曾经花了2千多购买过此通讯框架, 目前作者已经开源  许可是:Apache License v2 开源地址是:https://github.com/MarcFletcher/NetworkComms.Net 这个框架给我的感觉是,代码很优美,运行很稳定,我有一个项目使用此框架已经稳定运行1年多.这个框架能够

CodeIgniter框架——源码分析之入口文件index.php

CodeIgniter框架的入口文件主要是配置开发环境,定义目录常量,加载CI的核心类core/CodeIgniter.php. 源码分析如下: <?php //这个文件是入口,后期所有的文件都要在这里执行. /*----------------------------------------------- * 系统环境配置常量 * 能够配置错误显示级别 * ----------------------------------------------- * 默认情况下: * developmen

CodeIgniter框架——源码分析之CodeIgniter.php

CodeIgniter.php中加载了很多外部文件,完成CI的一次完整流程. <?php /** * 详见 http://www.phpddt.com/tag/codeIgniter/ */ //如果入口文件系统目录常量BASEPATH没定义,就挂了 if ( ! defined('BASEPATH')) exit('No direct script access allowed'); //定义常量:CI_VERSION,CI_CORE define('CI_VERSION', '2.1.4')

CodeIgniter框架——源码分析之Config.php

CI框架的配置信息被存储在$config数组中,我们可以添加自己的配置信息或配置文件到$config中: $this->config->load('filename'); //加载配置文件 $this->config->item('xxx'); //获取配置信息 当然也可以在autoload.php中设置默认加载! <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');   clas

Android Small插件化框架源码分析

Android Small插件化框架源码分析 目录 概述 Small如何使用 插件加载流程 待改进的地方 一.概述 Small是一个写得非常简洁的插件化框架,工程源码位置:https://github.com/wequick/Small 插件化的方案,说到底要解决的核心问题只有三个: 1.1 插件类的加载 这个问题的解决和其它插件化框架的解决方法差不多.Android的类是由DexClassLoader加载的,通过反射可以将插件包动态加载进去.Small的gradle插件生成的是.so包,在初始