频道栏目
首页 > 程序开发 > 移动开发 > Android > 正文
Android View系统分析之从setContentView说开来(一)
2014-09-09 10:53:00         来源:Mr.Simple的专栏  
收藏   我要投稿

今天是中秋节,先祝各位中秋快乐吧。作为北漂的人,对于过节最大的感触就是没气氛~ 中秋是一个特别重要的节日,小的时候过中秋都是特别快乐的,有月饼吃,和家人上月,过完中秋要去亲戚家拜访等等。现在对于我们来说也就是一个节日罢了,窝在家里看点电视、看点书、吃顿好的,虽说生活好了,但日子过得没啥滋味。废话不多说,开始今天的学习吧。

Hello World

对于学习编程的人而言,大多数人第一个项目都是著名的"Hello World",自从K&R开了这个先例,后面的人就很少有打破的。学习Android开发也是这样,我们第一次创建应用,估计也就是运行程序,然后在模拟器上输出一个Hello World,我们看到最简单的Activity中的内容大致是这样的:

public class MainActivity extends Activity {


	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main_activity);
	}

}
main_activity.xml大致是这样的 :



    

然后执行程序,我们就可以看到模拟器中的Hello World了。

WP+PDB589mIZuGUpDg0Np53/s9CGHPN8od9guIPtq1RgBxkcdZAsHbxobsj6gffmkS90WsvZSPQaR4Mqfa/fi8qKTAM629cjSrKyuuOa1cu7K7NA0e87ZCGEtD7vMD+126cxS6jFtMVlcn1Ksy8xY4+KfRtLCu8OWzspxrs8IlN+duGbDDsg3v1X7LNrEEuSCKfMJ9+LKYhq7Yywtfbbk8fia/2g+jf9oPB15+Ujafd9u9yf+7Nuzafcec9flIeBC8hc+XnA5LqD+OvmXk4nP6gurafyHNmlm/8gLknVj70A+kPOp904lhiAwUd7S9kD7atEYw1O2ENjICNA4Icf4oHGgpYSJxoub53Vh1tDHto2l4eFh746fmjsVSd2O9E33Fw3STCf30HeHfEyzadR1/CAU0jlBupS1L7SxfU/uS2et/2yKn8lfMUL2jOwZck5p4W0jCnuHKv2qa2DHTEM+9tqxdODJA6n/RpuQsHgeTtqLGGbyt9tkDZNTpz48lRYXF9OeH+7xVIeeO1SlNnym/3fal0T12eSOEzAhGUFWEVu/eX8083fefSctLy+7bDRGTAxz8M5BiidOnkjLny5X+ZvsfU/saxV4AVcrMVpi/9FkCwc0gw1eD948/mbyzx8ru2lHGUG82SaMbiHdQ7qSy4vL6Zn/eWZ9fTJmoq3R7WtrZ+HMQEN+w7ebZhfxYTYzntbkLJ9dXvd7HXz+YFq0GWsmW9cIMQh/xRKvVOnJyz5j20bT7vt3+/Pxt15LU09PpcVPKu2X8FXTbi+FHyBAZuWHBox0TWPbeU/1R6WRZeU9+srRNHDjQEViVs/C5PLR/Aa/M5hOvHuiyXf73dvT6K2j7mYJ1didY56UbjX1Nf4I8ceEWXvkPfbEYx5n9k+zafnMepyaeh6FMLuFGO3VW/v4cgsPOl9WuepO2IbA4ywqVgdz9KWjTkJHf2PLcdoYsCI9bYl1wb1bbPb589b1wS4fMqizifxa7CycbMC/t6daTkI8/z3q3yXSle2XMUEbE/B8zhpxMme0Ztv6R8rphGek+28jafyBCe/eL3yykKZ+Ne0TLh5ucZaJZ1yc51vmF+4ob7hnT87i5d1Z0mPefP3NNPvurJOXe9RfIR+yYvafPwTH/1SPPRZ8xFKlWBZ14OcHHPOQ5etO6/gMi4Rh/LNTfY442J3HGA10DC/nttwVDsLj618frFEuf77s3WEaKK3EG5NpKGGmX5hOR180cuwQTlePxslYIG2I9Jh4Xv3c/tiwaNzYBpt1iG6fM9v+hZtw8rBOsM0h9zopE+5jk2ZHeGNn9ZOJlX7TXnmXyDvywM3bMAmD1jVuO3Ewi59VGiJrHon72hvVus1Vk2FL3tfeI3sf0uXvl7vnP5lPMy9VkyOTP51s4vXfaBqeGd4zTGATbsYk596bS5OPrKUjDpok44YYNMMTfzrhNjgNftvWWpqZ/+t8Ov3haZ+AmX5+bebdcbLwTuX1xPbVojH6j0wIPzZGtnDYgPWA7huzmdR/GlBDOq41Ve7hW6ybhrtDuKetw2uuatpTLi/ihT311FRibAy7iWd5MMbnEy6UyeTibhq3uUnvn+z3GrMJhz7rrkKALsuirZyhC8070L2uyj9rGtn4gxO+kHsnkyOmpUGbkP+x3x+z8bxFlx2aaZlPJ/fZM2fTxA8nvJx7HtjjkzIUL48P2Tem4Judd+9MB56ycU7b1eOmDt/2vW3NmCtjijvus/FMm1hB7ujIaGJtJ+b727+fbv7OzWnmdzNpYGDA/XxMs8inKY/HqL5aidH8YrZLdtXPEQ4bDwcG6XfcsyOxdY/BfZZ9OAHWJMikCuOHQ8PV2F+E4c/sJ3b4QUg8t9Qja5jhX9qMoWGYwHAZMBjxTQYk0owxmhuD3Mgr3GFPmKY1bBMW/bZkhnwgQhixGm+0LiVOxiwRxbtZPhM/GE/zCws2Lvewj/8t0fX0ZPZl4S3vUecf+bXY1m9nzSPdXYiM8cqWcCt37naHfV2K/MceeSwxfsrY4/6n9ye6x+wXJy2fY68fS5M/mUwjNjzA7zj71qxjhAbMds083zK/KEdLV9rEOviyhQONcKPWg4GbBhIzoPH+E4+Y1mPsQBd2eGTYu22MWzG4jzY4/+G8tye6df3frLqbdAHDGOW0tCuXZekhC3bQsMbPx8jIwxovBjvyhPhwRyPGH5PblC3KG3a60Raps3TlQVu64qRGt5XftVrcbZ3sNHzPapp7u9bILJTdLaXxtY7mudJTdedDfkfbyIk/Lif/fNLJ6ehvj1Y7eyzndfUqtkXWma4Lv0g93HnXzvSM/QMLFrMP3mhd6S3J8Yzynf74tJPn9ru2dy6H5ZObFmIkwME339yO7UuMteT+4VZ4tb0r8Cht4XN948OyExrs8B3DTobsqYWsmHkeHLQdJTZehlYS/nTXFlcXU//minBoMy3txkiK2dFd91Z7rbEnH5/0Rps3Tshs2cYcMU6CdTrqk7utPTb+dbyWfAi3cq4sWffZniHxZfsHia6es7HEzX1p6M6VNGwfqNa73Jltj+63csYmQp4bSn22pbCUj7us38xKQ/ZD3x5KTFJB6jFmClmV7YN8wuTyGUc8aXu7J22fdrJVPf4HyArJMIbLMTwOv3C4Smrv19fXt658p/92OqFhYtAic/lRjqb8lST/Bq41YxlFpNJ2YBUufKxR5o0h6snXuX64trX5rI/9nXjvRNPQaDjRRYz3xw/NxccEIQFrM25oaVn78fjR+mo732pIGtzgGzIgOdeomF4m3EhpYPOAx3OPTH78Lmi2I9u2pYWFeT+Fh3hosE55aKKWptI/KzvIkXg826ukY8+aBn3rkI0RDl+0/s/Pz6fpX1daJ7PbjPnlhuVPDDVE+fKwFnws4OFHHvZg3oG93mD/zH8/48TKHx9wDsNOFwxy9/58bzr57slqIsnHS22IwMZQR+4YafKN/MP23yOEmR0/TeVlLmdUc7UwK6H8wAoXPtYYMRupfnhXlh0gZnhOX9j72z8mMnCz06PvRlNp8AcfayeMFTL2xaSAE1HWflwG7syg+aHJtRiLg8bIsh9Mn/2LWVxfCvSNWnO0eC6zTfuEVPY9bmNyvzzo3Xy039AykXno0SJPPMOYpjdo2vCoESKzvZOP7r1o/ffJnUjfxvZymn/g1LByHdf962cWibP2kC4w/IPNKUGnTp7ynTVoiIzpTv7YxhON9HJ+YpcM4WN3jaWJH0+kbfbHIQ+P/Jv8it/DoGw1zqD2o/tfJmw0BLmFhyHg9WAD1gcaZaVlVW0FHPp712ZKmUVmYXT6hmks1s1m4TJm+o16vM7SN+0IDRAVjZZHYwy7yMNCKrLDNtIcHrLxzIhLoMXvG+xrzovEC9Pkk/1eA98e8DE3Fj8zmQQ5QZhOkCETfgzV0R59jNM8sDlubGTEiMfiNLyQyc/5gdN7/vHPf6yPF/FLu6e3Y3y6yXl+TIIdff5oKx+V8gzfqWen0qFnD7WPd4H6C35hNtlDc9EL23dkhIAQaEWAnSeuzNWENn7/eBq5c8R2lSymQ7+ybW41ubBXF81k3hZW4w/5OMEYsS3YTG8Yl2dpOMx21/27fE0e2w6Rw4LlPffv8Rnh3fXaQjQl1gCy4NkXllu87XduT3t/tje9+odX07E/HHOSy/OIvGRfOgKMF4dpIUYWpcoIASHQikB05eY/nl/TqmoyDFLERhPb+5O96dBLRoowqfkN31RpenQJwzTybCmLm1xzzOS6ZmcaW4tmWYT39fSlwZsGnYDzPCIv2ZeOgG8rrKO3ECMLOP3HsB+VroPPXuW2/UgKb4NL4CV8vpb1g9Nh2F1B3b9sY0QGEQ7fNlxpjyYDeU5iRogxVth0R9lGaGOHl+NmiRC7V1i3p/Z55e0THHNDV9o/9iOdP//F+fNGkO1thbfHJfASPsJH7ee65Y/gwdquSBGHk2I0btnCg0aueqB6sEHqQU6MjFg0hhXqncYz5G8wZeM7wkN4qD5YHegwPnpd+jdMWBwiEWMosquxJOEgHGgrqgcbox5kvNh6r/SRF480YTH5Eh5yV4O6wqNCQPVB9SFfkP51qA+xdZAa3nK6Tv6X0Wek61k4/OWuZuQBTXioPqg9fP3aA207TMtynSMvHGm7TMc8W/wZP+AvRJ9tQo+/FO62NVW52yuP+WBz+U+kw83WJla126OHh7zcnafP5ZrIJp88fif/TnI6+SOnOQjUHMRjPIk1Y5Sj+m92jUOEu529Tyf58u+wHMxwzn9n4SQ8vsz68Nij1WETkGMLMR62U3vbDSj7Zu2YeCBVPuBqRBBuKrKfd5aHWzo/860mFOT7gZeQCpqo7Q5g3Zbna6Jit0BeDtLjbtnCFOXI8ieLkBPpkUf52pUryp3blMnzCfnx3jXhIafZvJ6/Zxaey4tyyDZAc7wCV9nCpUvqRU6MVMs106mSWgzurWAvKBvl3bCv3fgsfW4f/HF/0z52RJGTQJCU2ZANjYJFq/t+us+OL+rzEzgW7KIezm1jszcz4kufLHm80MpCTqNdUj4ThRz+e7iVh/2pXj7zcn8rV++5imydVI202pUryNLLV5eX+Cy6xXDDGmX1sn285FdIuhwLIz/O6ePcvtk/z6bZ/7OdDfb+fptaJxzlLxLoEhLQHylrxGV7pNHXpuMYI+FOGGZzZwQDk1O/mPI9mnSLCdv63a1+7NK+n+1zLYt4/rGz5tC6OHPObbuIB/+V5ao77XlbBeHMusbg/nzRr0WMdH4/r8lZtYspSM95avt/sd9P+kAuJ3mwn3T/f+33S7X9tBPzh6yIN/GTCb8jg62OUZ6mfFZ+7rdY/NTytG59hEOKyHGtkEpsJn8H0lMuzwvCJ/yLmvjr46ACN9k1PoGT7Kq+CIeuxMELVX+1EKOP6diPVtqh7ZEGkrB7eZw44vy42CjvvWXCTeFyUrMLfyAS/CES7+rWGUOKvauonJXxC8hXq0t+Ij3xSU+epOd8NwzXMjox2RntnPzhfnYo5qq58fdrG83Tr2ukG24E53KsPF6Ounzk4yS/XJcTt53xRn5Bai7c0jtR1u9BPnENI+FoichhzJR0JX5y21iZcFG9MAS6uR54W6+/UCYbkxcaz8YN2dXaE/biSnU5jpNMHQ+igOg4con7FzjmHcJEK+OmscW5xeYsN88QsrI0jbEskMvR5Lv3WHrT+pr0dhow58hxesjIbSN+ajIX7fT29Xo3HCLz03thOuvK9w9Wex455cTJ2m4bn/hR1e0NmZxUMjc/52fcHXjarl40Gexf5Y4Iyjz13FRTNN6TPwIce8TlPuTFeW+kwYCTk69pxoOb7X4Nbjev/YMU5c7qE3gJn7X2JTy6oj54Ieqv9RpjptZ5ozZ3NHzS8OwalZGCj6fhCWlS183mjgk2sy9/tpzm3p9zopuw+2ohPJ+FJn4bE3lMPGQn7Rr5IYuDPjkendN3B/sGffM9STkUlDKMDI/4ZA2aJJMsYyNj7h9a5MJHC95dn3zIDrKsZUJ6yBx/YDwNbBlouvOQHQdjYkOepaF8kCK3jZF3f19/cxtZxA285K4QEB7VrLLqw/VRH+J3wm7RGGOJSkTgLlsqtxNfHZPz4/iUBuKALND00LA4V867xzaLC1GO3j6ajn18bC0ZZJobc3N3BukhHrQ4usIcHc91iJzEO/ObGZcNyfb02WVEdmIJhoNCuZiI49f7P+z3CRO6vtz3QLe6k8zRO0fT/G9MqzQDsS781S4af3nKNUZ/Zw+xkQHTFjk+KkiRsnFtI7P4yHZj5QcDn/Sp363Br5Yjd12fhIcjoPrQXfWhrpZurdMY80AnxdzDntHilpaWfAaZ58YYGXAAJwTDTC6Edvi5w06KxIHILmQ4YjzSQ2qLH9tlPUaQ3h22hH7Pr9n4k8fWW+z6SuvaQsJcRIRN+uHb7XgnSI6urhHV4JCRqLkvJDPKdfzt407G+R+CCOv/VtU9Rw6kSJwY84w4pV3iJ3drHRAewiNvM191fcjL0kKMEAmmtHPtiXE4urssVfHThHNp9TOEOf3StC/JIQ6fU+9XF2K3RK81qxa/3NEmPIgSLRLNEQKEFNEu6SKHBuenGRfp472aLIpwhgN67ah1DEfEdzSRzoY03YS7tiMf2e3rk3ARLrSbbqsHVWOuvlu60oytUdh1tmlcOTmy/g9tDk2sMSYJMnJ/C2eNIqSFLMb8Fj5bSP1bWg+CzNNDRIv/rLRExvk4lRiy40YxDMtqiM8F3hjuoMC9MF+NL0KYkOXI7TY+aYbDQMkvl8mEEBpnLtMj119RHsixZZzR3m3502qiiLIhh3dDY3VTo+jp7Xkdfp1wlX/7+iZchEs7HrrG9SLngrpJV16QGqOOpe2hwYFmQwBBAkEMuJlwgbiY6OACcZ7pVnPD2IEnbea31khJ45pZnrs9Ly4tNumnnpryWWu0QDTCE3854VochIs7JljIAyJifDDdm9yf8IV/mttkor1GmUqZs+/OVu/hL2FfFj8Wfeejr5A2l3azAJ2LhRgmYEYdjbUxlpb38yU7HXAscZW7fX0TLsKlHQ9d63rRtGV7aOlKOxnQHbRG3oyz5W7zZhwATYyPk0jtB9HxOfrK0XTyLyfN17Q6ltYYKUJ4q5tbNUzIzMnRY1b7kJv071t6K0N0lWd+Z5Mun9p4JuRs/stLdmm4EbEToGmpvVt607zdm4sbfzRN4vHMZ+bVmXSykMluFkgzL4MXhXeH/K18YaKsM6/P+PgqMtkhw5ikG/Ky+J4mxwtZcneuT8JH9aOb2kc0eLM32ed8uOPy8LhvIvzZkdIszTHPmL0O8rAFPP4D4/ZnEvLCZvBj9o07cQlz9zkjsPqeXifhuoFAusTx7nwZjqw63OXCXmaI63IJrcnM3fWzx7EY/I8yOUnX6T3cSJsDMcKEvHD77HoeH83X3o/8nCQhff4ZYeb3dUT6Ek+5q+t5hU+FgOpDd9SHA08diCrZnhib0PrBD32on/PuMF6QQ+OH5mT/3F0ToxNfnTbiY0eaIDP3M/Zq0uOBDGTmhGcxchNy8It4TTiEizE5TbxMZvi1pMvSVInrtO3ejQhRvjqdH4gRCWULASFw3SCQE2NLVzoOTyhtNCgIwDUp04owTiaQQf1BW8KPAx2cLGwCBg7D392E2yfCuZErd+Pfkp50dXryjfAoR9i5/LychGPi5J4mHuXKyuw3g5k7yhXE1rgpl5WFC9ab96dcxftFOvIs8ZO7mr4XDsKhm9sHZQvTQow0bipvaUMKmMY2UoNcGncdHulK/3BH+MXsiJ/bUa6WcpTlKtx5Pu3S5eEh/0J2Xp5c3uXKUfz29Uy4CJcLtb9rXT9o02FaiPGrLNS1fmnJV6NT/V6v9KhdrLWLIEXsFmIUSGsgqRGpEak9bKz20JEYRQYiA5HBxiID/d5rv3dHYhRIayDpj4T+SKg9bKz2kBNjyzrGPEDPQkAICIGNikDLGONGBUHvLQSEgBDIERAx5mjoWQgIASFgCIgYVQ2EgBAQAgUC14wYp3455fenRH6lO/y7zb5YOTly7Ngfs5PIv6QXKMtVur+kYlw0m4uV66vC76IFVwQhkCGwjhj3/ufexKc0h188nHbdt/5KgzJeuDluzLfh1R6lO+Jdij317FSa/OlkS1Tcbx5/s9reV4dwHuM7s+/4vS0tkS/DcbFysm2ROJdqugHPbsbvyMtH1v22l4qt4gmBa4XAOmK8Vhn9K3K5IZCDaXODm2PGIMMwwyPD1Ynedv2AzBoC3YwfB3nEYR5rJdaTEPhqEbhyYrS90mhDdCtnfj+T9jyw5/LexNKj9ZGeD7JyDTMXNndyzq8s4PRsDLcEcnEW1yyM3THWROVk7rm5ucp9EflowCP/PpL2P73fNc+cYBuB5GV5onGhnaLdQL7XxFxDPLsZP8615CpcGSHQTQhcMTHu/dne1N/f7/e/cDL2znt3pm13bbvkdyM9l1dNPjrpMpC19+fru/AI5BqBpc+WGlIaHRn1C6lOz51OI9vWNMmtt25Npz6yu2XMXIp88p6fm0+PPfqYn/LtCYuvyScmnbC5FvaZp59JO+7eUcS4Os5riWc348epzNIYr04dkpSrh0BbYuTSecbq8g/XkzbGtJvtd21PR1+sTsGe/+t8OvHuCfdr4lzoIdLbFatcF8BJ2odfOJzG/n2s4/ggJDh626hL5TrWE++dSHMfmCZpVx+gaaJFDtw44ETHyT9evovI55qE115/zYk3DrHNi41cyuRXwVoZIRjiX67pBjy7Fb+zn5u2yCHCMkKgixAwCllvZv88m159+dWWgP1P7W/cQUYHnz/Y+DEpAUFeion0fg1pnQCChIiYtZx7v+4OZ8LmPpprJn9G7xhNx984Xl2vyh0ztdYIcXG9KTcFIuti8i9WXu6VKeX47YNZuS7lsRvw7Fb80BYZK5YRAt2EQFtiXP18tdKispK26+7se3yfXwrVRItTuxuPq/dw4uQJ7x4P31bdGx2kduq9U65JUr5mfPHqZXtVJHUDnt2KH6TIneIyQqCbEGjblb5YAblonrEhuq90g5vPJc4GR3q0wzDcvofJtbwIwyaPpaUlXxt56oNqHBH/uffmfMZ6+JbhZnzxSuQjqzR+iZe9Z9xVTfjgYHYzYJngCt1R3muJZ7fixxAMQxoyQqCbELgiYmQ87vhbx9PEIxMJDQ5S2/a9bf58SS+XpScthMAECF1OusKdDFrP2J1j1ThiHQnNkRlqSJaJFDdXKL/MF/JnHJOJF8oIQe66v3Ut58SDE/7uZdrLcmflvZZ4diN+k49P+sTdZeGlyELgGiNwZcRohZr+9bR3XblAhkmY8YfGL6uopEdTmH5h2ic3lpeX06FnD11QBjPOLK4uu8xokNxpnZPqlchvl/nB56px1JlXZnzWnHcNw/gjy5TaDTNEnEu1vww8uw0/sGFsWkYIdCMCXJ+qzxVgYGsfz9sazPM2Cy78rgA/1TvVm26tA1esMXYjw3/ZZWJBOUMK7Zb6fNllUX5CQAhcPQQ2mSi0HRkhIASEgBCoEZDGqKogBISAECgQEDEWgMgpBISAEBAxqg4IASEgBAoERIwFIHIKASEgBESMqgNCQAgIgQIBEWMBiJxCQAgIARGj6oAQEAJCoEBAxFgAIqcQEAJCQMSoOiAEhIAQKBAQMRaAyCkEhIAQEDGqDggBISAECgREjAUgcgoBISAERIyqA0JACAiBAgERYwGInEJACAgBEaPqgBAQAkKgQEDEWAAipxAQAkJAxKg6IASEgBAoEBAxFoDIKQSEgBAQMaoOCAEhIAQKBESMBSByCgEhIAREjKoDQkAICIECARFjAYicQkAICAERo+qAEBACQqBAQMRYACKnEBACQkDEqDogBISAECgQEDEWgMgpBISAEBAxqg4IASEgBAoERIwFIHIKASEgBESMqgNCQAgIgQIBEWMBiJxCQAgIARGj6oAQEAJCoEBAxFgAIqcQEAJCQMSoOiAEhIAQKBAQMRaAyCkEhIAQEDGqDggBISAECgREjAUgcgoBISAERIyqA0JACAiBAgERYwGInEJACAgBEaPqgBAQAkKgQEDEWAAipxAQAkJAxKg6IASEgBAoEBAxFoDIKQSEgBAQMaoOCAEhIAQKBESMBSByCgEhIAREjKoDQuUy8YoAAAFNSURBVEAICIECARFjAYicQkAICAERo+qAEBACQqBAQMRYACKnEBACQkDEqDogBISAECgQEDEWgMgpBISAEBAxqg4IASEgBAoERIwFIHIKASEgBESMqgNCQAgIgQIBEWMBiJxCQAgIARGj6oAQEAJCoEBAxFgAIqcQEAJCQMSoOiAEhIAQKBAQMRaAyCkEhIAQEDGqDggBISAECgREjAUgcgoBISAERIyqA0JACAiBAgERYwGInEJACAgBEaPqgBAQAkKgQEDEWAAipxAQAkJAxKg6IASEgBAoEBAxFoDIKQSEgBAQMaoOCAEhIAQKBESMBSByCgEhIAREjKoDQkAICIECARFjAYicQkAICAERo+qAEBACQqBAQMRYACKnEBACQkDEqDogBISAECgQEDEWgMgpBISAEBAxqg4IASEgBAoERIwFIHIKASEgBP4fNHRcGDZ03TsAAAAASUVORK5CYII=" alt="\" />
图1

我们在整个过程中做的事情很少,在我们的main_activity.xml我们只有一个显示文本的TextView,但是在上图中却还多了一个title。我们好奇的是整个过程是怎么工作的?对于大型系统来说细节总是复杂的,在下水平有限,所以我们今天只来理一下它的基本脉络。

setContentView

一般来说我们设置页面的内容视图是都是通过setContentView方法,那么我们就以2.3源码为例就来看看Activity中的setContentView到底做了什么吧。<喎"https://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD48cD48L3A+PHByZSBjbGFzcz0="brush:java;"> /** * Set the activity content from a layout resource. The resource will be * inflated, adding all top-level views to the activity. * * @param layoutResID Resource ID to be inflated. */ public void setContentView(int layoutResID) { getWindow().setContentView(layoutResID); } public Window getWindow() { return mWindow; } private Window mWindow;

我们可以看到,实际上调用的mWindow的setContentView方法,在Android Touch事件分发过程这篇文章中我们已经指出Window的实现类为PhoneWindow类,我们就移步到PhoneWindow的setConentView吧,核心源码如下 :

    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();			// 1、生成DecorView
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);// 2、将layoutResId的布局添加到mContentParent中
        final Callback cb = getCallback();
        if (cb != null) {
            cb.onContentChanged();
        }
    }
        // 构建mDecor对象,并且初始化标题栏和Content Parent(我们要显示的内容区域)
        private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor();          // 3、构建DecorView
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);              // 4、获取ContentView容器,即显示内容的区域

            mTitleView = (TextView)findViewById(com.android.internal.R.id.title); 5、设置Title等
            if (mTitleView != null) {
                if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
                    View titleContainer = findViewById(com.android.internal.R.id.title_container);
                    if (titleContainer != null) {
                        titleContainer.setVisibility(View.GONE);
                    } else {
                        mTitleView.setVisibility(View.GONE);
                    }
                    if (mContentParent instanceof FrameLayout) {
                        ((FrameLayout)mContentParent).setForeground(null);
                    }
                } else {
                    mTitleView.setText(mTitle);
                }
            }
        }
    }

        protected DecorView generateDecor() {
        return new DecorView(getContext(), -1);    // 构建mDecor对象
    }
我们可以看到,setContentView的基本流程简单概括就是如下几步:

1、构建mDecor对象。mDecor就是整个窗口的顶层视图,它主要包含了Title和Content View两个区域 (参考图1中的两个区域 ),Title区域就是我们的标题栏,Content View区域就是显示我们xml布局内容中的区域。关于mDecor对象更多说明也请参考Android Touch事件分发过程这篇文章;

2、设置一些关于窗口的属性,初始化标题栏区域和内容显示区域;

这里比较复杂的就是generateLayout(mDecor)这个函数,我们一起来分析一下吧。

     // 返回用于显示我们设置的页面内容的ViewGroup容器
     protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.
        // 1、获取窗口的Style属性
        TypedArray a = getWindowStyle();

        if (false) {
            System.out.println("From style:");
            String s = "Attrs:";
            for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) {
                s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "="
                        + a.getString(i);
            }
            System.out.println(s);
        }
        // 窗口是否是浮动的
        mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);
        int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
                & (~getForcedWindowFlags());
        if (mIsFloating) {
            setLayout(WRAP_CONTENT, WRAP_CONTENT);
            setFlags(0, flagsToUpdate);
        } else {
            setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
        }
        // 设置是否不显示title区域
        if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {
            requestFeature(FEATURE_NO_TITLE);
        }
        // 设置全屏的flag
        if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
            setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));
        }

        if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
            setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
        }

        WindowManager.LayoutParams params = getAttributes();
        // 设置输入法模式
        if (!hasSoftInputMode()) {
            params.softInputMode = a.getInt(
                    com.android.internal.R.styleable.Window_windowSoftInputMode,
                    params.softInputMode);
        }

        if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled,
                mIsFloating)) {
            /* All dialogs should have the window dimmed */
            if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
                params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
            }
            params.dimAmount = a.getFloat(
                    android.R.styleable.Window_backgroundDimAmount, 0.5f);
        }
        // 窗口动画
        if (params.windowAnimations == 0) {
            params.windowAnimations = a.getResourceId(
                    com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
        }

        // The rest are only done if this window is not embedded; otherwise,
        // the values are inherited from our container.
        if (getContainer() == null) {
            if (mBackgroundDrawable == null) {
                if (mBackgroundResource == 0) {
                    mBackgroundResource = a.getResourceId(
                            com.android.internal.R.styleable.Window_windowBackground, 0);
                }
                if (mFrameResource == 0) {
                    mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0);
                }
                if (false) {
                    System.out.println("Background: "
                            + Integer.toHexString(mBackgroundResource) + " Frame: "
                            + Integer.toHexString(mFrameResource));
                }
            }
            mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000);
        }

        // Inflate the window decor. 
        // 2、根据一些属性来选择不同的顶层视图布局,例如设置了FEATURE_NO_TITLE的属性,那么就选择没有Title区域的那么布局;
        // layoutResource布局就是整个Activity的布局,其中含有title区域和content区域,content区域就是用来显示我通过
        // setContentView设置进来的内容区域,也就是我们要显示的视图。

        int layoutResource;
        int features = getLocalFeatures();
        // System.out.println("Features: 0x" + Integer.toHexString(features));
        if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
            if (mIsFloating) {
                layoutResource = com.android.internal.R.layout.dialog_title_icons;
            } else {
                layoutResource = com.android.internal.R.layout.screen_title_icons;
            }
            // System.out.println("Title Icons!");
        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {
            // Special case for a window with only a progress bar (and title).
            // XXX Need to have a no-title version of embedded windows.
            layoutResource = com.android.internal.R.layout.screen_progress;
            // System.out.println("Progress!");
        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
            // Special case for a window with a custom title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                layoutResource = com.android.internal.R.layout.dialog_custom_title;
            } else {
                layoutResource = com.android.internal.R.layout.screen_custom_title;
            }
        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
            // If no other features and not embedded, only need a title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                layoutResource = com.android.internal.R.layout.dialog_title;
            } else {
                layoutResource = com.android.internal.R.layout.screen_title;
            }
            // System.out.println("Title!");
        } else {
            // Embedded, so no decoration is needed.
            layoutResource = com.android.internal.R.layout.screen_simple;
            // System.out.println("Simple!");
        }

        mDecor.startChanging();
        // 3、加载视图
        View in = mLayoutInflater.inflate(layoutResource, null);
        // 4、将layoutResource的内容添加到mDecor中
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        // 5、获取到我们的内容显示区域,这是一个ViewGroup类型的,其实是FrameLayout
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }

        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
            ProgressBar progress = getCircularProgressBar(false);
            if (progress != null) {
                progress.setIndeterminate(true);
            }
        }

        // 6、设置一些背景、title等属性
        // Remaining setup -- of background and title -- that only applies
        // to top-level windows.
        if (getContainer() == null) {
            Drawable drawable = mBackgroundDrawable;
            if (mBackgroundResource != 0) {
                drawable = getContext().getResources().getDrawable(mBackgroundResource);
            }
            mDecor.setWindowBackground(drawable);
            drawable = null;
            if (mFrameResource != 0) {
                drawable = getContext().getResources().getDrawable(mFrameResource);
            }
            mDecor.setWindowFrame(drawable);

            // System.out.println("Text=" + Integer.toHexString(mTextColor) +
            // " Sel=" + Integer.toHexString(mTextSelectedColor) +
            // " Title=" + Integer.toHexString(mTitleColor));

            if (mTitleColor == 0) {
                mTitleColor = mTextColor;
            }

            if (mTitle != null) {
                setTitle(mTitle);
            }
            setTitleColor(mTitleColor);
        }

        mDecor.finishChanging();

        return contentParent;
    }
其实也就是这么几个步骤:

1、获取用户设置的一些属性与Flag;

2、根据一些属性选择不同的顶层视图布局,例如FEATURE_NO_TITLE则选择没有title的布局文件等;这里我们看一个与图1中符合的顶层布局吧,即layoutResource = com.android.internal.R.layout.screen_title的情形:




    
    
    
    <frameLayout
        android:layout_width="match_parent" 
        android:layout_height="?android:attr/windowTitleSize"
        style="?android:attr/windowTitleBackgroundStyle">
        
    </frameLayout>
    
    <frameLayout android:id="@android:id/content"
        android:layout_width="match_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />

我们可以看到有两个区域,即title区域和content区域,generateLayout函数中的

 // 5、获取到我们的内容显示区域,这是一个ViewGroup类型的,其实是FrameLayout
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

获取的就是xml中id为content的FrameLayout,这个content就是我们的内容显示区域。整个布局对应的效果如下 :

\

这两个区域就组成了mDecor视图,我们的main_activity.xml就是放在内容视图这个区域的。

3、加载顶层布局文件,转换为View,将其添加到mDecor中;

4、获取内容容器Content Parent,即用于显示我们的内容的区域;

5、设置一些背景图和title等。

在经过这几步,我们就得到了mContentParent,这就是用来装载我们的视图的ViewGroup。再回过头来看setContentView函数:

    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();			// 1、生成DecorView,并且根据窗口属性加载顶级视图布局、获取mContentParent、设置一些基本属性等
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);// 2、将layoutResId加载到mContentParent中,这里的layoutResId就是我们的main_activity.xml
        final Callback cb = getCallback();
        if (cb != null) {
            cb.onContentChanged();
        }
    }
我们看看LayoutInflater的inflate函数吧 :

    /**
     * Inflate a new view hierarchy from the specified xml resource. Throws
     * {@link InflateException} if there is an error.
     * 
     * @param resource ID for an XML layout resource to load (e.g.,
     *        R.layout.main_page)
     * @param root Optional view to be the parent of the generated hierarchy.
     * @return The root View of the inflated hierarchy. If root was supplied,
     *         this is the root View; otherwise it is the root of the inflated
     *         XML file.
     */
    public View inflate(int resource, ViewGroup root) {
        return inflate(resource, root, root != null);
    }

    /**
     * Inflate a new view hierarchy from the specified xml resource. Throws
     * {@link InflateException} if there is an error.
     * 
     * @param resource ID for an XML layout resource to load (e.g.,
     *        R.layout.main_page)
     * @param root Optional view to be the parent of the generated hierarchy (if
     *        attachToRoot is true), or else simply an object that
     *        provides a set of LayoutParams values for root of the returned
     *        hierarchy (if attachToRoot is false.)
     * @param attachToRoot Whether the inflated hierarchy should be attached to
     *        the root parameter? If false, root is only used to create the
     *        correct subclass of LayoutParams for the root view in the XML.
     * @return The root View of the inflated hierarchy. If root was supplied and
     *         attachToRoot is true, this is root; otherwise it is the root of
     *         the inflated XML file.
     */
    public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
        if (DEBUG) System.out.println("INFLATING from resource: " + resource);
        XmlResourceParser parser = getContext().getResources().getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }
实际上就是将layoutResId这个布局的视图附加到mContentParent中。

DecorView

移步 : DecorView 。

ViewGroup

ViewGroup从语义上来说就是视图组,它也继承自View类,它其实就是视图的容器。我们看官方的定义 :

 * A ViewGroup is a special view that can contain other views
 * (called children.) The view group is the base class for layouts and views
 * containers. This class also defines the
 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
 * class for layouts parameters.
我们通过ViewGroup来组织、管理子视图,例如我们常见的FrameLayout、LinearLayout、RelativeLayout、ListView等都是ViewGroup类型,总之只要能包含其他View或者ViewGroup的都是ViewGroup类型。使用ViewGroup来构建视图树。

\

View

View就是UI界面上的一个可见的组件,任何在UI上可见的都为View的子类。我们看官方定义 :

 * This class represents the basic building block for user interface components. A View
 * occupies a rectangular area on the screen and is responsible for drawing and
 * event handling. View is the base class for widgets, which are
 * used to create interactive UI components (buttons, text fields, etc.). The
 * {@link android.view.ViewGroup} subclass is the base class for layouts, which
 * are invisible containers that hold other Views (or other ViewGroups) and define
 * their layout properties.

TextView、Button、ImageView、FrameLayout、LinearLayout、ListView等都是View的子类。

总结

\

整个窗口由Title区域和Content区域组成,Content区域就是我们要显示内容的区域,在这个区域中mContentParent是根ViewGroup,由mContentParent组织、管理其子视图,从而构建整个视图树。当Activity启动时,就将这些内容就会显示在手机上。



点击复制链接 与好友分享!回本站首页
相关TAG标签 系统
上一篇:Android 两次返回按键退出程序
下一篇:[android]在xml文件中定义drawable数组、id数组等
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站