首页 文章 精选 留言 我的

精选列表

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

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,如需转载请自行联系原作者

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

Android Fragment使用全解析

Fragment的使用可谓是老生常谈了~~~ 1、概述 自API 11引入Fragment之后,Fragment可谓风靡一时,现在大部分项目都或多或少的用到了Fragment,其更轻量级,更加适用屏幕,更加方便UI设计等优势。说了这么多什么是Fragment呢? Fragment:碎片,碎片是一个应用程序的用户界面和行为能够被放置在一个活动上。在其核心,它代表了一个特定的操作或界面,运行在一个更大的活动上。代表界面是因为可作为View在布局中进行使用,代表特定操作是因为包含生命周期可进行逻辑操作。简言之,Fragment就是一个带生命周期的组件。(若有问题恳请指正!) Fragment的特点: 生命周期必须依赖于Activity,当Activity被销毁,所有的碎片将被摧毁。(自己曾经踩坑) 轻量级,轻量切换。 方便处理平板、Phone的界面差异。 2、继承结构和生命周期 继承结构: Fragment直接继承Object,有四个直接子类,我个人对它的子类使用甚少。 生命周期: Fragment的生命周期在图上标注的很清楚了就不赘述了。该图是很久之前收藏的,已忘记原出处,在此感谢原作者! 3、基本使用 1).静态使用 静态使用就是Fragment相当于控件一样在布局中使用。 TestFragment.java 继承Fragment重写onCreateView方法 /** *Createdbymagicon2016年9月27日. */ publicclassTestFragmentextendsFragment{ @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer, BundlesavedInstanceState){ Viewview=inflater.inflate(R.layout.fragment_main,container); ImageViewimg=(ImageView)view.findViewById(R.id.img); img.setOnClickListener(newView.OnClickListener(){ @Override publicvoidonClick(Viewv){ Toast.makeText(getActivity(),"这是一个fragment",Toast.LENGTH_SHORT).show(); } }); returnview; } } fragment_main.xml <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/img"/> </RelativeLayout> MainActivity.java 里面其实什么也没干。 /** *Createdbymagicon2016年9月27日. */ publicclassMainActivityextendsActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } activity_main.xml <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/id_fragment" android:layout_width="match_parent" android:layout_height="match_parent" class="com.magic.test_fragment.TestFragment"/> </RelativeLayout> 使用 fragment 标签添加碎片,通过class指定碎片的完整类名。 运行效果: 2).动态使用 动态使用就是向Fragment布局容器中动态添加、替换、移除、隐藏、显示Fragment。 CommonFragment.java /** *Createdbymagicon2016年9月27日.通用Fragment */ @SuppressLint("ValidFragment") publicclassCommonFragmentextendsFragment{ Stringdesc; publicCommonFragment(Stringdesc){ super(); this.desc=desc; } @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer, BundlesavedInstanceState){ Viewview=inflater.inflate(R.layout.fragment_common,container,false); TextViewtev=(TextView)view.findViewById(R.id.tev); System.out.println(desc); tev.setText(desc); returnview; } } 通过构造方法传递数据的形式向TextView上设置内容。 fragment_common.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tev" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textColor="@color/mainOrange"/> </LinearLayout> MainActivity.java /** *Createdbymagicon2016年9月27日.底部tab+fragment */ publicclassMainActivityextendsActivityimplementsOnClickListener{ TextViewtev_tab1,tev_tab2,tev_tab3,tev_tab4; //fragment事务类 FragmentTransactionft; //fragment CommonFragmenttabFragment1,tabFragment2,tabFragment3,tabFragment4; @SuppressLint("CommitTransaction") @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); initView(); ft=getFragmentManager().beginTransaction(); tabFragment1=newCommonFragment("Tab1"); //替换 ft.replace(R.id.container,tabFragment1); //提交 ft.commit(); } //初始化控件 privatevoidinitView(){ tev_tab1=(TextView)findViewById(R.id.tev_tab1); tev_tab2=(TextView)findViewById(R.id.tev_tab2); tev_tab3=(TextView)findViewById(R.id.tev_tab3); tev_tab4=(TextView)findViewById(R.id.tev_tab4); tev_tab1.setOnClickListener(this); tev_tab2.setOnClickListener(this); tev_tab3.setOnClickListener(this); tev_tab4.setOnClickListener(this); } @Override publicvoidonClick(Viewv){ FragmentTransactionft=getFragmentManager().beginTransaction(); switch(v.getId()){ caseR.id.tev_tab1: ft.replace(R.id.container,tabFragment1); break; caseR.id.tev_tab2: if(tabFragment2==null){ tabFragment2=newCommonFragment("Tab2"); } ft.replace(R.id.container,tabFragment2); break; caseR.id.tev_tab3: if(tabFragment3==null){ tabFragment3=newCommonFragment("Tab3"); } ft.replace(R.id.container,tabFragment3); break; caseR.id.tev_tab4: if(tabFragment4==null){ tabFragment4=newCommonFragment("Tab4"); } ft.replace(R.id.container,tabFragment4); break; } //提交 ft.commit(); } } activity_main2.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/mainTextBlack" android:orientation="horizontal"> <TextView android:id="@+id/tev_tab1" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:text="Tab1" android:textColor="@color/white"/> <TextView android:id="@+id/tev_tab2" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:text="Tab2" android:textColor="@color/white"/> <TextView android:id="@+id/tev_tab3" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:text="Tab3" android:textColor="@color/white"/> <TextView android:id="@+id/tev_tab4" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:text="Tab4" android:textColor="@color/white"/> </LinearLayout> </LinearLayout> 通过 FrameLayout 标签创建Fragment的容器,底部四个Tab添加监听事件用于动态更换FrameLayout容器中的Fragment。 运行效果: 4、相关类及主要方法 FragmentManager碎片管理器,抽象类,具体实现在Android-support-v4.jar中的FragmentManagerImpl类中。 //获取FragmentManager对象 FragmentManagermanager=getFragmentManager(); FragmentTransaction碎片事务类,抽象类,具体实现在BackStackRecord类中。添加、删除、替换等操作其实最终的实现还是在FragmentManagerImpl类中。 //获取FragmentTransaction对象 FragmentTransactiontransaction=manager.beginTransaction(); //添加fragment transaction.add(); transaction.add(containerViewId,fragment,tag); //将被添加到容器的现有fragment替换 transaction.replace(); //删除一个现有的fragment transaction.remove(); //保存当前fragment数据,避免视图重绘 transaction.hide(); //显示以前隐藏的fragment transaction.show(); //这两个方法会触发fragment中的onHiddenChanged(booleanhidden)回调 //显示之前数据实例不会被销毁,但是视图层次依然会被销毁,即会调用onDestoryView和onCreateView transaction.addToBackStack(null); //事务提交 transaction.commit(); Fragment 碎片类 Fragmentfragment=newFragment(); //返回此fragment当前关联的Activity fragment.getActivity(); //设置数据 fragment.setArguments(newBundle()); //获取数据 fragment.getArguments(); //返回与该fragment作用的FragmentManager fragment.getFragmentManager(); //获取标签名 fragment.getTag(); //当隐藏状态改变的时候回调 //onHiddenChanged(true); 有兴趣大家可以去Read The Fucking Source,反正我看的比较头大……. 5、其它 未完待续…… 本文作者:佚名 来源:51CTO

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

HBase - 建表语句解析

像所有其他数据库一样,HBase也有表的概念,有表的地方就有建表语句,而且建表语句还很大程度上决定了这张表的存储形式、读写性能。比如我们熟悉的MySQL,建表语句中数据类型决定了数据的存储形式,主键、索引则很大程度上影响着数据的读写性能。虽然HBase没有主键、索引这些概念,但在HBase的世界里,有些东西和它们一样重要! 废话不说,直接奉上一条HBase建表语句,来为各位看官分解剖析: create 'NewsClickFeedback',{NAME=>'Toutiao',VERSIONS=>1,BLOCKCACHE=>true,BLOOMFILTER=>'ROW',COMPRESSION=>'SNAPPY',TTL => ' 259200 '},{SPLITS => ['1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']} 上述建表语句表示创建一个表名为“NewsClickFeedback”的表,该表只包含一个列簇“Toutiao”。接下来重点讲解其他字段的含义以及如何正确设置。Note:因为篇幅有限本文并不讲解具体的工作原理,后续会有相关专题对其进行分析。 VERSIONS 数据版本数,HBase数据模型允许一个cell的数据为带有不同时间戳的多版本数据集,VERSIONS参数指定了最多保存几个版本数据,默认为1。假如某个用户想保存两个历史版本数据,可以将VERSIONS参数设置为2,再使用如下Scan命令就可以获取到所有历史数据: scan 'NewsClickFeedback',{VERSIONS => 2} BLOOMFILTER 布隆过滤器,优化HBase的随机读取性能,可选值NONE|ROW|ROWCOL,默认为NONE,该参数可以单独对某个列簇启用。启用过滤器,对于get操作以及部分scan操作可以剔除掉不会用到的存储文件,减少实际IO次数,提高随机读性能。Row类型适用于只根据Row进行查找,而RowCol类型适用于根据Row+Col联合查找,如下: Row类型适用于:get ‘NewsClickFeedback’,’row1′ RowCol类型适用于:get ‘NewsClickFeedback’,’row1′,{COLUMN => ‘Toutiao’} 对于有随机读的业务,建议开启Row类型的过滤器,使用空间换时间,提高随机读性能。 COMPRESSION 数据压缩方式,HBase支持多种形式的数据压缩,一方面减少数据存储空间,一方面降低数据网络传输量进而提升读取效率。目前HBase支持的压缩算法主要包括三种:GZip | LZO | Snappy,下面表格分别从压缩率,编解码速率三个方面对其进行对比: Snappy的压缩率最低,但是编解码速率最高,对CPU的消耗也最小,目前一般建议使用Snappy TTL 数据过期时间,单位为秒,默认为永久保存。对于很多业务来说,有时候并不需要永久保存某些数据,永久保存会导致数据量越来越大,消耗存储空间是其一,另一方面还会导致查询效率降低。如果设置了过期时间,HBase在Compact时会通过一定机制检查数据是否过期,过期数据会被删除。用户可以根据具体业务场景设置为一个月或者三个月。示例中TTL => ‘259200’设置数据过期时间为三天 IN_MEMORY 数据是否常驻内存,默认为false。HBase为频繁访问的数据提供了一个缓存区域,缓存区域一般存储数据量小、访问频繁的数据,常见场景为元数据存储。默认情况,该缓存区域大小等于Jvm Heapsize * 0.2 * 0.25 ,假如Jvm Heapsize = 70G,存储区域的大小约等于3.2G。需要注意的是HBase Meta元数据信息存储在这块区域,如果业务数据设置为true而且太大会导致Meta数据被置换出去,导致整个集群性能降低,所以在设置该参数时需要格外小心。 BLOCKCACHE 是否开启block cache缓存,默认开启。 SPLITS region预分配策略。通过region预分配,数据会被均衡到多台机器上,这样可以一定程度上解决热点应用数据量剧增导致系统自动split引起的性能问题。HBase数据是按照rowkey按升序排列,为避免热点数据产生,一般采用hash + partition的方式预分配region,比如示例中rowkey首先使用md5 hash,然后再按照首字母partition为16份,就可以预分配16个region。 本文转载自:http://hbasefly.com 原文链接

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

LinkedIn架构演化历史解析

LinkedIn 创建于 2003 年,主要目标是连接你的个人人脉以得到更好的的工作机会。上线第一周只有 2700 个会员,之后几年,LinkedIn 的产品、会员、服务器负载都增长非常快。 今天,LinkedIn 全球用户已经超过 3.5 亿。我们每天每秒有上万个页面被访问,移动端流量已占到 50% 以上。所有这些接口请求都从后台获取,达到每秒上百万级。 那么,我们是怎么做到的呢? 早些年 – Leo LinedIn 开始跟很多网站一样,只有一台应用服务做了全部工作。这个应用我们给它取名叫“Leo”。它包含了所有的网站页面(JAVA Servlets),还包含了业务逻辑,同时连接了一个轻量的 LinkedIn 数据库。 哈!早年网站的形态-简单实用 会员图表 第一件要做的是管理会员与会员间的社交网络。我们需要一个系统来图形化遍历用户之间连接的数据,同时又驻留内存以达到有效和高性能。从这个不同的需 求来看,很明显我们需要可以独立可扩展的 Leo。一个独立的会员图示化系统,叫“云”的服务诞生了 – LinkedIn 的第一个服务。为了让图表服务独立于 Leo,我们使用了 Java RPC 用来通讯。 也大概在这期间我们也有搜索服务的需求了,同时会员图表服务也在给搜索引擎-Lucene 提供数据。 复制只读数据库 当站点继续增长,Leo 也在增长,增加了角色和职责,同时自然也增加了复杂度。负载均衡的多实例 Leo 运转起来了。但新增的负载也影响了 LinkedIn 的其它关键系统,如会员信息数据库。 一个通常的解决方案是做垂直扩展 – 即增加更多的 CPU 和内存!虽然换取了时间,但我们以后还要扩展。会员信息数据库受理了读和写请求,为了扩展,一个复制的从数据库出现了,这个复制从库, 是会员主库的一个拷贝,用早期的 databus 来保证数据的同步(现在开源了)。从库接管了所有的读请求,同时添加了保证从库与主库一致的逻辑。 当主-从架构工作了一段时间后,我们转向了数据库分区 当网站开始看起来越来越多流量,我们的应用服务 Leo 在生产环境经常宕机,排查和恢复都很困难,发布新代码也很困难,高可用性对 LinkedIn 至关重要,很明显我们要“干掉”Leo,然后把它拆分成多个小功能块和无状态服务。 面向服务的架构 – SOA 工程师从分解负担 API 接口和业务逻辑的微服务开始,如搜索、个人信息、通讯及群组平台,然后是展示层分解,如招募功能和公共介绍页。新产品和新服务都放在 Leo 之外了,不久,每个功能区的垂直服务栈完成了。 我们构建了从不同域抓取数据模型的前端服务器,用于表现层展示,如生成 HTML(通过 JSPs)。我们还构建了中间层服务提供 API 接口访问数据模型及提供数据库一致性访问的后端数据服务。到 2010 年,我们已经有超过 150 个单独的服务,今天,我们已经有超过 750 个服务。 因为无状态,可以直接堆叠新服务实例及用硬件负载均衡实现扩展。我们给每个服务都画了警戒红线,以便知道它的负载,从而制定早期对策和性能监控。 缓存 LinkedIn 可预见的增长,所以还需要进一步扩展。我们知道通过添加更多缓存可以减少集中压力的访问。很多应用开始使用如 memcached/couchbase 的中间层缓存,同时在数据层也加了缓存,某些场景开始使用 useVoldemort 提供预结果生成。 又过一了段时间,我们实际上去掉了很多中间层缓存,中间层缓存数据往往来自多个域,但缓存只是开始时对减少负载有用,但更新缓存的复杂度和生成图表变得更难于把控。保持缓存最接近数据层将降低潜在的不可控影响,同时还允许水平扩展,降低分析的负载。 Kafka 为了收集不断增长的数据,LinkedIn 开始了很多自定义的数据管道来流化和队列化数据,例如,我们需要把数据保存到数据仓库、我们需要发送批量数据到 Hadoop 工作流以分析、我们从每个服务聚合了大量日志、我们跟踪了很多用户行为,如页面点击、我们需要队例化 InMail 消息服务、我们要保障当用户更新个人资料后搜索的数据是最新的等等。 当站点还在增长,更多定制化管道服务出现了,因网站需要可扩展,单独的管道也要可扩展,有些时候很难取舍。解决方案是使用 kafka,我们的分布式发布-订阅消息平台。Kafka 成为一个统一的管道服务,根据提交的日志生成摘要,同时一开始就很快速和具有可扩展性。它可以接近于实时的访问所有数据源,驱动了 Hadoop 任务,允许我们构建实时的分析,广泛的提升了我们站点监控和告警的能力,同时支持将调用可视化。今天,Kafka 每天处理超过 5 亿个事件。 反转 扩展可从多个维度来衡量,包括组织结构。2011 年晚些时候,LinkedIn 内部开始一个创新,叫”反转”(Inversion)。我们暂停了新功能开发,允许所有的开发部门集中注意力提升工具和布署、基础架构及实用性开发。这对 于今天敏捷开发新的可扩展性产品很有帮助。 近几年 – Rest.li 当我们从 Leao 转向面向服务的架构后,之前基于 JAVA 的 RPC 接口,在团队中已经开始分裂了,并且跟表现层绑得太死,这,只会变得更坏。为了搞定这个问题,我们开发了一套新的 API 模型,叫 Rest.li,它是一套以数据为中心的架构,同时保证在整个公司业务的数据一致性且无状态的 Restful API。 基于 HTTP 的 JSON 数据传递,我们新的 API 最终很容易支持到非 java 编写的客户端,LinkedIn 今天依然主要用 Java,但同时根据已有的技术分布也利用了 Python、Ruby、Node.js 和C++。脱离了 RPC,同时也让我们从前端表现层及后端兼容问题解耦,另外, 使用了基于动态发现技术(D2)的 Rest.li,我们每个服务层 API 获得了自动负载均衡、发现和扩展的能力。 今天,LinkedIn 所有数据中心每天已经有超过 975 个 Rest.li 资源和超过千亿级 Rest.li 调用。 Rest.li R2/D2 技术栈 超级块 面向服务的架构对于域解耦和服务独立扩展性很有帮助,但弊端是,大都我们的应用都需要很多不同类型的数据,按序会产品数百个延伸的调用。这就是通常 说的“调用线路图”,或伴随着这么多延伸调用的“扇出”(fan-out)。例如,任何个人信息页都包含了远不止于相册、连接、群组、订阅、关注、博客、 人脉维度、推荐这些。调用图表可能会很难管理,而且只会把事件搞得越来越不规则。 我们使用了”超级块”的概念 – 一个只有单一 API 接口的群组化后台服务。这样可以允许一个小组去优化一个“块”,同时保证每个客户端的调用情况可控。 多数据中心 作为一个会员快速增长的全球化公司,我们需要将数据中心进行扩展,我们努力了几年来解决这个问题,首先,从两个数据中心(洛杉矶和芝加哥)提供了公 共个人信息,这表明,我们已经可以提供增强的服务用来数据复制、不同源的远程调用、单独数据复制事件、将用户分配到地理位置更近的数据中心。 我们大多的数据库运行在 Espresso(一个新的内部多用户数据仓库)。Espresso 支持多个数据中心,提供了主-主的支持,及支持复杂的数据复制。 多个数据中心对于高可用性具有不可思议的重要性,你要避免因单点故障不仅只导致某个服务失效,更要担心整个站点失效。今天,LinkedIn 运行了 3 个主数据中心,同时还有全球化的 PoPs 服务。 我们还做了哪些工作? 当然,我们的扩展故事永远不止这么简单。我们的工程师和运维团队这些年做了不计其数的工作,主要包括这些大的初创性的: 这些年大多关键系统都有自己的丰富的扩展演化历史,包括会员图表服务(Leo 之外的第一个服务),搜索(第二个服务),新闻种子,通讯平台及会员资料后台。 我们还构建了数据基础平台支持很长一段时间的增长,这是 Databus 和 Kafka 的第一次实战,后来用 Samza 做数据流服务,Espresso 和 Voldemort 作存储解决方案,Pinot 用来分析系统,以及其它自定义解决方案。另外,我们的工具也进步了,如工程师可自动化布署这些基础架构。 我们还使用 Hadoop 和 Voldemort 数据开发了大量的离线工作流,用以智能分析,如“你可能认识的人”,“相似经历”,“感觉兴趣的校友”及“个人简历浏览地图”。 我们重新考虑了前端的方法,加了客户端模板到混合页面(个人中心、我的大学页面),这样应用可以更加可交互,只要请求 JSON 或部分 JSON 数据。还有,模板页面通过 CDN 和浏览器缓存。我们也开始使用了 BigPipe 和 Play 框架,把我们的模型从线程化的服务器变成非阻塞异步的。 在代码之外,我们使用了 Apache 的多层代理和用 HAProxy 做负载均衡,数据中心,安全,智能路由,服务端渲染,等等。 最后,我们继续提升服务器的性能,包含优化硬件,内存和系统的高级优化,利用新的 JRE。 下一步是什么 LinkedIn 今天仍在快速增长,仍然有大量值得提升的工作要做,我们正在解决一些问题,看起来只解决了一部分 – 快来加入我们吧! 来源:51CTO

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

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

Sublime Text

Sublime Text

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

用户登录
用户注册