首页 文章 精选 留言 我的

精选列表

搜索[移动解析],共10000篇文章
优秀的个人博客,低调大师

extern "C"的用法解析

1.引言 C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同。作为一种欲与C兼容的语言, C++保留了一部分过程式语言的特点(被世人称为“不彻底地面向对象”),因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序设计语言 ,为了支持函数的重载,C++对全局函数的处理方式与C有明显的不同。 2. 从标准头文件说起 某企业曾经给出如下的一道面试题: 面试题 为什么标准头文件都有类似以下的结构? #ifndef __INCvxWorksh #define __INCvxWorksh #ifdef __cplusplus extern "C" { #endif /*...*/ #ifdef __cplusplus } #endif #endif /* __INCvxWorksh */ 分析 显然,头文件中的编译宏“#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif”的作用是防止该头文件被重复引用。 那么 #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif 的作用又是什么呢?我们将在下文一一道来。 3. 深层揭密 extern "C" extern "C"包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。让我们来详细解读这两重含义。 被extern "C"限定的函数或变量是extern类型的; extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。记住,下列语句: extern int a; 仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数。 与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。 被extern "C"修饰的变量和函数是按照C语言方式编译和连接的; 未加extern “C”声明时的编译方式 首先看看C++中对类似C的函数是怎样编译的。 作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为: void foo( int x, int y ); 该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。 _foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。 同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。 未加extern "C"声明时的连接方式 假设在C++中,模块A的头文件如下: //模块A头文件 moduleA.h #ifndef MODULE_A_H #define MODULE_A_H int foo( int x, int y ); #endif 在模块B中引用该函数: //模块B实现文件 moduleB.cpp #include "moduleA.h" foo(2,3); 实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号! 加extern "C"声明后的编译和连接方式 加extern "C"声明后,模块A的头文件变为: //模块A头文件 moduleA.h #ifndef MODULE_A_H #define MODULE_A_H extern "C" int foo( int x, int y ); #endif 在模块B的实现文件中仍然调用foo( 2,3 ),其结果是: (1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式; (2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。 如果在模块A中函数声明了foo为extern "C"类型,而模块B中包含的是extern int foo( int x, int y ),则模块B找不到模块A中的函数;反之亦然。 所以,可以用一句话概括extern “C”这个声明的真实目的(任何语言中的任何语法特性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入地理解许多问题): 实现C++与C及其它语言的混合编程。 明白了C++中extern "C"的设立动机,我们下面来具体分析extern "C"通常的使用技巧。 4.extern "C" 的惯用法 (1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理: extern "C" { #include "cExample.h" } 而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。 笔者编写的C++引用C函数例子工程中包含的三个文件的源代码如下: /* c语言头文件:cExample.h */ #ifndef C_EXAMPLE_H #define C_EXAMPLE_H extern int add(int x,int y);//注:写成extern "C" int add(int , int ); 也可以 #endif /* c语言实现文件:cExample.c */ #include "cExample.h" int add( int x, int y ) { return x + y; } // c++实现文件,调用add:cppFile.cpp extern "C" { #include "cExample.h"//注:此处不妥,如果这样编译通不过,换成 extern "C" int add(int , int ); 可以通过 } int main(int argc, char* argv[]) { add(2,3); return 0; } 如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C" { }。 (2)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,应该仅将C文件中将C++中定义的extern "C"函数声明为extern类型。 笔者编写的C引用C++函数例子工程中包含的三个文件的源代码如下: //C++头文件cppExample.h #ifndef CPP_EXAMPLE_H #define CPP_EXAMPLE_H extern "C" int add( int x, int y ); #endif //C++实现文件cppExample.cpp #include "cppExample.h" int add( int x, int y ) { return x + y; } /* C实现文件cFile.c /*这样会编译出错:#include "cExample.h" */ extern int add( int x, int y ); int main( int argc, char* argv[] ) { add( 2, 3 ); return 0; } 如果深入理解了第3节中所阐述的extern "C"在编译和连接阶段发挥的作用,就能真正理解本节所阐述的从C++引用C函数和C引用C++函数的惯用法。对第4节给出的示例代码,需要特别留意各个细节。 ============================================================================== 本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2012/03/20/2409046.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

C#事件(event)解析

原文:http://www.cnblogs.com/michaelxu/archive/2008/04/02/1134217.html 事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂。而这些东西却往往又是编程中常用且非常重要的东西。大家都知道windows消息处理机制的重要,其实C#事件就是基于windows消息处理机制的,只是封装的更好,让开发者无须知道底层的消息处理机制,就可以开发出强大的基于事件的应用程序来。 先来看看事件编程有哪些好处。 在以往我们编写这类程序中,往往采用等待机制,为了等待某件事情的发生,需要不断地检测某些判断变量,而引入事件编程后,大大简化了这种过程: - 使用事件,可以很方便地确定程序执行顺序。 - 当事件驱动程序等待事件时,它不占用很多资源。事件驱动程序与过程式程序最大的不同就在于,程序不再不停地检查输入设备,而是呆着不动,等待消息的到来,每个输入的消息会被排进队列,等待程序处理它。如果没有消息在等待,则程序会把控制交回给操作系统,以运行其他程序。 - 事件简化了编程。操作系统只是简单地将消息传送给对象,由对象的事件驱动程序确定事件的处理方法。操作系统不必知道程序的内部工作机制,只是需要知道如何与对象进行对话,也就是如何传递消息。 有了这么多好处,看来我们的确有必要掌握它。俗话说:“难了不会,会了不难”。就让我们一步一步开始吧... 要讲事件,必然要讲到委托(delegate)。它们之间的关系可以通过一个浅显的比方来说明,这个比方可能不是十分恰当。比如你要租一个房屋,这是一个事件,那么委托就是房屋租赁中介,当你把租房子的消息告知中介后,中介就会产生出一套符合你要求的房屋租赁方案来。再由中介执行这套方案,你便租得了这个房屋,即事件被处理了。当然你也可以不通过中介,直接找房东,但如果没有互联网等工具,你如何得到谁出租房屋的信息?话题扯远了。 委托(delegate) 委托可以理解成为函数指针,不同的是委托是面向对象,而且是类型安全的。关于委托的理解,可以参考我的另一篇文章《C#委托之个人理解》。 事件(event) 我们可以把事件编程简单地分成两个部分:事件发生的类(书面上叫事件发生器)和事件接收处理的类。事件发生的类就是说在这个类中触发了一个事件,但这个类并不知道哪个个对象或方法将会加收到并处理它触发的事件。所需要的是在发送方和接收方之间存在一个媒介。这个媒介在.NET Framework中就是委托(delegate)。在事件接收处理的类中,我们需要有一个处理事件的方法。好了,我们就按照这个顺序来实现一个捕获键盘按键的程序,来一步一步说明如何编写事件应用程序。 1、首先创建一个自己的EventArgs类。引自MSDN: EventArgs是包含事件数据的类的基类,此类不包含事件数据,在事件引发时不向事件处理程序传递状态信息的事件会使用此类。如果事件处理程序需要状态信息,则应用程序必须从此类派生一个类来保存数据。因为在我们键盘按键事件中要包含按键信息,所以要派生一个KeyEventArgs类,来保存按键信息,好让后面知道按了哪个键。 internal class KeyEventArgs:EventArgs {privatecharkeyChar;publicKeyEventArgs(charkeyChar):base(){this.keyChar=keyChar;}publiccharKeyChar{get{returnkeyChar;}}} 2、再创建一个事件发生的类KeyInputMonitor,这个类用于监控键盘按键的输入并触发一个事件: internal class KeyInputMonitor {//创建一个委托,返回类型为void,两个参数publicdelegatevoidKeyDown(objectsender,KeyEventArgse);//将创建的委托和特定事件关联,在这里特定的事件为OnKeyDownpubliceventKeyDownOnKeyDown;publicvoidRun(){boolfinished=false;do{Console.WriteLine("Inputachar");stringresponse=Console.ReadLine();charresponseChar=(response=="")?'':char.ToUpper(response[0]);switch(responseChar){case'X':finished=true;break;default://得到按键信息的参数KeyEventArgskeyEventArgs=newKeyEventArgs(responseChar);//触发事件OnKeyDown(this,keyEventArgs);break;}}while(!finished);}} 这里注意OnKeyDown( this, KeyEventArgs );一句,这就是触发事件的语句,并将事件交由KeyDown这个委托来处理,委托指定事件处理方法去处理事件,这就是事件接收方的类的事情了。参数this是指触发事件的对象就是本身这个对象,keyEventArgs包含了按键信息。 3、最后创建一个事件接收方的类,这个类先产生一个委托实例,再把这个委托实例添加到产生事件对象的事件列表中去,这个过程又叫订阅事件。然后提供一个方法回显按键信息。 internal class EventReceiver {publicEventReceiver(KeyInputMonitormonitor){//产生一个委托实例并添加到KeyInputMonitor产生的事件列表中monitor.OnKeyDown+=newKeyInputMonitor.KeyDown(this.Echo);}privatevoidEcho(objectsender,KeyEventArgse){//真正的事件处理函数Console.WriteLine("Capturekey:{0}",e.KeyChar);}} 4、看一下如何调用 public class MainEntryPoint {publicstaticvoidStart(){//实例化一个事件发送器KeyInputMonitormonitor=newKeyInputMonitor();//实例化一个事件接收器EventReceivereventReceiver=newEventReceiver(monitor);//运行monitor.Run();}} 总结: C#中使用事件需要的步骤: 1.创建一个委托 2.将创建的委托与特定事件关联(.Net类库中的很多事件都是已经定制好的,所以他们也就有相应的一个委托,在编写关联事件处理程序--也就是当有事件发生时我们要执行的方法的时候我们需要和这个委托有相同的签名) 3.编写事件处理程序 4.利用编写的事件处理程序生成一个委托实例 5.把这个委托实例添加到产生事件对象的事件列表中去,这个过程又叫订阅事件 C#中事件产生和实现的流程: 1.定义A为产生事件的实例,a为A产生的一个事件 2.定义B为接收事件的实例,b为处理事件的方法 3.A由于用户(程序编写者或程序使用者)或者系统产生一个a事件(例如点击一个Button,产生一个Click事件) 4.A通过事件列表中的委托对象将这个事件通知给B 5.B接到一个事件通知(实际是B.b利用委托来实现事件的接收) 6.调用B.b方法完成事件处理 public class A { public delegate void EventHandler(object sender); public event EventHandler a; public void Run() { Console.WriteLine("Trigger an event."); a(this); } } class B { public B(A a) { a.a += new A.EventHandler(this.b); } private void b(object sender) { Console.WriteLine("Received and handled an event." ); Console.Read(); } } 不当之处,欢迎指正。 (完) 本文转自麒麟博客园博客,原文链接:http://www.cnblogs.com/zhuqil/archive/2009/12/30/1636082.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android APK包文件解析

Android的.apk文件实际上就是一个zip文件 可以直接用winrar打开 如下图所示: 包括了一个META-INF目录 一个res目录 一个AndroidManifest.xml 一个classes.dex AndroidManifest.xml是每个应用都必须定义和包含的,它描述了应用的名字、版本、权限、引用的库文件等等信息,如要把apk上传到Google Market上,也要对这个xml做一些配置。 META-INF目录 META-INF目录下存放的是签名信息,用来保证apk包的完整性和系统的安全。在eclipse编译生成一个apk包时,会对所有要打包的文件做一个校验计算,并把计算结果放在META-INF目录下。而在Android平台上安装apk包时,应用管理器会按照同样的算法对包里的文件做校验,如果校验结果与META-INF下的内容不一致,系统就不会安装这个apk。这就保证了apk包里的文件不能被随意替换。比如拿到一个apk 包后,如果想要替换里面的一幅图片,一段代码,或一段版权信息,想直接解压缩、替换再重新打包,基本是不可能的。如此一来就给病毒感染和恶意修改增加了难度,有助于保护系 统的安全。 classes.dex文件 classes.dex是java源码编译后生成的java字节码文件。但由于Android使用的dalvik虚拟机与标准的java虚拟机是不兼容 的,dex文件与class文件相比,不论是文件结构还是opcode都不一样。目前常见的java反编译工具都不能处理dex文件。 Android模拟器中提供了一个dex文件的反编译工具dexdump。用法为首先启动Android模拟器,把要查看的dex文件用adb push上传的模拟器中,然后通过adb shell登录,找到要查看的dex文件,执行dexdump xxx.dex。 目前在网上能找到的另一个dex文件的反编译工具是Dedexer。Dedexer可以读取dex格式的文件,生成一种类似于汇编语言的输出。这种输出与jasmin[ ]的输出相似,但包含的是Dalvik的字节码。我们会在下一节详细介绍一下Dedexer。 res 目录 res目录存放资源文件。 resources.arsc 编译后的二进制资源文件。 其中dex的格式参见: http://www.retrodev.com/android/dexformat.html apk文件解压后反编译: 图片等多媒体文件:没有编译,无需反编译。 layout等二进制xml文件:使用AXMLPrinter将其转换为可读的xml文件:java -jar AXMLPrinter2.jar main.xml > new_main.xml 工具下载地址:http://code.google.com/p/android4me/downloads/list 下图是直接打印出来一个main.xml 要打开AndroidManifest.xml或者其他xml也同理 class文件反编译: Android模拟器中提供了一个dex文件的反编译工具,dexdump。用法为首先启动Android模拟器,把要查看的dex文件用adb push上传的模拟器中,然后通过adb shell登录,找到要查看的dex文件,执行dexdump xxx.dex。 然后找到上传的要打开的dex 然后可以看到反汇编之后的代码如下 目前在网上能找到的另一个dex文件的反编译工具是Dedexer。Dedexer可以读取dex格式的文件,生成一种类似于汇编语言的输出。这种输出与jasmin[ ]的输出相似,但包含的是Dalvik的字节码。 resources.arsc这个文件我是用了 汉化浪子编写的AndroidResEdit 软件 能看到里面的所有字段 直接用记事本打开大多数是乱码 打开如下图所示 以上就是apk文件的详细结构分析 apk文件如果把其中的资源文件进行替换修改 比如进行类似汉化操作的时候 需要重新对其签名 具体的可以替换的内容有 res文件下下的资源文件 而且 res下面的资源文件中的图片等多媒体文件:没有编译,无需反编译,这样就可以很轻松地获得一些比较好的 apk应用里的图片,通过解码 xml文件,可以还原原来应用的 xml文件,这样,可以获得其界面布局文件。 在替换了之后,只需要使用 Auto-sign工具重新对其进行签名即可,首先,删掉 META-INF文件夹下的签名文件 删除 CERT.RASACERT.SF 只留下 MANIFEST.MF文件即可 然后使用 Auto-sign工具重新对其进行签名 具体的调用格式如下 [vb] view plain copy @ECHOOFF EchoAuto-signCreatedByDaveDaillest1 EchoUpdate.zipisnowbeingsignedandwillberenamedtoupdate_signed.zip java-jarsignapk.jartestkey.x509.pemtestkey.pk8update.zipupdate_signed.zip EchoSigningComplete Pause EXIT 重新签名之后的 apk包即可和原来的包一样正常地安装到手机上 本文转自jazka 51CTO博客,原文链接:http://blog.51cto.com/jazka/1111856,如需转载请自行联系原作者

优秀的个人博客,低调大师

AAC ADTS流解析总结

这里列出Android里将aac编码器输出的音频帧加上ADTS头的代码: + int tmpFd; + tmpFd = ::open("/data/src.aac", O_WRONLY | O_APPEND ); + if ( tmpFd < 0 ) { + LOGE("No dump decode file %s",strerror(errno)); + } + else + { + unsigned char adts_hdr[7] = {0xff, 0xf9, 0x5c, 0x80, 0x00,0x1f, 0xfc}; + + adts_hdr[3] = 0x80 | ((mConfig->inputBufferCurrentLength >> 11) & 3); + adts_hdr[4] = (mConfig->inputBufferCurrentLength >> 3) & 0xff; + adts_hdr[5] = ((mConfig->inputBufferCurrentLength & 7) << 5) | 0x1f; + + ::write(tmpFd,adts_hdr, 7); + ::write(tmpFd,(const char *)mConfig->pInputBuffer , mConfig->inputBufferCurrentLength); + ::close(tmpFd); + } AAC参考知识: http://blog.csdn.net/axdc_qa_team/article/details/4271043 (除协议外,非常详细的文章) http://blog.csdn.net/jay100500/article/details/52955232 (adts协议) http://blog.csdn.net/leixiaohua1020/article/details/11822537 //aac header http://yeyingxian.blog.163.com/blog/static/344712420134485613752/ https://wiki.multimedia.cx/index.php?title=MPEG-4_Audio 本文转自 曾永刚 51CTO博客,原文链接:http://blog.51cto.com/zyg0227/1952766

优秀的个人博客,低调大师

Handler的解析和使用

1.handler为android中多线程间通信的一种机制, @1android中只允许在UI线程(主线程)操作或改变UI,其他线程不能操作UI。 @2其他线程有刷新UI的需要,所以得告诉UI线程,这时候就用到Handler,在handeMessage方法中处理消息。 @3handler可以定义在主线程也可以定义在其他线程,作用不一样。 @4与handler执行相关的类:Handler,Message,MessageQueue,Looper UI线程:主线程,创建时会自动初始化一个Looper对象,也会创建一个消息队列 Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。 Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。 MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。 Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。 Thread:线程,负责调度整个消息循环,即消息循环的执行场所。 2.handler的使用 @1用在主线程 ---1-定义Handler对象,重写handleMessage方法,在方法里面处理消息,更新UI privateHandlermHanlder=newHandler(){ publicvoidhandleMessage(android.os.Messagemsg){ numberAdapter=newBlackNumberAdapter(getApplicationContext(),mList,mBnd); lv_blacknum.setAdapter(numberAdapter); }; }; ---2-在其他 线程发送消息,有时需要自己定义消息对象 mHanlder.sendEmptyMessage(BLACKNUM_PREPARED); @2handler定义在子线程,需要自己创建Looper对象 ----流程: ====1.调用Looper.prepare()为当前线程创建Looper对象,此时会自动创建MessageQueue消息队列;2.创建Handler对象,重写handleMessage方法;3.调用Looper.loop()方法启动Looper消息循环 本文转自lzwxx 51CTO博客,原文链接:http://blog.51cto.com/13064681/1943367

优秀的个人博客,低调大师

Ubuntu环境变量解析

在Ubuntu中有如下几个文件可以设置环境变量 /etc/profile:在登录时,操作系统定制用户环境时使用的第一个文件,此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行. /etc/environment:在登录时操作系统使用的第二个文件,系统在读取你自己的profile前,设置环境文件的环境变量 ~/.profile:在登录时用到的第三个文件是.profile文件,每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件. /etc/bashrc:为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取. ~/.bashrc:该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取. 当你登录并且登录shell是bash时,bash首先执行/etc/profile文件中的命令(如果该文件存在),然后它顺序寻找 ~ /.bash_profile,~/.bash_login或~/.profile文件,并执行找到的第一个可读文件中的命令.当登录bash退出时,它 将执行~/.bash_logout文件中的命令. 当启动一个交互的bash时,它将执行~/.bashrc文件中的命令(如果该文件存在并且可读).当非交互地启动以运行一个shell脚本时,bash将查找bash_env环境变量,确定执行文件的名称. 本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/4474154.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

深度解析阿里云存储

国际知名调研机构Gartner近日公布了2017年全球云计算云存储魔力象限,阿里云的云存储强势崛起成为这一核心领域的前四名。 图1 2017年Gartner全球云存储魔力象限图 在去年首次进入Gartner魔力象限即取得了不错的位置之后,今年阿里云存储再次强势进入公共云存储魔力象限,紧跟Google成为公共云存储厂商中在利基象限中最接近领导者象限的公共云存储厂商,而领导者象限中目前只有AWS和Azure。 图2 2016年Gartner全球云存储魔力象限图 作为国内市场排名第一的云厂商的云存储产品系列,取得这样的成绩也并不是水涨船高的结果。首先从整体评估上来说,Gartner的评估方法并不依赖母体厂商的品牌和占有率,而是客观的从云存储类型(对象,块,文件)和冷热存储,全球数据中心的位置、技术成熟度、市场策略、市场份额、服务承诺和SLA

优秀的个人博客,低调大师

Android 使用SAX解析XML

项目的结构 首先新建一个book_info.xml的xml文件,结构如下: <?xml version= "1.0" encoding= "UTF-8" ?> <books> <catalog>Computer</catalog> <book> <country>USA</country> <title>Empire Burlesque</title> <artist>Bob Dylan</artist> <price> 10.90 </price> </book> <book> <country>UK</country> <title>Hide your heart</title> <artist>Bonnie Tyler</artist> <price> 9.90 </price> </book> <book> <country>USA</country> <title>Greatest Hits</title> <artist>Dolly Parton</artist> <price> 9.90 </price> </book> </books> BookItem.java 代表一本书的信息,代码如下: package com.example.utility; public class BookItem { public String name; public String title; public String artit; public String price; public BookItem() { } public String getName() { return name; } public void setName(String countryName) { this .name = countryName; } public String getTitle() { return title; } public void setTitle(String title) { this .title = title; } public String getArtist() { return artit; } public void setArtist(String artit) { this .artit = artit; } public String getPrice() { return price; } public void setPrice(String price) { this .price = price; } } BookFeed代表所有书的信息,代码如下: package com.example.utility; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; public class BookFeed { private String catalog; private List<BookItem> bookList; private int itemcount; public BookFeed() { bookList = new Vector<BookItem>( 0 ); } public int addBookItem(BookItem item) { itemcount++; bookList.add(item); return itemcount; } public BookItem getBookItem( int location) { return bookList.get(location); } public List<BookItem> getAllBooks() { return bookList; } public String getCatalog() { return catalog; } public void setCatalog(String catalog) { this .catalog = catalog; } public List<BookItem> getBookList() { return bookList; } public void setBookList(List<BookItem> bookList) { this .bookList = bookList; } public List GetAllBooks() { List<Map<String, String>> data = new ArrayList<Map<String,String>>() ; int size = bookList.size(); for ( int i = 0 ; i < size; i++) { HashMap<String, String> bookItemHashMap = new HashMap<String, String>(); bookItemHashMap.put( "title" , bookList.get(i).getTitle()); bookItemHashMap.put( "price" , bookList.get(i).getPrice()); data.add(bookItemHashMap); } return data; } } BookHand.java package com.example.utility; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import android.R.integer; public class BookHandle extends DefaultHandler { BookFeed bookFeed; BookItem bookItem; final int Book_Country = 1 ; final int Book_Title = 2 ; final int Book_Artist = 3 ; final int Book_Price = 4 ; int curState = 0 ; public BookHandle() { } public BookFeed getBookFeed() { return bookFeed; } @Override public void startDocument() throws SAXException { bookFeed = new BookFeed(); bookItem = new BookItem(); } @Override public void endDocument() throws SAXException { } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (localName.equals( "books" )) { curState = 0 ; return ; } if (localName.equals( "book" )) { bookItem = new BookItem(); return ; } if (localName.equals( "country" )) { curState = Book_Country; return ; } if (localName.equals( "title" )) { curState = Book_Title; return ; } if (localName.equals( "artist" )) { curState = Book_Artist; return ; } if (localName.equals( "price" )) { curState = Book_Price; return ; } curState = 0 ; } @Override public void endElement(String uri, String localName,String qName) throws SAXException { if (localName.equals( "book" )) { bookFeed.addBookItem(bookItem); return ; } } @Override public void characters( char [] ch, int start, int length) throws SAXException { String str = new String(ch,start,length); switch (curState) { case Book_Country: bookItem.setName(str); curState = 0 ; break ; case Book_Title: bookItem.setTitle(str); curState = 0 ; break ; case Book_Artist: bookItem.setArtist(str); curState = 0 ; break ; case Book_Price: bookItem.setPrice(str); curState = 0 ; break ; default : return ; } } } MainActiviyt.java public class MainActivity extends Activity { public BookFeed feed; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); feed = getFeed(); showList(); } private void showList() { // TODO Auto-generated method stub ListView lView = (ListView) this .findViewById(R.id.listView1); if (feed == null ) { Log.i( "Custom Message" , "feed is null" ); return ; } SimpleAdapter adapter = new SimpleAdapter( this , feed.GetAllBooks(), android.R.layout.simple_list_item_2, new String[]{ "title" , "price" }, new int []{android.R.id.text1, android.R.id.text2}); lView.setAdapter(adapter); } public BookFeed getFeed() { try { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); XMLReader reader = parser.getXMLReader(); BookHandle handle = new BookHandle(); reader.setContentHandler(handle); InputSource iSource = new InputSource( this .getClassLoader().getResourceAsStream( "book_info.xml" )); reader.parse(iSource); return handle.getBookFeed(); } catch (ParserConfigurationException e) { // TODO: handle exception e.printStackTrace(); } catch (SAXException e) { // TODO: handle exception e.printStackTrace(); } catch (IOException e) { // TODO: handle exception e.printStackTrace(); } return null ; } } 效果图: 本文转自Work Hard Work Smart博客园博客,原文链接:http://www.cnblogs.com/linlf03/archive/2013/03/18/2966020.html,如需转载请自行联系原作者

资源下载

更多资源
Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册