我是福景外国语学校2013届的学生,明年就要中考了,我在这里准备向群里的各位分享一些自己两年以来的经验以及推荐一些有用的学习书目,希望可以帮到大家~
语文:语文是一门需要下很大功夫的科目,不像数理化一样有固定的解题思路。怎么说呢,只要你肯多花时间折腾它,它对你来说就是小case,好了废话就不多说了下面进入正题:
①:语文的基础知识是最好拿分的地方,如果肯在这方面多下功夫那么选择题的10分就可以轻易拿到。这里推荐《语文中考全攻略》,这本书的知识非常前面,我建议是暑假就开始做,先从基础下手做,把易错的知识都专门记在一个本子上,茶余饭后都看看,基础的问题就应该不大了。 ②:语文的默写题目没有任何技术含量可言,就靠一个字——背。只要你肯下功夫去背,去记,那么我可以告诉你默写题的10分就相当于是免费送给你了。易错的字最好标记一下,复习的话可以找一个伙伴一起然后交换批改一下,自己写错了字自己是很难发现的,最好让别人帮你找出问题。
③:语文的文言文阅读明年好像是要考课外文言文,依照今年期末福田统考的课外文言文的难度来看应该不会特别难,我个人认为其实更可能出阅读对比类的题目,就是将两篇文言文进行对比考察之类的。文言文的得分率相较于默写和选择会稍微难一点,但是还是那句话,只要你肯下功夫,花心思去背、记,弄清楚每一个字词的含义,那么文言文对你来说就不是问题了。这里我不太赞成初三下学期之前花太多时间去刷课外文言文,毕竟课外文言文考察的知识应该都是课本这个范围,以本为本才是关键。这里推荐《深圳中考红宝书》、《中学文言文必考140字》
④现在来谈谈现代文阅读这个东西。我相信现代文阅读特别是文学类文本的阅读对于很多人来说都是一个硬伤吧?一开始我做阅读题也是完全凭感觉去做,看到了答案以后就发现原来和自己想的一模一样,这是为什么呢?我相信很多人都有跟我一样的感受,有时候想到点上了,就是不知道应该用什么语言来表述答案。我认为这是积累不足和应试技巧不够娴熟造成的。这里强烈推荐《读者》、《意林》、《青年文摘》!!!可以多读读上面的文章做做摘抄什么的,最好每天都要做,这样在考场上就不会“词穷”了。语文阅读的辅导书推荐《渔夫阅读》、《开心语文》系列的书。如果实在找不到感觉,我这里还有一个死马当活马医的极端方法,就是反复地做一篇阅读,不停地总结答案的规律,比如说赏析句子,我个人认为这是最容易的题目,一般从修辞角度下手最好。运用了XX的修辞手法,将XX比作XX,生动形象地写出了XXX。基本上这样就没什么问题了,但还是注意要看分值,如果分值较大可以考虑多写一写,比如说从表达方式和表现手法上面下手。慎用这种费时耗神的方法。 ⑤说起作文,我还是要强烈地推荐《读者》、《青年文摘》、《意林》!!!素材什么的从来都不愁!!!如果一定要去买什么作文辅导书的话个人建议不要买高考的。我看身边很多同学都爱买高考满分作文的辅导书,个人认为高考满分作文目前对我们来说没有任何益处。高考作文以议论文为主,中考作文主要是记叙文。上了高中以后你就算不想写议论文你也得写,这里有一个小建议,诸位可以拿往年的各省市中考作文题练练笔,然后再看看满分作文是怎么样的。 今天就分享这么多吧,明天再来和大家分享英语和数学。
今天咱来谈谈关于英语这一门学科。作为一名外国语学校的学生,英语是我最拿手的科目了。我个人认为英语是语数英三科中最好拿A+的科目,为啥呢?因为英语基本上都是选择题啊!主观题才25分啊!好了废话不多说下面进入正题:
①:先来说说听力吧。相信听力对于很多人来说都是一个很难跨越的门槛,特别是听短文回答问题对吧?刚升入初中的时候我英语也是徘徊在85分分左右,有一部分原因也是在这个上面栽了跟斗。目前来说,听力总分有15分,难度也主要集中在最后两题。第一题难度不大,只要达到两个层次5分就可以轻易拿到了。第一要听清,听清他说的每一个单词是什么。第二要听懂,听懂整个句子的意思以便选出最佳选项。这里推荐大家可以下载《VOA慢速英语》,最好试着自己跟读,因为中考英语是要考察听说的。第二题是根据对话回答问题,这一题的开放性很强,只要平时英语有积累的同学这一题应该不是问题。但是答这种题还是要注意语法和原则,每题只有一分,如果要语法错误基本上就不得分了。第三题是听短文回答问题,这个我建议大家在边听的时候要边做笔记,把重点都快速的记下来。一般是先读一遍短文再读一遍问题,如果在听的过程中漏记了内容的话不要着急去想,等放第二遍的时候多注意一下听漏的地方。最后一题看图说话,这一题就相当于小作文了,有4分的分值。注意一定不要偏题,偏题基本上扣分就是2分以上。最后给大家分享一下我的一些经验,作为一个经常听英文歌的人我听歌的时候都有一种记歌词的习惯。大家如果想挑战自己的极限可以去听听Hiphop的歌,也就是饶舌说唱,如果可以听清Hiphop的歌词那么你的听力就会十分强大了。
②:现在咱来谈谈单选题。单选题分为词语释义和补全句子两部分。这个就要看
课堂上的积累了,基本上只要上课好好听讲这15分是可以做到一分不扣的。这里推荐《深圳金卷》,《轻巧夺冠》和《中考易》,这三个系列的英语算是很赞的了,细节什么的也很全面,建议大家可以现在就开始做起。这里还建议大家可以配一个错题本,错题本是最宝贵的资源,考前盲目的复习书本还不如高效的复习错题本和笔记。我个人有一本名字叫“杂记”的本子,上面就记载了各种错题啊,经典例题啊,作文的好词好句啊,生词啊之类的。可惜的是搬家的时候这个本子被我弄不见了,当时还挺心疼的。
③:现在咱来谈谈完形填空和阅读理解。这两道题占45分的分值,算是英语考试里的重点了。我身边有许多同学都是输在了这上面,具体该怎么提分呢?重点还是在于语法和积累!这里推荐《星火英语》、《沸腾英语》。平时建议各位最好每天都抽出时间做一篇阅读,不要太多,就一篇。然后找出自己的错因,试着去总结。完形填空答题的时候注意结合上下文,如果考试时间允许的话做完以后最好再抽出时间重新看看。阅读理解题其实可以先看一遍题目然后再看文章,个人建议用排除法来做阅读理解题。每篇阅读理解遇到了生词一定要记下来!每天茶余饭后花时间去看。 ④语法填空也是在于平时的积累了,这里还是建议各位每天有时间可以做一做《深圳金卷》还有《中考易》什么的语法填空。有做错的地方记得一定要弄明白。这里提醒大家一件事,不要以为语法填空是每空一次,有时候遇到完成时或者被动语态的时候一定要特别注意一下。
⑤说起作文,我可以说英语作文比起语文作文简直是太简单了有木有!!我有一个学习特别好的姐姐曾经跟我说过这样一句话:“理科需要练习,文科需要积累。”作文想要在考场中脱颖而出还是挺难的。以下是我的一些经验:写作文一定要结
合材料或题目,不能偏题;不要试着故意凑字数而写一些没有实际意义的东西;平时可以多积累一些词组,举个例子,比如说‘I think’可以写成‘As far as i am concerd',关联词也要多积累一些;一定要把字写工整!!听老师说阅卷老师的平均阅卷时间只有45秒左右,很多时候给的分数可以说只是印象分,所以说一定要写好字!
现在我们来谈谈数学~数学是一门技术含量相当高的学科,数学最突出的特点就是高度概括和抽象。这种抽象的学科特点势必会给咱带来很多麻烦,所以说高考才有文理分科(我是不是扯远了)。在系统的分析之前我想先说一些个人的经验。 ①:不仅要刷题,还有学会总结思考。题海战术是一种费神耗时的方法,我个人不提倡这种方法。初一的时候苦于数学成绩提不上来,就每天都拿着好多本课外习题在做,结果效果还是不尽人意。所以我一直在思考一个问题,刷题究竟是让我们的学习事半功倍还是事倍功半?这个问题我想了两年,现在终于得到了一个稍微令我满意的答案:做题的效果取决于两点:做题的方法以及对习题的选择。怎么说呢?以前做题都是一味的猛刷,刷完就对答案,对完答案就不管了,其实这样做题不但一点都没有效果还会适得其反,为什么呢?原因如下:很多题目没有任何技术含量,一味地做这种题目只会浪费大量时间;很多题目所涉及的知识点我们已经掌握了,何必浪费时间去大量的做呢?初三的一个前辈曾经告诉跟我说过这样一句哈:“做题的时候要多做自己所不擅长的哪一类题,不要一味地各种做测试卷。请务必记住,如果要学好数学不是做什么题都能取得良好成效的。” 何为做题的方法呢?就是说要学会总结思考。在学而思上课的时候老师也一直在给咱灌输一个思想,即弄透一道题,会做一类题。数学学习尤其要学会总结,只有这样学过的东西才能算真正被消化吸收。我妈一个朋友的儿子曾经给过我极大的启发。他从小成绩就特别好,高三的时候就保送清华了。他跟我这样说过:“数学其实是考点最少的学科,题目的变化其实就是考点之间的转换。高等三角函数的考点只有不到10个,以此出的题目却有成百上千种。学数学,实质其实就培养转化题目的能力,把这个以前从没见过的题目转化成以前见过的题目,然后再
用你熟悉的方法解决它。”当时我就觉得特震撼,现在回头想想也不过就是那么回事。日常生活中我们经常会这样说授之以鱼不如授之以渔,只有学会了解题的方法才算学会数学。善于总结做题的方法,我觉得是学好数学最为关键的一点’ ②现在咱来谈谈第二点。很多数学底子不错的同学为什么成绩仍然上不去?有一点尤为重要,那就是忽视基础了。100分的试卷,你拼了全力把压轴题给做出来了,结果发现前面选择填空错了两个,94分;另外一个同学果断放弃压轴题最后一问,回头检查出了选择和填空的错误,97分。这就是不重视基础的下场。我相信很多学校应该都有一些这样的同学——他们“自我感觉良好”,不重视基础知识,不屑于解题的过程。喜欢专门跟难题对着干,结果往往最后考试却不能考出好成绩。我个人认为扎实的基础才是顺利做出难题的前提。就像上面那位清华的师兄说的一样,所谓的难题只不过是换了一种考法而已,考察的实际上就是转化问题的能力。所以说,只有在一开始把基础打好了才能保证自己考试可以取得优秀的成绩。
③现在来谈谈第三点~我个人认为这是学习数学中最不允许犯的两个错误。第一,重结果,轻过程;第二,不重视错题。相信很多同学曾经都跟我一样,因为过程被扣了不少分。很多数学思维很棒的同学,一下笔就丢分,这是为什么呢?这明显是不重视过程造成的结果。现在的数学考试都是踩点给分,如果你步骤不全也是要扣分的。初一的时候,我就有一个特别不好的习惯,也就是期末复习的时候,只顾着刷题,答案对了就不管了。结果呢,考试的时候就为此扣了4分。现在再来思考一个问题,我们刷题是为了什么?明显是为了学会方法对吧!很多同学期末复习的时候都为了应付老师就草草地把老师发的试卷写完了,这样没有任何效果。我思考了这个问题也挺久了,其实很多时候我们刷题都是为了获得一
种心理上的安慰,比如说像我一样,我就属于那种有强迫症的人,考前不做做题心里不舒服。思考了很久这个问题,现在终于可以得出一个可以稍微令我满意的答案——数学刷题是为了领悟解题思路和方法。再说说第二点。个人认为错题是数学学习中最宝贵的东西,错题本比任何辅导书都不知道好多少倍,不信可以去看看各位中高考状元都访谈,他们几乎都有记错题本的习惯。考前就拿着错题本来复习,整理每道题的思路和方法。如果有不懂的地方就及时去请教老师。因为一直坚持这样做,我在做数学题目的时候就很少遇到“被相同的石头绊倒”的情况。我相信如果你肯弄清楚每一个知识点,不断复习自己做错的题目,把那些模糊的知识点彻底弄懂,那么你的数学成绩就可以日见起色!
在Android系统中,提供了独特的匿名共享内存子系统Ashmem(Anonymous Shared Memory),它以驱动程序的形式实现在内核空间中。它有两个特点,一是能够辅助内存管理系统来有效地管理不再使用的内存块,二是它通过Binder进程间通信机制来实现进程间的内存共享。本文中,我们将通过实例来简要介绍Android系统的匿名共享内存的使用方法,使得我们对Android系统的匿名共享内存机制有一个感性的认识,为进一步学习它的源代码实现打下基础。
Android系统的匿名共享内存子系统的主体是以驱动程序的形式实现在内核空间的,同时,在系统运行时库层和应用程序框架层提供了访问接口,其中,在系统运行时库层提供了C/C++调用接口,而在应用程序框架层提供了Java调用接口。这里,我们将直接通过应用程序框架层提供的Java调用接口来说明匿名共享内存子系统Ashmem的使用方法,毕竟我们在Android开发应用程序时,是基于Java语言的,而实际上,应用程序框架层的Java调用接口是通过JNI方法来调用系统运行时库层的C/C++调用接口,最后进入到内核空间的Ashmem驱动程序去的。
我们在这里举的例子是一个名为Ashmem的应用程序,它包含了一个Server端和一个Client端实现,其中,Server端是以Service的形式实现的,在这里Service里面,创建一个匿名共享内存文件,而Client是一个Activity,这个Activity通过Binder进程间通信机制获得前面这个Service创建的匿名共享内存文件的句柄,从而实现共享。在Android应用程序框架层,提供了一个MemoryFile接口来封装了匿名共享内存文件的创建和使用,它实现在frameworks/base/core/java/android/os/MemoryFile.java文件中。下面,我们就来看看Server端是如何通过MemoryFile类来创建匿名共享内存文件的以及Client是如何获得这个匿名共享内存文件的句柄的。
在MemoryFile类中,提供了两种创建匿名共享内存的方法,我们通过MemoryFile类的构造函数来看看这两种使用方法:
view plain
1. public class MemoryFile
2. {
3. ......
4.
5. /**
6. * Allocates a new ashmem region. The region is initially not purgable.
7. *
8. * @param name optional name for the file (can be null).
9. * @param length of the memory file in bytes.
10. * @throws IOException if the memory file could not be created.
11. */
12. public MemoryFile(String name, int length) throws IOException {
13. mLength = length;
14. mFD = native_open(name, length);
15. mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE);
16. mOwnsRegion = true;
17. }
18.
19. /**
20. * Creates a reference to an existing memory file. Changes to the original file
21. * will be available through this reference.
22. * Calls to {@link #allowPurging(boolean)} on the returned MemoryFile will fail.
23. *
24. * @param fd File descriptor for an existing memory file, as returned by
25. * {@link #getFileDescriptor()}. This file descriptor will be closed
26. * by {@link #close()}.
27. * @param length Length of the memory file in bytes.
28. * @param mode File mode. Currently only "r" for read-only access is supported.
29. * @throws NullPointerException if <code>fd</code> is null.
30. * @throws IOException If <code>fd</code> does not refer to an existing memory file,
31. * or if the file mode of the existing memory file is more restrictive
32. * than <code>mode</code>.
33. *
34. * @hide
35. */
36. public MemoryFile(FileDescriptor fd, int length, String mode) throws IOException {
37. if (fd == null) {
38. throw new NullPointerException("File descriptor is null.");
39. }
40. if (!isMemoryFile(fd)) {
41. throw new IllegalArgumentException("Not a memory file.");
42. }
43. mLength = length;
44. mFD = fd;
45. mAddress = native_mmap(mFD, length, modeToProt(mode));
46. mOwnsRegion = false;
47. }
48.
49. ......
50. }
从注释中,我们可以看出这两个构造函数的使用方法,这里就不再详述了。两个构造函数的主要区别是第一个参数,第一种构造方法是以指定的字符串调用JNI方法native_open来创建一个匿名共享内存文件,从而得到一个文件描述符,接着就以这个文件描述符为参数调用JNI方法natvie_mmap把这个匿名共享内存文件映射在进程空间中,然后就可以通过这个映射后得到的地址空间来直接访问内存数据了;第二种构造方法是以指定的文件描述符来直接调用JNI方法natvie_mmap把这个匿名共享内存文件映射在进程空间中,然后进行访问,而这个文件描述符就必须要是一个匿名共享内存文件的文件描述符,这是通过一个内部函数isMemoryFile来验证的,而这个内部函数isMemoryFile也是通过JNI方法调用来进一步验证的。前面所提到的这些JNI方法调用,最终都是通过系统运行时库层进入到内核空间的Ashmem驱动程序中去,不过这里我们不关心这些JNI方法、系统运行库层调用以及Ashmem驱动程序的具体实现,在接下来的两篇文章中,我们将会着重介绍,这里我们只关注MemoryFile这个类的使用方法。
前面我们说到,我们在这里举的例子包含了一个Server端和一个Client端实现,其中, Server端就是通过前面一个构造函数来创建一个匿名共享内存文件,接着,Client端过Binder进程间通信机制来向Server请求这个匿名共享内存的文件描述符,有了这个文件描述符之后,就可以通过后面一个构造函数来共享这个内存文件了。
因为涉及到Binder进程间通信,我们首先定义好Binder进程间通信接口。Binder进程间通信机制的相关介绍,请参考前面一篇文章Android进程间通信(IPC)机制Binder简要介绍和学习计划,这里就不详细介绍了,直接进入主题。
首先在源代码工程的packages/experimental目录下创建一个应用程序工程目录Ashmem。关于如何获得Android源代码工程,请参考在Ubuntu上下载、编译和安装Android最新源代码一文;关于如何在Android源代码工程中创建应用程序工程,请参考在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务一文。这里,工程名称就是Ashmem了,它定义了一个路径为shy.luo.ashmem的package,这个例子的源代码主要就是实现在这里了。下面,将会逐一介绍这个package里面的文件。
这里要用到的Binder进程间通信接口定义在src/shy/luo/ashmem/IMemoryService.java文件中:
view plain
1. package shy.luo.ashmem;
2.
3. import android.util.Log;
4. import android.os.IInterface;
5. import android.os.Binder;
6. import android.os.IBinder;
7. import android.os.Parcel;
8. import android.os.ParcelFileDescriptor;
9. import android.os.RemoteException;
10.
11. public interface IMemoryService extends IInterface {
12. public static abstract class Stub extends Binder implements IMemoryService {
13. private static final String DESCRIPTOR = "shy.luo.ashmem.IMemoryService";
14.
15. public Stub() {
16. attachInterface(this, DESCRIPTOR);
17. }
18.
19. public static IMemoryService asInterface(IBinder obj) {
20. if (obj == null) {
21. return null;
22. }
23.
24. IInterface iin = (IInterface)obj.queryLocalInterface(DESCRIPTOR);
25. if (iin != null && iin instanceof IMemoryService) {
26. return (IMemoryService)iin;
27. }
28.
29. return new IMemoryService.Stub.Proxy(obj);
30. }
31.
32. public IBinder asBinder() {
33. return this;
34. }
35.
36. @Override
37. public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException {
38. switch (code) {
39. case INTERFACE_TRANSACTION: {
40. reply.writeString(DESCRIPTOR);
41. return true;
42. }
43. case TRANSACTION_getFileDescriptor: {
44. data.enforceInterface(DESCRIPTOR);
45.
46. ParcelFileDescriptor result = this.getFileDescriptor();
47.
48. reply.writeNoException();
49.
50. if (result != null) {
51. reply.writeInt(1);
52. result.writeToParcel(reply, 0);
53. } else {
54. reply.writeInt(0);
55. }
56.
57. return true;
58. }
59. case TRANSACTION_setValue: {
60. data.enforceInterface(DESCRIPTOR);
61.
62. int val = data.readInt();
63. setValue(val);
64.
65. reply.writeNoException();
66.
67. return true;
68. }
69. }
70.
71. return super.onTransact(code, data, reply, flags);
72. }
73.
74. private static class Proxy implements IMemoryService {
75. private IBinder mRemote;
76.
77. Proxy(IBinder remote) {
78. mRemote = remote;
79. }
80.
81. public IBinder asBinder() {
82. return mRemote;
83. }
84.
85. public String getInterfaceDescriptor() {
86. return DESCRIPTOR;
87. }
88.
89. public ParcelFileDescriptor getFileDescriptor() throws RemoteException {
90. Parcel data = Parcel.obtain();
91. Parcel reply = Parcel.obtain();
92.
93. ParcelFileDescriptor result;
94.
95. try {
96. data.writeInterfaceToken(DESCRIPTOR);
97.
98. mRemote.transact(Stub.TRANSACTION_getFileDescriptor, data, reply, 0);
99.
100. reply.readException();
101. if (0 != reply.readInt()) {
102. result = ParcelFileDescriptor.CREATOR.createFromParcel(reply);
103. } else {
104. result = null;
105. }
106. } finally {
107. reply.recycle();
108. data.recycle();
109. }
110.
111. return result;
112. }
113.
114. public void setValue(int val) throws RemoteException {
115. Parcel data = Parcel.obtain();
116. Parcel reply = Parcel.obtain();
117.
118. try {
119. data.writeInterfaceToken(DESCRIPTOR);
120. data.writeInt(val);
121.
122. mRemote.transact(Stub.TRANSACTION_setValue, data, reply, 0);
123.
124. reply.readException();
125. } finally {
126. reply.recycle();
127. data.recycle();
128. }
129. }
130. }
131.
132. static final int TRANSACTION_getFileDescriptor = IBinder.FIRST_CALL_TRANSACTION + 0;
133. static final int TRANSACTION_setValue = IBinder.FIRST_CALL_TRANSACTION + 1;
134.
135. }
136.
137. public ParcelFileDescriptor getFileDescriptor() throws RemoteException;
138. public void setValue(int val) throws RemoteException;
139. }
这里主要是定义了IMemoryService接口,它里面有两个调用接口:
view plain
1. public ParcelFileDescriptor getFileDescriptor() throws RemoteException;
2. public void setValue(int val) throws RemoteException;
同时,还分别定义了用于Server端实现的IMemoryService.Stub基类和用于Client端使用的代理IMemoryService.Stub.Proxy类。关于Binder进程间通信机制在应用程序框架层的Java接口定义,请参考前面Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析一文。
有了Binder进程间通信接口之后,接下来就是要在Server端实现一个本地服务了。这里,Server端实现的本地服务名为MemoryService,实现在src/shy/luo/ashmem/MemoryService.java文件中:
view plain
1. package shy.luo.ashmem;
2.
3. import java.io.FileDescriptor;
4. import java.io.IOException;
5.
6. import android.os.Parcel;
7. import android.os.MemoryFile;
8. import android.os.ParcelFileDescriptor;
9. import android.util.Log;
10.
11. public class MemoryService extends IMemoryService.Stub {
12. private final static String LOG_TAG = "shy.luo.ashmem.MemoryService";
13. private MemoryFile file = null;
14.
15. public MemoryService() {
16. try {
17. file = new MemoryFile("Ashmem", 4);
18. setValue(0);
19. }
20. catch(IOException ex) {
21. Log.i(LOG_TAG, "Failed to create memory file.");
22. ex.printStackTrace();
23. }
24. }
25.
26. public ParcelFileDescriptor getFileDescriptor() {
27. Log.i(LOG_TAG, "Get File Descriptor.");
28.
29. ParcelFileDescriptor pfd = null;
30.
31. try {
32. pfd = file.getParcelFileDescriptor();
33. } catch(IOException ex) {
34. Log.i(LOG_TAG, "Failed to get file descriptor.");
35. ex.printStackTrace();
36. }
37.
38. return pfd;
39. }
40.
41. public void setValue(int val) {
42. if(file == null) {
43. return;
44. }
45.
46. byte[] buffer = new byte[4];
47. buffer[0] = (byte)((val >>> 24) & 0xFF);
48. buffer[1] = (byte)((val >>> 16) & 0xFF);
49. buffer[2] = (byte)((val >>> 8) & 0xFF);
50. buffer[3] = (byte)(val & 0xFF);
51.
52. try {
53. file.writeBytes(buffer, 0, 0, 4);
54. Log.i(LOG_TAG, "Set value " + val + " to memory file. ");
55. }
56. catch(IOException ex) {
57. Log.i(LOG_TAG, "Failed to write bytes to memory file.");
58. ex.printStackTrace();
59. }
60. }
61. }
注意,这里的MemoryService类实现了IMemoryService.Stub类,表示这是一个Binder服务的本地实现。在构造函数中,通过指定文件名和文件大小来创建了一个匿名共享内存文件,即创建MemoryFile的一个实例,并保存在类成员变量file中。这个匿名共享内存文件名为"Ashmem",大小为4个节字,刚好容纳一个整数,我们这里举的例子就是要说明如果创建一个匿名共享内存来在两个进程间实现共享一个整数了。当然,在实际应用中,可以根据需要创建合适大小的共享内存来共享有意义的数据。
这里还实现了IMemoryService.Stub的两个接口getFileDescriptor和setVal,一个用来获取匿名共享内存文件的文件描述符,一个来往匿名共享内存文件中写入一个整数,其中,接口getFileDescriptor的返回值是一个ParcelFileDescriptor。在Java中,是用FileDescriptor类来表示一个文件描述符的,而ParcelFileDescriptor是用来序列化FileDescriptor的,以便在进程间调用时传输。
定义好本地服务好,就要定义一个Server来启动这个服务了。这里定义的Server实现在src/shy/luo/ashmem/Server.java文件中:
view plain
1. package shy.luo.ashmem;
2.
3. import android.app.Service;
4. import android.content.Intent;
5. import android.os.IBinder;
6. import android.util.Log;
7. import android.os.ServiceManager;
8.
9. public class Server extends Service {
10. private final static String LOG_TAG = "shy.luo.ashmem.Server";
11.
12. private MemoryService memoryService = null;
13.
14. @Override
15. public IBinder onBind(Intent intent) {
16. return null;
17. }
18.
19. @Override
20. public void onCreate() {
21. Log.i(LOG_TAG, "Create Memory Service...");
22.
23. memoryService = new MemoryService();
24.
25. try {
26. ServiceManager.addService("AnonymousSharedMemory", memoryService);
27. Log.i(LOG_TAG, "Succeed to add memory service.");
28. } catch (RuntimeException ex) {
29. Log.i(LOG_TAG, "Failed to add Memory Service.");
30. ex.printStackTrace();
31. }
32.
33. }
34.
35. @Override
36. public void onStart(Intent intent, int startId) {
37. Log.i(LOG_TAG, "Start Memory Service.");
38. }
39.
40. @Override
41. public void onDestroy() {
42. Log.i(LOG_TAG, "Destroy Memory Service.");
43. }
44. }
这个Server继承了Android系统应用程序框架层提供的Service类,当它被启动时,运行在一个独立的进程中。当这个Server被启动时,它的onCreate函数就会被调用,然后它就通过ServiceManager的addService接口来添加MemoryService了:
view plain
1. memoryService = new MemoryService();
2.
3. try {
4. ServiceManager.addService("AnonymousSharedMemory", memoryService);
5. Log.i(LOG_TAG, "Succeed to add memory service.");
6. } catch (RuntimeException ex) {
7. Log.i(LOG_TAG, "Failed to add Memory Service.");
8. ex.printStackTrace();
9. }
这样,当这个Server成功启动了,Client就可以通过ServiceManager的getService接口来获取这个MemoryService了。
接着,我们就来看Client端的实现。Client端是一个Activity,实现在src/shy/luo/ashmem/Client.java文件中:
view plain
1. package shy.luo.ashmem;
2.
3. import java.io.FileDescriptor;
4. import java.io.IOException;
5.
6. import shy.luo.ashmem.R;
7. import android.app.Activity;
8. import android.content.Intent;
9. import android.os.Bundle;
10. import android.os.MemoryFile;
11. import android.os.ParcelFileDescriptor;
12. import android.os.ServiceManager;
13. import android.os.RemoteException;
14. import android.util.Log;
15. import android.view.View;
16. import android.view.View.OnClickListener;
17. import android.widget.Button;
18. import android.widget.EditText;
19.
20. public class Client extends Activity implements OnClickListener {
21. private final static String LOG_TAG = "shy.luo.ashmem.Client";
22.
23. IMemoryService memoryService = null;
24. MemoryFile memoryFile = null;
25.
26. private EditText valueText = null;
27. private Button readButton = null;
28. private Button writeButton = null;
29. private Button clearButton = null;
30.
31. @Override
32. public void onCreate(Bundle savedInstanceState) {
33. super.onCreate(savedInstanceState);
34. setContentView(R.layout.main);
35.
36. IMemoryService ms = getMemoryService();
37. if(ms == null) {
38. startService(new Intent("shy.luo.ashmem.server"));
39. } else {
40. Log.i(LOG_TAG, "Memory Service has started.");
41. }
42.
43. valueText = (EditText)findViewById(R.id.edit_value);
44. readButton = (Button)findViewById(R.id.button_read);
45. writeButton = (Button)findViewById(R.id.button_write);
46. clearButton = (Button)findViewById(R.id.button_clear);
47.
48. readButton.setOnClickListener(this);
49. writeButton.setOnClickListener(this);
50. clearButton.setOnClickListener(this);
51.
52. Log.i(LOG_TAG, "Client Activity Created.");
53. }
54.
55. @Override
56. public void onResume() {
57. super.onResume();
58.
59. Log.i(LOG_TAG, "Client Activity Resumed.");
60. }
61.
62. @Override
63. public void onPause() {
64. super.onPause();
65.
66. Log.i(LOG_TAG, "Client Activity Paused.");
67. }
68.
69. @Override
70. public void onClick(View v) {
71. if(v.equals(readButton)) {
72. int val = 0;
73.
74. MemoryFile mf = getMemoryFile();
75. if(mf != null) {
76. try {
77. byte[] buffer = new byte[4];
78. mf.readBytes(buffer, 0, 0, 4);
79.
80. val = (buffer[0] << 24) | ((buffer[1] & 0xFF) << 16) | ((buffer[2] & 0xFF) << 8) | (buffer[3] & 0xFF);
81. } catch(IOException ex) {
82. Log.i(LOG_TAG, "Failed to read bytes from memory file.");
83. ex.printStackTrace();
84. }
85. }
86.
87. String text = String.valueOf(val);
88. valueText.setText(text);
89. } else if(v.equals(writeButton)) {
90. String text = valueText.getText().toString();
91. int val = Integer.parseInt(text);
92.
93. IMemoryService ms = getMemoryService();
94. if(ms != null) {
95. try {
96. ms.setValue(val);
97. } catch(RemoteException ex) {
98. Log.i(LOG_TAG, "Failed to set value to memory service.");
99. ex.printStackTrace();
100. }
101. }
102. } else if(v.equals(clearButton)) {
103. String text = "";
104. valueText.setText(text);
105. }
106. }
107.
108. private IMemoryService getMemoryService() {
109. if(memoryService != null) {
110. return memoryService;
111. }
112.
113. memoryService = IMemoryService.Stub.asInterface(
114. ServiceManager.getService("AnonymousSharedMemory"));
115.
116. Log.i(LOG_TAG, memoryService != null ? "Succeed to get memeory service." : "Failed to get memory service.");
117.
118. return memoryService;
119. }
120.
121. private MemoryFile getMemoryFile() {
122. if(memoryFile != null) {
123. return memoryFile;
124. }
125.
126. IMemoryService ms = getMemoryService();
127. if(ms != null) {
128. try {
129. ParcelFileDescriptor pfd = ms.getFileDescriptor();
130. if(pfd == null) {
131. Log.i(LOG_TAG, "Failed to get memory file descriptor.");
132. return null;
133. }
134.
135. try {
136. FileDescriptor fd = pfd.getFileDescriptor();
137. if(fd == null) {
138. Log.i(LOG_TAG, "Failed to get memeory file descriptor.");
139. return null;
140. }
141.
142. memoryFile = new MemoryFile(fd, 4, "r");
143. } catch(IOException ex) {
144. Log.i(LOG_TAG, "Failed to create memory file.");
145. ex.printStackTrace();
146. }
147. } catch(RemoteException ex) {
148. Log.i(LOG_TAG, "Failed to get file descriptor from memory service.");
149. ex.printStackTrace();
150. }
151. }
152.
153. return memoryFile;
154. }
155. }
Client端的界面主要包含了三个按钮Read、Write和Clear,以及一个用于显示内容的文本框。
这个Activity在onCreate时,会通过startService接口来启动我们前面定义的Server进程。调用startService时,需要指定要启动的服务的名称,这里就是"shy.luo.ashmem.server"了,后面我们会在程序的描述文件AndroidManifest.xml看到前面的Server类是如何和名称"shy.luo.ashmem.server"关联起来的。关于调用startService函数来启动自定义服务的过程,可以参考Android系统在新进程中启动自定义服务过程(startService)的原理分析一文。
内部函数getMemoryService用来获取IMemoryService。如果是第一次调用该函数,则会通过ServiceManager的getService接口来获得这个IMemoryService接口,然后保存在类成员变量memoryService中,以后再调用这个函数时,就可以直接返回memoryService了。
内部函数getMemoryFile用来从MemoryService中获得匿名共享内存文件的描述符。同样,如果是第一次调用该函数,则会通过IMemoryService的getFileDescriptor接口来获得MemoryService中的匿名共享内存文件的描述符,然后用这个文件描述符来创建一个MemoryFile实例,并保存在类成员变量memoryFile中,以后再调用这个函数时,就可以直接返回memoryFile了。
有了memoryService和memoryFile后,我们就可以在Client端访问Server端创建的匿名共享内存了。点击Read按钮时,就通过memoryFile的readBytes接口把共享内存中的整数读出来,并显示在文本框中;点击Write按钮时,就通过memoryService这个代理类的setVal接口来调用MemoryService的本地实现类的setVal服务,从而把文本框中的数值写到Server端创建的匿名共享内存中去;点击Clear按钮时,就会清空文本框的内容。这样,我们就可以通过Read和Write按钮来验证我们是否在Client和Server两个进程中实现内存共享了。
现在,我们再来看看Client界面的配置文件,它定义在res/layout/main.xml文件中:
view plain
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. >
7. <LinearLayout
8. android:layout_width="fill_parent"
9. android:layout_height="wrap_content"
10. android:orientation="vertical"
11. android:gravity="center">
12. <TextView
13. android:layout_width="wrap_content"
14. android:layout_height="wrap_content"
15. android:text="@string/value">
16. </TextView>
17. <EditText
18. android:layout_width="fill_parent"
19. android:layout_height="wrap_content"
20. android:id="@+id/edit_value"
21. android:hint="@string/hint">
22. </EditText>
23. </LinearLayout>
24. <LinearLayout
25. android:layout_width="fill_parent"
26. android:layout_height="wrap_content"
27. android:orientation="horizontal"
28. android:gravity="center">
29. <Button
30. android:id="@+id/button_read"
31. android:layout_width="wrap_content"
32. android:layout_height="wrap_content"
33. android:text="@string/read">
34. </Button>
35. <Button
36. android:id="@+id/button_write"
37. android:layout_width="wrap_content"
38. android:layout_height="wrap_content"
39. android:text="@string/write">
40. </Button>
41. <Button
42. android:id="@+id/button_clear"
43. android:layout_width="wrap_content"
44. android:layout_height="wrap_content"
45. android:text="@string/clear">
46. </Button>
47. </LinearLayout>
48. </LinearLayout>
相关的字符串定义在res/values/strings.xml文件中:
view plain
1. <?xml version="1.0" encoding="utf-8"?>
2. <resources>
3. <string name="app_name">Ashmem</string>
4. <string name="value">Value</string>
5. <string name="hint">Please input a value...</string>
6. <string name="read">Read</string>
7. <string name="write">Write</string>
8. <string name="clear">Clear</string>
9. </resources>
这样,界面的相关配置文件就介绍完了。
我们还要再来看程序描述文件AndroidManifest.xml的相关配置,它位于Ashmem目录下:
view plain
1. <?xml version="1.0" encoding="utf-8"?>
2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3. package="shy.luo.ashmem"
4. android:sharedUserId="android.uid.system"
5. android:versionCode="1"
6. android:versionName="1.0">
7. <application android:icon="@drawable/icon" android:label="@string/app_name">
8. <activity android:name=".Client"
9. android:label="@string/app_name">
10. <intent-filter>
11. <action android:name="android.intent.action.MAIN" />
12. <category android:name="android.intent.category.LAUNCHER" />
13. </intent-filter>
14. </activity>
15. <service
16. android:enabled="true"
17. android:name=".Server"
18. android:process=".Server" >
19. <intent-filter>
20. <action android:name="shy.luo.ashmem.server"/>
21. <category android:name="android.intent.category.DEFAULT"/>
22. </intent-filter>
23. </service>
24. </application>
25. </manifest>
这里我们可以看到,下面的配置项把服务名称"shy.luo.ashmem.server"和本地服务类Server关联了起来:
view plain
1. <service
2. android:enabled="true"
3. android:name=".Server"
4. android:process=".Server" >
5. <intent-filter>
6. <action android:name="shy.luo.ashmem.server"/>
7. <category android:name="android.intent.category.DEFAULT"/>
8. </intent-filter>
9. </service>
这样,我们就可以通过startService(new Intent("shy.luo.ashmem.server"))来启动这个Server了。不过,在Android中,启动服务是需要权限的,所以,下面这一行配置获取了启动服务需要的相应权限:
view plain
1. android:sharedUserId="android.uid.system"
最后,我们来看工程的编译脚本文件Android.mk,它位于Ashmem目录下:
view plain
1. LOCAL_PATH:= $(call my-dir)
2. include $(CLEAR_VARS)
3.
4. LOCAL_MODULE_TAGS := optional
5.
6. LOCAL_SRC_FILES += $(call all-subdir-java-files)
7.
8. LOCAL_PACKAGE_NAME := Ashmem
9.
10. LOCAL_CERTIFICATE := platform
11.
12. include $(BUILD_PACKAGE)
这里又有一个关键的地方:
view plain
1. LOCAL_CERTIFICATE := platform
因为我们需要在程序中启动Service,所以要配置这一行,并且要把源代码工程放在Android源代码平台中进行编译。
这样,整个例子的源代码实现就介绍完了,接下来就要编译了。有关如何单独编译Android源代码工程的模块,以及如何打包system.img,请参考如何单独编译Android源代码中的模块一文。
执行以下命令进行编译和打包:
view plain
1. USER-NAME@MACHINE-NAME:~/Android$ mmm packages/experimental/Ashmem
2. USER-NAME@MACHINE-NAME:~/Android$ make snod
这样,打包好的Android系统镜像文件system.img就包含我们前面创建的Ashmem应用程序了。
再接下来,就是运行模拟器来运行我们的例子了。关于如何在Android源代码工程中运行模拟器,请参考在Ubuntu上下载、编译和安装Android最新源代码一文。
执行以下命令启动模拟器:
view plain
1. USER-NAME@MACHINE-NAME:~/Android$ emulator
模拟器启动起,就可以在Home Screen上看到Ashmem应用程序图标了:
点击Ashmem图标,启动Ashmem应用程序,界面如下:
这样,我们就可以验证程序的功能了,看看是否实现了在两个进程中通过使用Android系统的匿名共享内存机制来共享内存数据的功能。
通过这个例子的学习,相信读者对Android系统匿名共享内存子系统Ashmem有了一个大概的认识,但是,这种认识还是停留在表面上。我们在文章开始时就提到,Android系统匿名共享内存子系统Ashmem两个特点,一是能够辅助内存管理系统来有效地管理不再使用的内存块,二是它通过Binder进程间通信机制来实现进程间的内存共享。第二个特点我们在上面这个例子中看到了,但是似乎还不够深入,我们知道,在Linux系统中,文件描述符其实就是一个整数,它是用来索引进程保存在内核空间的打开文件数据结构的,而且,这个文件描述符只是在进程内有效,也就是说,在不同的进程中,相同的文件描述符的值,代表的可能是不同的打开文件,既然是这样,把Server进程中的文件描述符传给Client进程,似乎就没有用了,但是不用担心,在传输过程中,Binder驱动程序会帮我们处理好一切,保证Client进程拿到的文件描述符是在本进程中有效的,并且它指向就是Server进程创建的匿名共享内存文件。至于第一个特点,我们也准备在后续学习Android系统匿名共享内存子系统Ashmem时,再详细介绍。
因此,为了深入了解Android系统匿名共享内存子系统Ashmem,在接下来的两篇文章中,围绕上面提到的两个特点,分别学习:
1. Android系统匿名共享内存子系统Ashmem是如何够辅助内存管理系统来有效地管理不再使用的内存块的?
2. Android系统匿名共享内存子系统Ashmem是如何通过Binder进程间通信机制来实现进程间的内存共享的?
学习完这两篇文章后,相信大家对 Android系统匿名共享内存子系统Ashmem就会有一个更深刻的认识了,敬请关注。
Memo范文1说明性memoMemorandumToAllemployeesofCarsonBankFromRobertDicki…
样题YouaretheManagingDirectorofacompanywhoseprofitshaverecentlyincr…
Memosampleletters1告知信息类例题YouareamanageratanauditorscalledGoldinga…
SituationFloydJonesistheproprietorofthefirmforwhichyouworkMrJoneswantstoacq…
洛香镇中心小学“多彩贵州文明行动”工作总结一年来,在上级主管部门的正确领导下下,我校“多彩贵州文明行动”工作按照“统一领导、分级负…
“三要素六环节”课堂教学模式总结报告一、提出背景1、创新人才培养模式,打造高效课堂,提高教学效率,推进素质教育是新世纪时代发展的必…
200xx年工会换届工作总结各位领导老师们:我们这一届工会委员会自20xx年x月份开展工作至今,任期已经三年了,根据《新工会法》,…
从女生部成立以来,各级领导和老师们都时刻关心着我们的成长,正因为我们迈出了前所未有的一步,正因为我们肩负着开拓创新的重担,我们的将…
工作总结转眼间,我加入xxxx这个大家庭已有半年时间,进入技术小组也近3个月余,我感觉自己很幸运,在技术小组成立之初就加入其中,可…