安卓笔记.txt 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. 小明经过一年的努力学习终于成为Android中级工程师了,月薪变成了17k。到了中级工程师,已经可以在公司里干很多体力活了,但是一些很重要的任务小明还不能一个人承担起来,这个时候小明需要学习的内容就很多了,如下所示:
  2. - AIDL:熟悉AIDL,理解其工作原理,懂transact和onTransact的区别;
  3. - Binder:从Java层大概理解Binder的工作原理,懂Parcel对象的使用;
  4. - 多进程:熟练掌握多进程的运行机制,懂Messenger、Socket等;
  5. - 事件分发:弹性滑动、滑动冲突等;
  6. - 玩转View:View的绘制原理、各种自定义View;
  7. - 动画系列:熟悉View动画和属性动画的不同点,懂属性动画的工作原理;
  8. - 懂性能优化、熟悉mat等工具
  9. - 懂点常见的设计模式
  10. 学习方法
  11. 阅读进阶书籍,阅读Android源码,阅读官方文档并尝试自己写相关的技术文章,需要有一定技术深度和自我思考。在这个阶段的学习过程中,有2个点是比较困扰大家的,一个是阅读源码,另一个是自定义View以及滑动冲突。
  12. 如何阅读源码呢?这是个头疼的问题,但是源码必须要读。阅读源码的时候不要深入代码细节不可自拔,要关注代码的流程并尽量挖掘出对应用层开发有用的结论。另外仔细阅读源码中对一个类或者方法的注释,在看不懂源码时,源码中的注释可以帮你更好地了解源码中的工作原理,这个过程虽然艰苦,但是别无他法。
  13. 如何玩转自定义View呢?我的建议是不要通过学习自定义view而学习自定义view。为什么这么说呢?因为自定义view的种类太多了,各式各样的绚丽的自定义效果,如何学的玩呢!我们要透过现象看本质,更多地去关注自定义view所需的知识点,这里做如下总结:
  14. - 搞懂view的滑动原理
  15. - 搞懂如何实现弹性滑动
  16. - 搞懂view的滑动冲突
  17. - 搞懂view的measure、layout和draw
  18. - 然后再学习几个已有的自定义view的例子
  19. - 最后就可以搞定自定义view了,所谓万变不离其宗
  20. 大概再需要1-2年时间,即可达到高级工程师的技术水平。我个人认为通过《Android开发艺术探索》和《Android群英传》可以缩短这个过程为0.5-1年。注意,达到高级工程师的技术水平不代表就可以立刻成为高级工程师(受机遇、是否跳槽的影响),但是技术达到了,成为高级工程师只是很简单的事。
  21. 技术要求:
  22. - 稍微深入的知识点
  23. AIDL、Messenger、Binder、多进程、动画、滑动冲突、自定义View、消息队列等
  24. - 书籍推荐
  25. 《Android开发艺术探索》、《Android群英传》
  26. 高级工程师
  27. 小明成为了梦寐以求的高级工程师,月薪达到了20k,还拿到了一丢丢股票。这个时候小明的Android水平已经不错了,但是小明的目标是资深工程师,小明听说资深工程师月薪可以达到30k+。
  28. 为了成为Android资深工程师,需要学习的东西就更多了,并且有些并不是那么具体了,如下所示:
  29. - 继续加深理解”稍微深入的知识点“中所定义的内容
  30. - 了解系统核心机制:
  31. 1. 了解SystemServer的启动过程
  32. 2. 了解主线程的消息循环模型
  33. 3. 了解AMS和PMS的工作原理
  34. 4. 能够回答问题”一个应用存在多少个Window?“
  35. 5. 了解四大组件的大概工作流程
  36. 6. …
  37. - 基本知识点的细节
  38. 1. Activity的启动模式以及异常情况下不同Activity的表现
  39. 2. Service的onBind和onReBind的关联
  40. 3. onServiceDisconnected(ComponentName className)和binderDied的区别
  41. 4. AsyncTask在不同版本上的表现细节
  42. 5. 线程池的细节和参数配置
  43. 6. …
  44. - 熟悉设计模式,有架构意识
  45. 学习方法
  46. 这个时候已经没有太具体的学习方法了,无非就是看书、看源码和做项目,平时多种总结,尽量将知识融会贯通从而形成一种体系化的感觉。同时这个阶段对架构是有一定要求的,架构是抽象的,但是设计模式是具体的,所以一定要加强下设计模式的学习。关于设计模式的学习,最近一本新书推荐给大家《Android 源码设计模式解析与实战》,既可以学习设计模式,又可能体会到Android源码中的设计思想,我最近也在阅读此书。
  47. - 系统核心机制
  48. - 基本知识点的细节
  49. - 设计模式和架构
  50. - 书籍推荐
  51. 《Android开发艺术探索》、《Android 源码设计模式解析与实战》、《Android内核剖析》
  52. 没有类的成员变量,可以把该类的方法写成static
  53. ProgressBar可以在子线程里面更新UI
  54. 将某一个变量从局部变量移为成员变量快捷键
  55. 不会被继承所以要在类的前面加上final
  56. 得到屏幕宽和高:
  57. DisplayMetrics displayMetrics = new DisplayMetrics();
  58. getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
  59. int screenWidth = displayMetrics.widthPixels;
  60. int screenHeight = displayMetrics.heightPixels;
  61. 一、下载图片
  62. 二、解析xml
  63. 三、冒择入希快归堆
  64. 四、设计模式
  65. 五、数据库分页
  66. 文件流
  67. 八、多线程
  68. 页面上现有ProgressBar控件progressBar,请用书写线程以10秒的的时间完成其进度显示工作。
  69. public class ProgressBarStu extends Activity {
  70. private ProgressBar progressBar = null;
  71. protected void onCreate(Bundle savedInstanceState) {
  72. super.onCreate(savedInstanceState);
  73. setContentView(R.layout.progressbar);
  74. //从这到下是关键
  75. progressBar = (ProgressBar)findViewById(R.id.progressBar);
  76. Thread thread = new Thread(new Runnable() {
  77. @Override
  78. public void run() {
  79. int progressBarMax = progressBar.getMax();
  80. try {
  81. while(progressBarMax!=progressBar.getProgress())
  82. {
  83. int stepProgress = progressBarMax/10;
  84. int currentprogress = progressBar.getProgress();
  85. progressBar.setProgress(currentprogress+stepProgress);
  86. Thread.sleep(1000);
  87. }
  88. } catch (InterruptedException e) {
  89. // TODO Auto-generated catch block
  90. e.printStackTrace();
  91. }
  92. }
  93. });
  94. thread.start();
  95. //关键结束
  96. }
  97. }
  98. 九、Activity启动模式和Intent有关Activity启动的方式
  99. 十、数据库
  100. 1。 创建一个版本为1的“diaryOpenHelper.db”的数据库,
  101. 2. 同时创建一个 “diary” 表(包含一个_id主键并自增长,topic字符型100长度, content字符型1000长度)
  102. 3. 在数据库版本变化时请删除diary表,并重新创建出diary表。
  103. public class DBHelper extends SQLiteOpenHelper {
  104. public final static String DATABASENAME = "diaryOpenHelper.db";
  105. public final static int DATABASEVERSION = 1;
  106. String mCreateSQL ="create table diary"+
  107. "("+
  108. "_id integer primary key autoincrement,"+
  109. "topic varchar(100),"+
  110. "content varchar(1000)"+
  111. ")";
  112. db.execSQL(sql);
  113. //创建数据库
  114. public DBHelper(Context context,String name,CursorFactory factory,int version)
  115. {
  116. super(context, name, factory, version);
  117. }
  118. //创建表等机构性文件
  119. public void onCreate(SQLiteDatabase db)
  120. {
  121. db.execSQL(mCreateSQL);
  122. }
  123. //若数据库版本有更新,则调用此方法
  124. public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion)
  125. {
  126. String sql = "drop table if exists diary";
  127. db.execSQL(sql);
  128. db.execSQL(mCreateSQL);
  129. }
  130. }
  131. 十一、内存泄露情况
  132. 1.数据库的cursor没有关闭
  133. 2.构造adapter时没有使用缓存contentview
  134. 3.Bitmap对象不使用时采用recycle()释放内存
  135. 4.activity中的对象的生命周期大于activity
  136. 总结:保存了不可能再被访问的变量类型的引用
  137. 十三、Message, Handler, Message Queue, Looper之间的关系
  138. Andriod提供了Handler和Looper来满足线程间的通信.Handler先进先出原则.Looper类用来管理特定线程内对象之间的消息交换(Message Exchange).
  139. 1)Looper:
  140. 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列).
  141. 2)Handler:
  142. 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出所送来的消息.
  143. android中线程与线程,进程与进程之间如何通信。
  144. 线程通信使用Handler
  145. 十四、系统上安装了多种浏览器,能否指定某浏览器访问指定页面?
  146. 在action赋值为android.intent.action.VIEW“时可接收如下scheme为"http"等等类型的data。所以突发奇想,启动该程序后,指定action及Uri,即访问指定网页
  147. 十五、SIM卡的文件系统有自己规范,主要是为了和手机通讯,SIM卡本身可以有自己的操作系统,EF就是作存储并和手机通讯用的。
  148. 十六、判断手机是否有SD卡
  149. 在程序中访问SDCard,你需要申请访问SDCard的权限。在AndroidManifest.xml中加入访问SDCard的权限如下:
  150. <!--在SDCard中创建与删除文件权限-->
  151. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
  152. <!--往SDCard写入数据权限-->
  153. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  154. Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
  155. Environment.getExternalStorageState()方法用于获取SDCard的状态,如果手机装有SDCard,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA_MOUNTED
  156. 十七、堆和栈
  157. 十八、传递数据的方式
  158. 十九、Android UI中的view刷新:多线程和双缓冲
  159. 二十、算法
  160. 二十一、排序
  161. 二十二、Splash
  162. 二十三、View Page
  163. 二十四、ViewSwitcher
  164. 监测网络状况变化
  165. IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
  166. mNetReceiver = new NetReceiver();
  167. registerReceiver(mNetReceiver, intentFilter);
  168. 重启应用
  169. Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());
  170. i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  171. startActivity(i);
  172. 版本升级只有code变的时候才会出现
  173. 先static{}再执行构造函数
  174. JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
  175. 属性动画
  176. ObjectAnimator.ofFloat(ll_article_detail_bottom, "translationY", toolBarBotom, toolBarBotom + toolBarHeight).setDuration(1000).start();
  177. 代替webview
  178. https://github.com/shivasurya/ChromeCustomTabs
  179. https://github.com/4k3R/chrome-custom-tabs
  180. https://github.com/WeRockStar/Android-Chrome-Custom-Tabs
  181. 不要定时去请求,请求成功之后再请求
  182. 1个字节是8位
  183. 只有8种基本类型可以算.其他引用类型都是由java虚拟机决定的自己不能操作
  184. byte 1字节
  185. short 2字节
  186. int 4字节
  187. long 8字节
  188. float 4字节
  189. double 8字节
  190. char 2字节
  191. boolean 1字节
  192. volley网络框架
  193. 为什么使用service:
  194. http://www.tuicool.com/articles/Yn2YR3
  195. 安卓进程间通信:
  196. http://www.jb51.net/article/37797.htm
  197. Java ->使用 lambda 巩固 性能优化 线程 socket
  198. 不同颜色柱状图:
  199. https://bitbucket.org/danielnadeau/holographlibrary/overview
  200. 复制对象(深浅)
  201. 弱引用
  202. 更改线程中的flag,由false变为true的时候重新执行
  203. 两种办法
  204. 1.线程终止之后,想重新运行,重新new,然后start
  205. 2.变量不要放在while(_flag)里,而是
  206. 销毁时外层设为false,暂停只改变里层的
  207. while(_Stop)
  208. {
  209. if(_pause)
  210. {
  211. Thread.Sleep(1000);
  212. }
  213. else
  214. {
  215. //dosomething
  216. }
  217. }
  218. 先findid,再setListener,因为初始化listener的时候,case里面的会执行
  219. ndk
  220. contentprovider
  221. 自定义控件
  222. 算法
  223. 设计模式
  224. 网络、握手
  225. jni
  226. 动画相关
  227. vpn
  228. aidl
  229. widget
  230. surfaceview 视频播放(多媒体)
  231. 多线程断点下载
  232. 底层源码
  233. openGL
  234. ImageLoader
  235. 安卓空格用\u3000
  236. looper、handler
  237. webview
  238. 按照这种方式启动的应用杀不死: system(am start -n 包名)
  239. kill pid才能杀死
  240. 这样获取sd卡路径:
  241. public static final String EXCEL_DIRECTORY = Environment.getExternalStorageDirectory().getPath() + "/questionnaire/paper/";
  242. 不要getAbsolutePath()
  243. 自己写一个ps命令,覆盖原有命令,不显示自己应用的pid,那么其他应用无法杀掉
  244. // 复制内容
  245. ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
  246. ClipData clip = ClipData.newPlainText("password", password);
  247. clipboard.setPrimaryClip(clip);
  248. 获取资源Id:
  249. int resId = getResources().getIdentifier(type, "drawable" , getPackageName());
  250. aidl
  251. messenger
  252. socket
  253. ndk
  254. contentprovider
  255. 通知+顽固service
  256. widget
  257. 会动的启动图标
  258. 换皮肤
  259. EventBus
  260. 自定义EmptyView
  261. View emptyView = LayoutInflater.from(getActivity()).inflate(R.layout.reload_layout, null);
  262. ((ViewGroup)mListView.getParent()).addView(emptyView);
  263. mListView.setEmptyView(emptyView);
  264. /**
  265. * 采用Pull解析XML内容
  266. */
  267. public class PULLPersonService {
  268. /**
  269. * 使用pull技术生成xml文件
  270. * @param persons
  271. * @param writer
  272. * @throws Throwable
  273. */
  274. public static void save(List<Person> persons, Writer writer) throws Throwable{
  275. XmlSerializer serializer = Xml.newSerializer();
  276. serializer.setOutput(writer);
  277. serializer.startDocument("UTF-8", true);
  278. serializer.startTag(null, "persons");
  279. for(Person person : persons){
  280. serializer.startTag(null, "person");
  281. serializer.attribute(null, "id", person.getId().toString());
  282. serializer.startTag(null, "name");
  283. serializer.text(person.getName());
  284. serializer.endTag(null, "name");
  285. serializer.startTag(null, "age");
  286. serializer.text(person.getAge().toString());
  287. serializer.endTag(null, "age");
  288. serializer.endTag(null, "person");
  289. }
  290. serializer.endTag(null, "persons");
  291. serializer.endDocument();
  292. writer.flush();
  293. writer.close();
  294. }
  295. /**
  296. * 使用pull技术解析xml
  297. * @param inStream
  298. * @return
  299. * @throws Throwable
  300. */
  301. public static List<Person> getPersons(InputStream inStream) throws Throwable{
  302. List<Person> persons = null;
  303. Person person = null;
  304. XmlPullParser parser = Xml.newPullParser();
  305. parser.setInput(inStream, "UTF-8");
  306. int eventType = parser.getEventType();//产生第一个事件
  307. while(eventType!=XmlPullParser.END_DOCUMENT){//只要不是文档结束事件
  308. switch (eventType) {
  309. case XmlPullParser.START_DOCUMENT:
  310. persons = new ArrayList<Person>();
  311. break;
  312. case XmlPullParser.START_TAG:
  313. String name = parser.getName();//获取解析器当前指向的元素的名称
  314. if("person".equals(name)){
  315. person = new Person();
  316. person.setId(new Integer(parser.getAttributeValue(0)));
  317. }
  318. if(person!=null){
  319. if("name".equals(name)){
  320. person.setName(parser.nextText());//获取解析器当前指向元素的下一个文本节点的值
  321. }
  322. if("age".equals(name)){
  323. person.setAge(new Short(parser.nextText()));
  324. }
  325. }
  326. break;
  327. case XmlPullParser.END_TAG:
  328. if("person".equals(parser.getName())){
  329. persons.add(person);
  330. person = null;
  331. }
  332. break;
  333. }
  334. eventType = parser.next();
  335. }
  336. return persons;
  337. }
  338. }