首页 文章 精选 留言 我的

精选列表

搜索[基础搭建],共10000篇文章
优秀的个人博客,低调大师

RxJava 和 RxAndroid 一 (基础)

1、RxJava 项目地址 https://github.com/ReactiveX/RxJava 2、RxAndroid 项目地址 https://github.com/ReactiveX/RxAndroid 3、RxJava 和 RxAndroid 的关系 RxAndroid是RxJava的一个针对Android平台的扩展,主要用于 Android 开发 4、RxJava和EventBus的区别? https://www.zhihu.com/question/32179258/answer/54989242 5、RxAndroid的使用方法 compile 'io.reactivex:rxandroid:1.2.0' 6、如何查看RxAndroid最新版本? http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22rxandroid%22 7、RxAndroid具体使用方法 http://gank.io/post/560e15be2dca930e00da1083#toc_14 http://blog.csdn.net/theone10211024/article/details/50435325 http://huxian99.github.io/tags/RxJava/ https://github.com/mcxiaoke/RxDocs 8、创建观察者 package lib.com.myapplication; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import rx.Observer; import rx.Subscriber; public class Main2Activity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); //创建观察者 2 种方法 Observer<String> observer = new Observer<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { } } ; // Subscriber 继承 Observer ,对Observer类做了扩展 Subscriber<String> subscriber = new Subscriber<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { } } ; } } 从上文可以看到,Subscriber继承Observer, 只是Subscriber对Observer做了一些扩展。Subscriber的使用和Observer完全一样。 Subscriber 多了一个onStart 方法 onStart(): 这是Subscriber增加的方法。它会在 subscribe 刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行),onStart()就不适用了,因为它总是在 subscribe 所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用doOnSubscribe()方法,具体可以在后面的文中看到。 // Subscriber 继承 Observer ,对Observer类做了扩展 Subscriber<String> subscriber = new Subscriber<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { } @Override public void onStart() { super.onStart(); } } ; 9、创建被观察者 //create方式 Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext( "aa" ) ; subscriber.onNext( "bb" ) ; subscriber.onNext( "cc" ) ; subscriber.onCompleted(); } }); //just方式 最多支持10个数据 Observable<String> observable1 = Observable.just( "aa" , "bb" , "cc") ; // 将会依次调用: // onNext("aa"); // onNext("bb"); // onNext("cc"); // onCompleted(); //from方式 //1:集合 List<String> list = new ArrayList<>() ; list.add( "aa" ) ; list.add( "bb" ) ; list.add( "cc" ) ; Observable<String> observable2 = Observable.from( list ) ; //2:数组 String[] words = { "aa", "bb", "cc" }; Observable<String> observable3 = Observable.from( words ) ; Call()方法:当Observable被订阅的时候,OnSubscribe的call()方法会自动被调用,事件序列就会依照设定依次触发(对于上面的代码,就是观察者Subscriber将会被调用三次onNext()和一次onCompleted())。这样,由被观察者调用了观察者的回调方法,就实现了由被观察者向观察者的事件传递,即观察者模式。 10、订阅 由于观察者可以由两种方式被创建,所以订阅的方式也有两种 observable.subscribe( observer ) ; observable.subscribe( subscriber ) ; Observable.subscribe(Subscriber)的内部实现是这样的(仅核心代码): // 注意:这不是 subscribe() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。 // 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。 public Subscription subscribe(Subscriber subscriber) { subscriber.onStart(); onSubscribe.call(subscriber); return subscriber; } 在subscribe() 中,首先会调用onStart() 方法,这个方法前文已经介绍了,是可选的。接着会调用 call()方法,我们已经分析了在call()方法中会调用多次 onNext() ,最后调用onCompleted().看到这里你就会突然明白原来subscribe() 方法其实相当于依次执行了:onStart() --> onNext()--> onCompleted() 从这也可以看出,在 RxJava 中,Observable并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当subscribe()方法执行的时候。 Observer和Subscriber具有相同的角色,而且Observer在subscribe()过程中最终会被转换成Subscriber对象 将传入的Subscriber作为Subscription返回。这是为了方便unsubscribe(). 11、RxBus 你是否听说过EventBus , 他是android 中的事件总线。用rxjava同样可以实现android的事件总线功能,也就是RxBus. 关于rxbus 的基本说明在这里http://nerds.weddingpartyapp.com/tech/2014/12/24/implementing-an-event-bus-with-rxjava-rxbus/ 然而这并没有什么卵用 ! 下面是RxBus的封装版 package lib.com.myapplication; import android.support.annotation.NonNull; import android.util.Log; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import rx.Observable; import rx.subjects.PublishSubject; import rx.subjects.Subject; /** * Created by ${zyj} on 2016/5/6. */ public class RxBus { private static final String TAG = RxBus.class.getSimpleName(); private static RxBus instance; public static boolean DEBUG = false; public static RxBus get() { if (instance == null) { synchronized (RxBus.class) { if (instance == null) { instance = new RxBus(); } } } return instance; } private RxBus() { } private ConcurrentHashMap<Object, List<Subject>> subjectMapper = new ConcurrentHashMap<>(); @SuppressWarnings("unchecked") public <T> Observable<T> register(@NonNull Object tag, @NonNull Class<T> clazz) { List<Subject> subjectList = subjectMapper.get(tag); if (null == subjectList) { subjectList = new ArrayList<>(); subjectMapper.put(tag, subjectList); } Subject<T, T> subject; subjectList.add(subject = PublishSubject.create()); if (DEBUG) Log.d(TAG, "[register]subjectMapper: " + subjectMapper); return subject; } public void unregister(@NonNull Object tag, @NonNull Observable observable) { List<Subject> subjects = subjectMapper.get(tag); if (null != subjects) { if ( observable != null && subjects.contains( observable )){ subjects.remove((Subject) observable); } if (isEmpty(subjects)) { subjectMapper.remove(tag); } } if (DEBUG) Log.d(TAG, "[unregister]subjectMapper: " + subjectMapper); } public void post(@NonNull Object content) { post( content.getClass().getName(), content); } @SuppressWarnings("unchecked") public void post(@NonNull Object tag, @NonNull Object content) { List<Subject> subjectList = subjectMapper.get(tag); if (!isEmpty(subjectList)) { for (Subject subject : subjectList) { subject.onNext(content); } } if (DEBUG) Log.d(TAG, "[send]subjectMapper: " + subjectMapper); } private boolean isEmpty(Collection collection) { return null == collection || collection.isEmpty(); } } RxBus的使用 package lib.com.myapplication; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import rx.Observable; import rx.functions.Action1; public class Activity1 extends AppCompatActivity { String tag = "tag" ; Observable<String> ob ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity1); //创建被观察者 ob = RxBus.get().register( tag , String.class ) ; //订阅观察事件 ob.subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println( "fff-- " + s ); } }) ; //发送内容 RxBus.get().post( tag , "我是内容" ); } @Override protected void onDestroy() { super.onDestroy(); //取消订阅 RxBus.get().unregister( tag , ob ); } } 在Activity销毁的时候,要取消订阅服务 。 否则 post() 次数会随着post()调用逐渐增加 除了上面的简单使用外,还可以使用 Schedulers 、AndroidSchedulers 进行线程切换 RxJava 和 RxAndroid 二(操作符的使用)

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

苹果开发基础知识

App ID(应用ID) App ID是识别不同应用程序的唯一标示符。每个app都需要一个App ID或者app标识。 目前有两种类型的App标识:一个是精确的App ID(explicit App ID),一个是通配符App ID(wildcard App ID)。 使用通配符的App ID可以用来构建和安装多个程序。尽管通配符App ID非常方便,但是一个精确的App ID也是需要的, 尤其是当App使用iCloud 或者使用其他iOS功能的时候,比如Game Center、Push Notifications或者IAP。 如果你不确定什么样的App ID适合你的项目,我推荐你读下苹果关于这一主题的文档:Technical Note QA1713。 Distribution Certificate(发布证书) iOS应用都有一个安全证书用于验证开发者身份和签名。为了可以向App Store提交app,你需要创建一个iOS provisioning profile 。 首先需要创建一个distribution certificate(发布证书),过程类似于创建一个development certificate(开发证书)。 如果你已经在实体设备上测试你的App,那么你对创建development certificate就已经很熟悉了。 如果对此不熟悉,我建议你读下苹果关于signing certificates和provisioning profiles的详细指导。 Provisioning Profile(配置文件) 一旦你创建了App ID和distribution certificate,你可以创建一个iOS provisioning profile以方便在App Store中销售你的App。 不过,你不能使用和ad hoc distribution相同的provisioning profile。 你需要为App Store分销创建一个单独的provisioning profile,如果你使用通配符App ID,那么你的多个app就可以使用相同的provisioning profile。 Build Settings(生成设置) 配置App ID、distribution certificate 和provisioning profile已经完成,是时候配置Xcode中target的build settings了。 在Xcode Project Navigator的targets列表中选择一个target,打开顶部的Build Settings选项,然后更新一下Code Signing来跟之前创建的distribution provisioning profile相匹配。 最近添加的provisioning profiles有时候不会立马就在build settings的Code Signing中看到,重启一下Xcode就可以解决这个问题。 Deployment Target(部署目标) 非常有必要说下deployment target,Xcode中每个target都有一个deployment target,它可以指出app可以运行的最小版本。 不过,一旦应用在App Store中生效,再去修改deployment target,你要考虑到一定后果。 如果你在更新app的时候提高了deployment target,但是已经购买应用的用户并没有遇到新的deployment target,那么应用就不能在用户的移动设备上运行。 如果用户通过iTunes (不是设备)下载了一个更新过的app,然后替代了设备上原先的版本,最后却发现新版本不能在设备上运行,这确实是个问题。 证书主要分为两类 Development和Production, Development证书用来开发和调试应用程序, Production主要用来分发应用程序(根据证书种类有不同作用),下面是证书的分类信息:(括号内为证书有效期) Development App Development (1年):用来开发和真机调试应用程序。 Push Development (1年):用来调试Apple Push Notification Production In-House and Ad Hoc (3年):用来发布In-House和AdHoc的应用程序。 App Store :用来发布提交App Store的应用程序。 MDM CSR Push Production (1年):用来在发布版本中使用Apple Push Notification。 Pass Type ID Certificate:用于通行证类证书 Website Push ID Certificate 有一些类型的证书我没有使用过,所以也不了解具体的作用。 证书 1)Developer Certification(开发证书) 2)Distribution Certification(发布证书) 授权文件 1)Developer Provisioning Profile(开发授权文件) 2)Distribution Provisioning Profile(发布授权文件)

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

ios入门之界面基础

学习移动app开发,我们常常从讲解基本的控件开始,如UILabel、UISearchBar、UIButton、UITextField等等。在实现一个简单的ios 应用之前,我们首先来看ios开发中一些基本的概念。 视图控制器(View Controllers) 视图控制器是MVC(Modl-View-Controller)模式的逻辑部分。按照字面意思,这个控制器能够控制某个视图。 UIViewController 苹果极力推崇MVC这种开发模式,并且帮我们实现了一个叫做UIViewController的控制器,它是UIKit的一部分。UIKit是众多能够制作交互界面元素的类,如果你在某个类的开头是UI,那么这个类属于UIkit。UIViewController视图属性被连接到一个视图文件,大多数情况下,是一个storyboard文件。 UIViewController提供一些需要的方法和属性,通常我们在使用的时候只需要将UIViewController子类化即可。如: class mySubController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any addition setup after loading the view } } 在这个例子中,父类就是UIViewController。viewDidLoad()是UIViewcontroller默认的方法。 UINavigationController 我们在编写一个ios软件的时候,往往不只一个界面,界面之前跳转我们常常会用到navigation controller这么一个东西。一个UINavigationController可以在数组中支持多个UIViewController,导航控制器(navigation controller)按照先进后出的堆栈管理原则对我们创建的UIViewController进行管理。通过self.title属性来设置导航栏的标题。如: self.title =@"登录"; Table View Table views是用来显示滚动视图的控件,滚动视图是iOS Apps中最常见的用户界面。滚动视图中的每一行叫做cell,cell是用了展示table view中每行的内容。table view可以有很多个cell,多个cell组成section(组)。在iPhone的设置界面,就是用不同的section把界面分开,像通知中心,控制中心,个人隐私,每个table view都有header和footer,header是在cell上面,footer在cell下面。 Delegation 在很多的OA软件中,往往都有定时提醒这么一个功能。在App内部发生某个事件时,就会发出提醒,为某个事件订阅或者接收提醒的过程叫做delegation(委托)。例如,我们使用delegate创建table view,并告知要绘制10行。 override func tableView ( tableView: UITableView, numberOfRowsInSection section: Int ) -> Int { //Return the number of rows in the section return 10 } UITableViewController UITableViewController会自动创建一个table view,然后设置tableView属性,同时也需要委托自己获取所有需要的delegate方法。 UITableViewDataSource UITableView的delegate协议有三个必须要写的方法,叫做UITableViewDataSource。这个协议包括组的数量,美组中行的数量,以及cell如何展现。 第一个方法是numberOfSectionsInTableView(_:),如: override func numberOfSectionsInTableView(tableView: UITableView) -> Int { //#warning Potentially incomplete method implementation. //return the number of sections. return 0 } 注:注意到return那行目前是零,这意味着这个table view中没有组。苹果公司增加了一个警告注释,说如果组的个数是零,那么就不会显示行,组包含行cell,没有了组section,行cell也就不会被显示出来。 第二个方法是tableView(_:numberOfRowsInSection:),这个方法决定了某个组里具体有多少行,当然这里也不能为0: override func tableView(tableView: UITableView,numberOfRowsInSection section: Int) -> Int { //#warning Incomplete method implementation // Return the number of rows in the section return 5 } 第三个方法是tableView(:cellForRowAtIndexPath:),这个方法里有个参数值叫indexPath,是一个NSIndexPath。section组属性的索引是当前组,cell行属性的索引是当前行: 第一组第一行的索引NSIndexPath是0,0。 第一组第四行的索引NSIndexPath是0,3。 第三组第一行的索引NSIndexPath是2,0。可以用点语法调用section和row属性: var currentRow = indexPath.row var currentSection = indexPath.section tableView代码: override func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell =tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell return cell } ios跳转实例 为了方便大家的理解,我们先来一个简单的跳转的实例。1)打开Xcode,点击顶部菜单栏的File -> New -> Project,从模板中选择Single View Application,点击Next。如图: 2)输入项目名称等属性,点击Next。 3)打开Main.storyboard,点击Inspector上工具栏中第一个图标File Inspector,鼠标移动到到中间部分,不勾选Use Auto Layout选项。这时会出现一个对话框,选择iPhone。 4)选中这个界面,然后点击顶部菜单栏的Editor -> Embed In -> Navigation Controller。一个新的scene会增加到Storyboard中,一个scene表示App一屏或者一个界面。Navigation Controller Scene和之前的View Controller Scene是连接在一起的,这连接说明View Controller Scene是Navigation Controller Scene里第一个出现视图,点击Storyboard Editor左下角的盒子按钮打开Document Outline,Document Outline显示了storyboard文件中所有的控件以及控件所处的层次等级。 5)接下来我们在ViewController.m中新建一个按钮,用来跳转到第二个界面。先创建一个按钮,代码如下: UIButton * button=[UIButton buttonWithType:UIButtonTypeSystem]; button.frame=CGRectMake(130, 220, 100, 30); [button addTarget:self action:@selector(toNext) forControlEvents:UIControlEventTouchUpInside]; [button setTitle:@"跳转登录" forState:UIControlStateNormal]; [self.view addSubview:button]; 然后通过action添加跳转方法: //跳转到登录界面 -(void)toNext{ UIBarButtonItem * back=[[UIBarButtonItem alloc]init]; back.title = @"返回"; self.navigationItem.backBarButtonItem = back; SecondViewController * second = [[SecondViewController alloc]init]; [self.navigationController pushViewController:second animated:YES]; } 整体的代码结构如下:

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

swift基础知识二

//1.if语句以及强制解析 //可以使用if语句和nil比较来判断一个可选值是否包含值,可以使用“==”,'!= ' 来执行比较 //如果可选类型有值,它将不等于nil var num:Int? = 3 if num != nil { print("值不为空") } //感叹号 ! //当你判断一个可选类型确实包含值之后,你可以在可选的名字后面加上感叹号(!)来获取值,这个感叹号表示“我知道这个可选类型有值,请使用它”。这个被称为可选值的强制解析。 //注意:使用!来获取一个不存在的可选值会导致运行时错误。使用!来强制解析值之前,一定要确定可选包含一个非nil的值。 //2.可选绑定 //使用可选绑定来判断可选类型是否包含值,如果包含,就把值赋值给一个临时常量或者变量。可选绑定可以用在if和while语句中,这条语句不仅可以用来判断可选类型是否有值,同时把可选类型的值赋给常量或者变量。 let empty:String? = nil if let constName = num { print(constName) } if let em = empty { print("aaaaaa") }else{ print("判断为假") } if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 { print("\(firstNumber) < \(secondNumber) < 100") } // 输出 "4 < 42 < 100" if let firstNumber = Int("4") { if let secondNumber = Int("42") { if firstNumber < secondNumber && secondNumber < 100 { print("\(firstNumber) < \(secondNumber) < 100") } } } // 输出 "4 < 42 < 100" //注意:在if条件语句中使用常量和变量来创建一个可选绑定,仅在if语句的句中(body)中才可以获取可选绑定的值。 //相反,在guard语句中使用常量和变量来创建一个可选绑定,仅在guard语句外且在语句后才能获取到值。 //3.隐式解析可选类型 /* 如上所述,可选类型暗示了常量或者变量可以“没有值”。可选可以通过 if 语句来判断是否有值,如果有值的话可以通过可选绑定来解析值。 有时候在程序架构中,第一次被赋值之后,可以确定一个可选类型总会有值。在这种情况下,每次都要判断和解析可选值是非常低效的,因为可以确定它总会有值。 这种类型的可选状态被定义为隐式解析可选类型(implicitly unwrapped optionals)。把想要用作可选的类型的后面的问号(String?)改成感叹号(String!)来声明一个隐式解析可选类型。 当可选类型被第一次赋值之后就可以确定之后一直有值的时候,隐式解析可选类型非常有用。隐式解析可选类型主要被用在 Swift 中类的构造过程中 */ let possibleString :String? = "An optional string" let forcedString :String = possibleString! //需要感叹号来获取值,没有感叹号会报错 let assumeString :String! = "一个隐式解析可选值" let implicitString :String = assumeString //不需要感叹号 //你可以把隐式解析可选类型当做一个可以自动解析的可选类型。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。 //注意: //如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个惊叹号一样。 //4.错误处理 //可以使用 错误处理来应对程序执行中可能遇到的错误条件。

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

swift基础知识一

import UIKit var str = "Hello, playground" //1.变量,常量 let max = 10 var current = 0 if current < max { print(current) } var x = 0,y = 0.0 //2.类型标注 var message:String message = "Hello" //常量和变量的命名可以使任何喜欢的字符,但是,不能包含数学符号,箭头,保留的(或者非法的)Unicode 码位,连线与制表符,也不能以数字开头 let pai = 3.14 let 你好 = "中国🇨🇳" let = "" let ww2 = "heihei" let bool = false //3.分号 //并不强求在每一行的末尾添加分号,也可以根据自己习惯添加,但是有一种情况必须添加,你打算在同一行添加多条独立语句的时候,必须用分号隔开 let first = 0; var second = "haahhaah";print(first,second) //4.整数:没有小数部分的数字,包括有符号整数(正,负,零)和无符号整数(正,零) //swift提供 8,16,32,64位有符号和无符号整数类型 //整数范围:可以访问不同类型整数的最大值和最小值 let minValue = UInt8.min let maxValue = UInt8.max //(2的8次方) let min16 = UInt16.min let max16 = UInt16.max //(2的16次方) //Int //一般情况下,不需要专门指定整数长度,Int的长度与当前平台的原生字长相同 let minInt = Int.min //(本机最小字长,64位) let maxInt = Int.max //数值型字面量 //十进制:没有前缀 //二进制:0b //八进制:0o //十六进制:0x //如果一个十进制数的指数为 exp,那这个数相当于基数和10^exp的乘积: print(1.25e2)//1.25*10^2 print(1.25e-2)//1.25*10^-2 //如果一个十六进制数的指数为exp,那这个数相当于基数和2^exp的乘积: print(0xFp2) //15*2^2 print(0xFp-2) //15*2^-2 相当于15*1/4 //整数类型转换,其他类型转换类似 let twoThousand:UInt16 = 2_000 let one:UInt8 = 1 let sum = twoThousand + UInt16(one) //5.类型别名,typealias //给现有类型起一个别的名字,当你想要给现有类型起一个更有意义的名字时,类型别名非常有用。 typealias AudioSample = UInt16 var maxAudioS = AudioSample.max //6.BOOL 布尔值 true false let yes = true let no = false //Bool类型和整型不可以转换,非零即真在swift中是不适用的 //7.元组 //元组把多个值组合成一个复合值,元组内的值可以使任意类型,并不要求是相同类型 let httpError = (404,"Not Found") //httpError的类型是(Int,String),值是(404,"Not Found") //可以将元组内容分解成单独的常量和变量,然后就可以使用它们了 let (statusCode,statusMessage) = httpError print("错误码:(statusCode),错误信息:(statusMessage)") //如果你只需要一部分的元组值,分解的时候可以把要忽略的部分用(_)标记 let (justCode,_) = httpError print("错误 \(justCode)") //可以通过下标访问元组中的元素,下标从0开始 print(httpError.0) print(httpError.1) //定义元组的时候给单个元素命名,命名后可以通过名字访问元组元素的值 let httpOK = (code:200,desc:"OK") print(httpOK.code) print(httpOK.desc) //作为函数返回值的时候,元组是非常有用的 //8.可选类型 optionals //使用可选类型来处理值可能缺失的情况,可选类型表示: //1》有值,等于x //2》没有值 //例如:String转Int,有可能成功,也有可能失败 let possibleNum = "123" let possibleStr = "Hello" let converNum = Int(possibleNum) let converStr = Int(possibleStr) print(possibleNum) print(possibleStr) var cc = converNum! + 1 //var dd = converStr! + 1 //报错 //上面的转换还可以这么写 let conver:Int? = Int(possibleNum) let conver2:Int? = Int(possibleStr) var ee = converNum! + 1 //var ff = converStr! + 1 报错 //你可以给一个可选变量赋值为nil表示它没有值 var serverResCode:Int? = 404 serverResCode = nil //现在serverResCode不包含值 //注意:nil不能用于非可选的变量或者常量 //如果你声明一个可选的常量或者变量但是没有赋值,它们会自动设置成nil var surverAnswer:String? //注意:Swift的nil和OC的nil的意义是不一样的,OC中的nil是指向不存在对象的指针。在Swift中,nil不是指针,它是一个确定的值,表示值缺失。任何类型的值缺失都可以被设置成nil,而不只是对象类型。

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

Android 应用基础知识

Android 应用采用 Java 编程语言编写,Android SDK 工具将代码连同任何数据和资源文件编译到一个 APK(Android 软件包)当中,即带有 .apk 后缀的存档文件中。一个 APK 文件包含 Android 应用的所有内容,它是基于 Android 系统的设备用来安装应用的文件 安装到设备后,每个 Android 应用都运行在自己的安全沙箱内: Android 操作系统是一种多用户 Linux 系统,其中的每个应用都是一个不同的用户 默认情况下,系统会为每个应用分配一个唯一的 Linux 用户 ID(该 ID 仅由系统使用,应用并不知晓)。系统为应用中的所有文件设置权限,使得只有分配给该应用的用户 ID 才能访问这些文件 每个进程都具有自己的虚拟机 (VM),因此应用代码是在与其他应用隔离的环境中运行 Android 系统可以通过这种方式实现最小权限原则。也就是说,默认情况下,每个应用都只能访问执行其工作所需的组件,而不能访问其他组件。 这样便营造出一个非常安全的环境,在这个环境中,应用无法访问系统中其未获得权限的部分 不过,应用仍然可以通过一些途径与其他应用共享数据以及访问系统服务: 可以安排两个应用共享同一 Linux 用户 ID,在这种情况下,它们能够相互访问彼此的文件。 为了节省系统资源,可以安排具有相同用户 ID 的应用在同一 Linux 进程中运行,并共享同一 VM(应用还必须使用相同的证书签署) 应用可以请求访问设备数据(如用户的联系人、短信、可装载存储装置 [SD 卡]、相机、蓝牙等)的权限。 用户必须明确授予这些权限 一、核心框架组件 应用组件是 Android 应用的基本构建基块。每个组件都是一个不同的点,系统可以通过它进入应用中。 并非所有组件都是用户的实际入口点,有些组件相互依赖,但每个组件都以独立实体形式存在,并发挥特定作用 — 每个组件都是唯一的构建基块,有助于定义应用的总体行为 共有四种不同的应用组件类型。每种类型都服务于不同的目的,并且具有定义组件的创建和销毁方式的不同生命周期 以下便是这四种应用组件类型: Activity Activity 表示具有用户界面的单一屏幕。例如,电子邮件应用可能具有一个显示新电子邮件列表的 Activity、一个用于撰写电子邮件的 Activity 以及一个用于阅读电子邮件的 Activity。 尽管这些 Activity 通过协作在电子邮件应用中形成了一种紧密结合的用户体验,但每一个 Activity 都独立于其他 Activity 而存在。 因此,其他应用可以启动其中任何一个 Activity(如果电子邮件应用允许)。 例如,相机应用可以启动电子邮件应用内用于撰写新电子邮件的 Activity,以便用户共享图片 服务 服务是一种在后台运行的组件,用于执行长时间运行的操作或为远程进程执行作业。 服务不提供用户界面。 例如,当用户位于其他应用中时,服务可能在后台播放音乐或者通过网络获取数据,但不会阻断用户与 Activity 的交互。 诸如 Activity 等其他组件可以启动服务,让其运行或与其绑定以便与其进行交互 内容提供者 内容提供程序管理一组共享的应用数据,可以将数据存储在文件系统、SQLite 数据库、网络上或应用可以访问的任何其他永久性存储位置。 其他应用可以通过内容提供程序查询数据,甚至修改数据(如果内容提供程序允许)。 例如,Android 系统可提供管理用户联系人信息的内容提供程序。 因此,任何具有适当权限的应用都可以查询内容提供程序的某一部分(如 ContactsContract.Data),以读取和写入有关特定人员的信息 内容提供程序也适用于读取和写入您的应用不共享的私有数据。 例如,记事本示例应用使用内容提供程序来保存笔记 广播接收器 广播接收器是一种用于响应系统范围广播通知的组件。 许多广播都是由系统发起的 。例如,通知屏幕已关闭、电池电量不足或已拍摄照片的广播。应用也可以发起广播 ,例如,通知其他应用某些数据已下载至设备,并且可供其使用。 尽管广播接收器不会显示用户界面,但它们可以创建状态栏通知,在发生广播事件时提醒用户。 但广播接收器更常见的用途只是作为通向其他组件的“通道”,设计用于执行极少量的工作。 例如,它可能会基于事件发起一项服务来执行某项工作 Android 系统设计的独特之处在于,任何应用都可以启动其他应用的组件。 例如,如果想让用户使用设备的相机拍摄照片,很可能有另一个应用可以执行该操作,那么你的应用就可以利用该应用,而不是开发一个 Activity 来自行拍摄照片。 不需要集成甚至链接到该相机应用的代码,而是只需启动拍摄照片的相机应用中的 Activity。 完成拍摄时,系统甚至会将照片返回您的应用,以便应用使用。对用户而言,就好像相机真正是应用的组成部分。 当系统启动某个组件时,会启动该应用的进程(如果尚未运行),并实例化该组件所需的类。 例如,如果你的应用启动相机应用中拍摄照片的 Activity,则该 Activity 会在属于相机应用的进程,而不是你的应用的进程中运行。因此,与大多数其他系统上的应用不同,Android 应用并没有单一入口点(例如,没有 main() 函数) 由于系统在单独的进程中运行每个应用,且其文件权限会限制对其他应用的访问,因此你的应用无法直接启动其他应用中的组件, 但 Android 系统却可以。因此,要想启动其他应用中的组件,你必须向系统传递一则消息,说明想启动特定组件的 Intent。 系统随后便会为你启动该组件 二、Intent 四种组件类型中的三种:Activity、服务和广播接收器 ,都通过名为 Intent 的异步消息进行启动。Intent 会在运行时将各个组件相互绑定(可以将 Intent 视为从其他组件请求操作的信使),无论组件属于你的应用还是其他应用。 Intent 使用 Intent 对象创建,它定义的消息用于启动特定组件或特定类型的组件 — Intent 可以是显式的,也可以是隐式的 对于 Activity 和服务, Intent 定义要执行的操作(例如,“查看”或“发送”某个内容),并且可以指定要执行操作的数据的 URI(以及正在启动的组件可能需要了解的信息)。 例如, Intent 传达的请求可以是启动一个显示图像或打开网页的 Activity。 在某些情况下,可以启动 Activity 来接收结果,在这种情况下,Activity 也会在 Intent 中返回结果(例如,可以发出一个 Intent,让用户选取某位联系人并将其返回给应用,返回 Intent 包括指向所选联系人的 URI) 对于广播接收器, Intent 只会定义要广播的通知(例如,指示设备电池电量不足的广播只包括指示“电池电量不足”的已知操作字符串) Intent 不会启动另一个组件类型:内容提供程序,后者会在成为 ContentResolver 的请求目标时启动。 内容解析程序通过内容提供程序处理所有直接事务,使得通过提供程序执行事务的组件可以无需执行事务,而是改为在 ContentResolver 对象上调用方法。 这会在内容提供程序与请求信息的组件之间留出一个抽象层(以确保安全) 每种类型的组件有不同的启动方法: 可以通过将 Intent 传递到 startActivity() 或 startActivityForResult()(当想让 Activity 返回结果时使用)来启动 Activity(或为其安排新任务) 可以通过将 Intent 传递到 startService() 来启动服务(或对执行中的服务下达新指令)。 或者,也可以通过将 Intent 传递到 bindService() 来绑定到该服务 可以通过将 Intent 传递到 sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast() 等方法来发起广播 可以通过在 ContentResolver 上调用 query() 来对内容提供程序执行查询 三、清单文件 在 Android 系统启动应用组件之前,系统必须通过读取应用的 AndroidManifest.xml 文件("清单"文件)确认组件存在。应用必须在此文件中声明其所有组件,该文件必须位于应用项目目录的根目录中。 除了声明应用的组件外,清单文件还有许多其他作用,如: 确定应用需要的任何用户权限,如互联网访问权限或对用户联系人的读取权限 根据应用使用的 API,声明应用所需的最低 API 级别 声明应用使用或需要的硬件和软件功能,如相机、蓝牙服务或多点触摸屏幕 应用需要链接的 API 库(Android 框架 API 除外),如 Google 地图库 其他功能 四、声明组件 清单文件的主要任务是告知系统有关应用组件的信息。例如,清单文件可以像下面这样声明 Activity: <?xml version="1.0" encoding="utf-8"?> <manifest ... > <application android:icon="@drawable/app_icon.png" ... > <activity android:name="com.example.project.ExampleActivity" android:label="@string/example_label" ... > </activity> ... </application> </manifest> 在< application >元素中,android:icon 属性指向标识应用的图标所对应的资源 在< activity >元素中,android:name 属性指定 Activity 子类的完全限定类名,android:label 属性指定用作 Activity 的用户可见标签的字符串。 通过以下方式声明所有应用组件: Activity 的 < activity > 元素 服务的 < service > 元素 广播接收器的 < receiver > 元素 内容提供者的 < provider > 元素 包含在源代码中,但未在清单文件中声明的 Activity、服务和内容提供者对系统不可见,因此也永远不会运行。 不过,广播接收器可以在清单文件中声明或在代码中动态创建(如 BroadcastReceiver 对象)并通过调用 registerReceiver() 在系统中注册 五、声明组件功能 如上文启动组件中所述,可以使用 Intent 来启动 Activity、服务和广播接收器。 你可以通过在 Intent 中显式命名目标组件(使用组件类名)来执行此操作。 不过,Intent 的真正强大之处在于隐式 Intent 概念。 隐式 Intent 的作用无非是描述要执行的操作类型(还可选择描述想执行的操作所针对的数据),让系统能够在设备上找到可执行该操作的组件,并启动该组件。 如果有多个组件可以执行 Intent 所描述的操作,则由用户选择使用哪一个组件 系统通过将接收到的 Intent 与设备上的其他应用的清单文件中提供的 Intent 过滤器进行比较来确定可以响应 Intent 的组件。 当在应用的清单文件中声明 Activity 时,可以选择性地加入声明 Activity 功能的 Intent 过滤器,以便响应来自其他应用的 Intent。 可以通过将 < intent-filter > 元素作为组件声明元素的子项进行添加来为组件声明 Intent 过滤器 例如,如果你开发的电子邮件应用包含一个用于撰写新电子邮件的 Activity,则可以像下面这样声明一个 Intent 过滤器来响应“send” Intent(以发送新电子邮件): <manifest ... > ... <application ... > <activity android:name="com.example.project.ComposeEmailActivity"> <intent-filter> <action android:name="android.intent.action.SEND" /> <data android:type="*/*" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest> 然后,如果另一个应用创建了一个包含ACTION_SEND操作的 Intent,并将其传递到 startActivity(),则系统可能会启动你的 Activity(因为系统中可能有多个应用能提供该服务,所以需要用户来选定使用哪个Activity),以便用户能够用来发送电子邮件 六、声明应用要求 基于 Android 系统的设备多种多样,并非所有设备都提供相同的特性和功能。 为防止将应用安装在缺少应用所需特性的设备上,必须通过在清单文件中声明设备和软件要求,为应用支持的设备类型明确定义一个配置文件。 其中的大多数声明只是为了提供信息,系统不会读取它们,但 Google Play 等外部服务会读取它们,以便当用户在其设备中搜索应用时为用户提供过滤功能 例如,如果应用需要相机,并使用 Android 2.1(API 级别 7)中引入的 API,则应该像下面这样在清单文件中以要求形式声明这些信息: <manifest ... > <uses-feature android:name="android.hardware.camera.any" android:required="true" /> <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> ... </manifest> 现在,没有相机且 Android 版本低于 2.1 的设备将无法从 Google Play 安装该应用。 不过,你也可以声明应用有使用到相机,但并不要求必须使用。 在这种情况下,应用必须将 required 属性设置为 "false",并在运行时检查设备是否具有相机,然后根据需要停用任何相机功能 七、应用资源 Android 应用并非只包含代码,它还需要与源代码分离的资源,如图像、音频文件以及任何与应用的视觉呈现有关的内容。 例如,你应该通过 XML 文件定义 Activity 用户界面的动画、菜单、样式、颜色和布局。 使用应用资源能够在不修改代码的情况下轻松地更新应用的各种特性,并可通过提供备用资源集让你能够针对各种设备配置(如不同的语言和屏幕尺寸)优化应用。 对于Android 项目中包括的每一项资源,SDK 构建工具都会定义一个唯一的整型 ID,你可以利用它来引用应用代码或 XML 中定义的其他资源中的资源。 例如,如果应用包含一个名为 logo.png 的图像文件(保存在 res/drawable/ 目录中),则 SDK 工具会生成一个名为 R.drawable.logo 的资源 ID,可以利用它来引用该图像并将其插入用户界面当中 提供与源代码分离的资源的其中一个最重要优点在于,您可以提供针对不同设备配置的备用资源。 例如,通过在 XML 中定义 UI 字符串,可以将字符串翻译为其他语言,并将这些字符串保存在单独的文件中。 然后,Android 系统会根据向资源目录名称追加的语言限定符(如为法语字符串值追加 res/values-fr/)和用户的语言设置,应用相应的语言字符串 Android 支持许多不同的备用资源限定符。限定符是一种加入到资源目录名称中,用来定义这些资源适用的设备配置的简短字符串。 再举一例,你应该经常会根据设备的屏幕方向和尺寸为 Activity 创建不同的布局。 例如,当设备屏幕为纵向(长型)时,你可能想要一种垂直排列按钮的布局;但当屏幕为横向(宽型)时,应按水平方向排列按钮。 要想根据方向更改布局,你可以定义两种不同的布局,然后对每个布局的目录名称应用相应的限定符。 然后,系统会根据当前设备方向自动应用相应的布局

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

Swift入门基础知识

var //代表变量,变量的值可以改变 let//代表常量类型不可改变 //声明常量heh类型Swift会自动根据你的值来自动判断该变量的类型也可以指定类型(个人感觉还是指定类型的比较好,可能会减少系统的开销),值为10 //自动判断变量的类型 let heh = 10//假如在下面的代码中没有用到该变量Swift就会提示将let改为下划线,因为下划线代表忽略该变量,就相当于OC中提示并没有用该属性或者变量一样,估计没用到的变量一般人也不会写,只是给刚入门的说一下并不是你写错了或者Xcode有问题,只是Swift提示很细 //声明指定变量的类型 let heh:Double = 10.000 //声明变量hehe类型Swift会自动根据你的值来自动判断该变量的类型也可以指定类型(个人感觉还是指定类型的比较好),值为10 var heh:Double = 10//假如声明的变量没有改变的话Swift也会提示将其改为let //修改变量的值 heh = 12 //输出打印信息 print(heh) Swift还可以用中文当作变量的名字,因为Swift支持unicode编码,所以变量名可以是中文甚至是表情(感觉中文还是好一点,和java一样代码的风格也都和java一样) 比如: var 测试:Double = 10 测试 = 12 print(测试) 而且Swift的字符串不用带@,直接""就可以了 //遍历字符串 let zifu:String="abcdefghijk" for zf in zifu.characters { print(zf) } 或者也可以这样直接将字符串进行遍历(因为Swift会自动把字符串判断成String类型) for zf in "abcdefghijk".characters { print(zf) } //合并字符串(表示和java基本上就是一样啊)直接用加号就可以了字符串a,b。合成字符串c就是c=a+b let zifu:String="abcdefghijk" let zf2="xyz" let zf3 = zifu+zf2 print(zf3) print(zifu+zf2) //转义输出就是5*10=50 let a = 5 let b = 10 let js = "\(a)*\(b)=\(a*b)" print(js) //数组数组元素必须统一这个就不说了 let names = ["赵","钱","孙","李","周","吴","正","王"] print(names) //字典假如键所对应的值类型都是一样就照着下面写就可以 let zidian = ["a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9,"j":10,"k":11] print(zidian) 假如值的类型有很多种那么Swift就会提示变成下面这种 let zd = ["jian":"zhi","hehe":5,"sds":8,"sdffd":43,"fdss":"dsdds","dasa":"dsdsd","cdsd":454] as [String : Any] 一看就知道了,后面语句的意思就是键是String类型的,而值为任意类型的 //循环(基本上其他语言有的这里都有) for zf in "abcdefghijk".characters { print(zf) } //1...5代表遍历1到5包括1和5(三个点代表全闭区间) for number in 1...5 { print(number) } //1..5代表遍历1到5包括1但不包括5(两个点代表半开半闭区间不包含右边的区尾) fornumberin1..5{ print(number) } //遍历字典,可以一下就把键和值都遍历出来 let zd = ["jian":"zhi","hehe":5,"sds":8,"sdffd":43,"fdss":"dsdds","dasa":"dsdsd","cdsd":454] as [String : Any] for (j,z) in zd { print("键=\(j),值=\(z)") } //数组操作 //数组数组元素必须统一这个就不说了 var names = ["赵","钱","孙","李","周","吴","正","王"] //显示元素 print(names[0]) //增加元素 names.append("冯") //修改元素 names[0]="陈" //把第三个元素到第五个元素替换掉 names[3...5]=["楚","魏"] //字典 //定义一个可变字典 var zidian = ["a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9,"j":10,"k":11] //修改字典某个键的值 zidian["a"]=8 //方法,Swift中的方法是这样的 //参数和返回值都为空的一个方法 func kong() { print("空") } //带参数的方法,但是没有返回值 func hello(hehe:String) { print("\(hehe)") } //带参数并且有返回值 func fanhuizhi(name:String) -> String { return name } //多参数多返回值 func duofanhuizhi() -> (Int,String) { return(200,"haha") } //多参数多返回值第二种类型 func duofanhuizhi2() -> (code:Int,name:String) { return(200,"haha") }

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

Android内存基础——内存泄漏

个人博客CoorChice,https://chenbingx.github.io/ ,最新文章将会首发CoorChice的博客,欢迎探索哦 ! 同时,搜索微信公众号CoorChice,或扫描文章末尾二维码,可以关注我的微信公众号。同期文章也将会优先推送到微信公众号中,以提醒您有新鲜文章出炉。 背景介绍 内存泄漏一种情况是一块内存没有引用指向它,却没被回收,这种情况已经由Java虚拟机的GC帮助我们处理好了,见Java内存管理机制;另一种属于逻辑内存泄漏,即一个对象已经不再被使用了,但它仍然被另一个被使用中的对象所持有,导致该对象所占用的内存块不能被回收。 少部分内存泄漏看不出有什么影响,但如果大量发生,将会明显减少可用内存,导致频繁GC,运行缓慢,严重时将容易引发OutOfMemoryError。 Android中常见的内存泄漏 集合引发的泄漏 一些对象缓存到集合中,当它不在被使用时,没有从集合中移除,就造成了泄漏。 Activity中的泄漏 一个Activity中的Context通常会被很多地方引用,如果在Activity执行了onDestory()后这些引用没有被置空,将会导致Activity无法被回收。而Activity中依赖了很对对象,这些对象将都不能被回收,所以一定要十分小心Activity的泄漏。以下几种常见的情况需要注意: 当创建一个对象,该对象需要Context作为参数时。当该对象在Activity执行了onDestory()后仍然可到达,那么它持有的Activity就无法被回收。 使用匿名内部类Handler时。Handler会间接的持有外部Activity的引用,当Activity执行了onDestory()后,若Handler中仍然有消息在MessageQueue中,那么该Handler就不能被释放,也就意味着Activity也不会被释放。解决方法: 需要在onDestory()完成前确保Handler没有执行yan shi延时任务,没有被其他地方引用。同时清理Handler中所有任务,调用removeCallbacksAndMessages(null);,该方法参数为空时会移除所以的CallBack和Message。 另一种方法是自定义一个静态内部Handler,让它持有的Activity为弱引用。 static class MyHandler extends Handler { private final WeakReference<Activity> mActivity; public MyHandler(Activity activity) { mActivity = new WeakReference<Activity>(activity); } @Override public void handleMessage(Message msg) { System.out.println(msg); if (mActivity.get() == null) { return; } mActivity.get().todo(); } } 在异步任务中引用Activity或Context,而没有在Activity销毁前停止线程,就会导致Activity的泄漏。 内部类、匿名内部类会持有外部类的实例,所以在Activity中使用内部类或匿名内部类,并且将该类创建的对象传递给其他对象,若该对象在Activity之外被引用,或是在仍在进行的异步任务中,那么Activity将不能释放。 Bitmap引发的内存泄漏 Bitmap是引用中占用内存的大户,在使用时一定要十分注意。当Bitmap不用时,应该及时调用recycle()释放其申请的内存。 异步任务引发的泄漏 异步任务如果在它应该停止的时候没有停止,那它本身及它所依赖的对象将都不能被正确的释放。比如上面提到的Activity中的异步任务。 比如在Activity中这样来开启一个异步任务: new Thread(()->{ // doSomething with long-time }).start(); 那么,在Activity已经finish()了,但异步任务中的Runnable还被持有,并且由于是属于Activity的匿名内部类,所以会导致Activity的内存不能及时回收。 总结 由于系统内存资源有限,所以我们需要尽量避免内存泄漏,以保证程序能够流畅运行。 由于Activity泄漏将会连带大量的对象一起泄漏,所以在Activity中写代码应该特别注意Handler、内部类及匿名内部类,还有Context不能随便传递。 使用异步任务时一定要明确其作用范围,在应该停止的时候记得停止。 Bitmap占用内存通常较大,所以在使用完后及时释放十分重要。 此外,在传递参数到单例中时,也需要谨慎。 CoorChice的公众号

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

Android内存基础——内存抖动

个人博客CoorChice,https://chenbingx.github.io/ ,最新文章将会首发CoorChice的博客,欢迎探索哦 ! 同时,搜索微信公众号CoorChice,或扫描文章末尾二维码,可以关注我的微信公众号。同期文章也将会优先推送到微信公众号中,以提醒您有新鲜文章出炉。 参考资料 Google官方讲解视屏 背景介绍 在Java内存管理机制中我提到过内存抖动会引起频繁的GC,从而使UI线程被频繁阻塞,导致画面卡顿。这次我们就聊聊内存抖动。 需要避免内存抖动 内存抖动是由于短时间内有大量对象进出Young Generiation区导致的,它伴随着频繁的GC。通常存在内存抖动时,我们可以在Android Studio的Monitors中看到如下场景: 内存抖动图 下面是避免发生 内存抖动的几点建议: 尽量避免在循环体内创建对象,应该把对象创建移到循环体外。 注意自定义View的onDraw()方法会被频繁调用,所以在这里面不应该频繁的创建对象。 当需要大量使用Bitmap的时候,试着把它们缓存在数组中实现复用。 对于能够复用的对象,同理可以使用对象池将它们缓存起来。 总结 总之,因为内存抖动是由于大量对象在短时间内被配置而引起的,所以我们要做的就是谨慎对待那些可能会大量创建对象的情况。 CoorChice的公众号

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

【原创】HBase 基础知识

特点 1. 在 HDFS 之上开发的; 2. 面向列(实际是面向列族)的存储器 3. 实时读写 4. 随机读写 5. 针对超大规模数据集 6. 不支持 SQL 基本概念 单元格(cell) 由行和列的坐标交叉决定,有版本号; 版本号默认为自动分配,为 HBase 向单元格插入数据时的时间戳; 单元格中的内容为未解释的字节数组 行的键 表中行的键为字节数组; 表中的行根据行的键值(即表的主键)进行排序; 排序依据为字节序; 所有对表的访问都要通过表的主键(二级索引问题); 列族(column family) 行中的列会被划分成不同的列族; 同一列族中成员具有相同的前缀; 列族的前缀必须是可打印字符构成的; 列族修饰符,即结尾字符,可以为任意字符; 在 HBase 中,规定使用冒号来分隔列族和列族修饰符; 一个表的列族必须作为表模式定义的一部分预先给出,但是心的列族成员可以随后按需要加入; 物理上,所有的列族成员都一起存放在文件系统中; HBase 的调优和存储都在列族这个层次上进行的,所以最好使所有列族成员都有相同的访问模式(access pattern)和大小特征。 区域(region) HBase 自动把表水平划分成区域; 每个区域由表中行的子集构成; 一开始,一个表只有一个区域,随着表变大,区域的个数也会增加; 区域是在 HBase 中分布数据的最小单位; 在线的所有区域按次序排列就构成了表的所有内容; 锁 无论对行进行访问的事务牵涉多少列,对行的更新都是原子的; 构成 HBase 模型为一个 Master 节点负责协调管理一个或多个 Regionserver 从属机; Master 负责:启动(bootstrap)、全新的安装、将区域分配给注册的 Regionserver 、恢复 Regionserver 的故障。 Regionserver 负责:零个或多个区域的管理,响应客户端的读写请求,区域的划分,通知 Master 有新子区域(daughter region)产生; HBase 依赖于 Zookeeper ,默认情况下,HBase 管理一个 Zookeeper 实例,用于作为集群的权威(authority); HBase 负责管理根目录表(root catalog table)的位置、当前集群 Master 地址等重要信息; 相关文件 conf/regionservers -- 可以查看 Regionserver 节点信息 conf/hbase-site.xml 和 conf/hbase-env.sh -- 集群站点配置 持久化接口 本地文件系统接口(默认) KFS 文件系统接口 Amazon S3 接口 HDFS 接口 若要使用 HBase 集群,则通常要把 HBase 的存储配置为指向 HDFS 集群; 特殊表(涉及数据定位过程问题) -ROOT- 表包含 .META. 表的区域列表; .META. 表包含所有用户空间区域(user-space region)的列表; 在 Regionserver 上进行读写操作 写操作 追加方式写入提交日志(commit log),提交日志存放在 HDFS 中(保证高可用); 写入内存中的 memstore ; 若 memstore 满,则刷入(flush)文件系统; 读操作 查看区域(region)的 memstore ; 若在 memstore 中找到需要的版本则直接返回,否则按照次序从新到旧检查 flush file ; Regionserver 上存在一个后台进程负责在 flush file 数量达到阈值后,对其进行压缩处理(将多个文件的内容处理后写入一个文件中) HBase 提供的对外接口 Avro REST Thrift 通过上述接口和 HBase 集群进行双向交互时,需要 HBase 客户端实例进行代理,故比直接 JAVA 客户端交互更慢。 服务的启动和停止 hbase-daemon.sh <start|stop> <rest|thrift|avro> 对比 HDFS 和 MapReduce 适用于对大数据集进行批处理,但对于读或写单独的记录,效率很低;而 HBase 可以高效完成; HDFS 和 MapReduce 不擅长在有更新到达时维护索引(虽然 MapReduce 作业可以用于建立索引以支持随机访问),所以不符合低延时查询需求,而 HBase 可以; 大数据集需求 -> 排除 RDBMS 的使用(可能有点绝对) 低查询延时 -> 排除直接使用 HDFS ;

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

docker基础入门之一

一、概述 1、传统虚拟化技术: 纯软件的虚拟化是通过对于硬件层的模拟从而实现允许运行多个操作系统; 硬件辅助虚拟化需要硬件层面对于虚拟化的支持,类似Intel-VT技术等,具有更高的运行效率; 解决方案: 商业版解决方案:VMware vSphere、 VMware Fusion 开源解决方案:KVM、Xen 2、system-level虚拟化(container虚拟机技术): 不需要模拟硬件层; 共享同一个HOST OS的Kernal user space instance = Container 解决方案: LXC: OpenVZ: Docker: Imctfy:google开源的容器虚拟实现 3、容器虚拟化和传统虚拟化的区别: 传统虚拟化 容器虚拟化 创建速度 很慢 非常快 性能影响 通过对于硬件层的模拟,增加了系统调用链路 的环节,有性能损耗 共享Kernel,几乎没有性能损耗 资源消耗 很大 很小,一台机器可以轻松创建多个 Container 操作系统覆盖 支持Linux、windows、Mac等 仅仅支持Kernal所支持的OS 4、container核心技术cgroups,namespace,chroot: CGroups 限制容器的资源使用; Linux内核提供的限制,记录和隔离进程组所使用的资源,由Google工程师提出,后来整合进kernel; 通过不同的子系统(blkio、cpu、cpuacct等)来实现对不听资源使用的控制和记录; Namespace机制,实现容器间的隔离; pid,容器有自己独立的进程表和1号进程 net,容器有自己独立的network info ipc,在ipc通信时候,需要加入额外信息来标识进程;(进程间通信) mnt,每个容器有自己唯一的目录挂载; utc,每个容器有独立的hostname和domain chroot,隔离根文件系统: 将host os的某个目录隔离成container的根目录; 二、进入Docker的世界: dotCloud是docker公司的前身,专注于PaaS的云计算平台;可能是支持最广泛的PaaS平台; 使用container的概念来解决应用stack部署的难题; 定义:什么是docker 开源的应用容器引擎,方便打包发布应用到容器中; Go语音领域比较大型的应用; docker实现: docker是container技术的实现,最早使用LXC作为container的引擎,最新版本的docker使用libcontainer替换了lxc; 采用aufs文件系统来管理Image和container 基于C/S架构的实现,Server端使用UnixSocket,也可以切换到TcpProtocol; aufs文件系统: 1、advanced multi layer unification filesystem //先进的多层的联合文件系统 2、可以实现把多个不同目录的内容合并在一起; 3、允许read-only和read-write目录并存; docker中的aufs: docker使用aufs来实现分层的文件系统的管理; 只读部分定义为Image,可写部分是container Image类似一个单链表系统,每个Image包含一个指向parent image的指针; 没有parent Image的image是base Image docker hub: 类似于Github服务,用来分发Image 大量标准的Image,例如Tutum/Ubuntu, Tutum/Mysql docker的优点: 构建标准化的应用运行的环境; 良好的RestAPI的实现; Container的实现,更少的资源的使用,创建速度快; docker的局限性: 基于Linux64的,不能在32bit的环境下运行; GuestOS只能是Linux Base 隔离性相对于KVM等虚拟化技术有所欠缺; 采用cgroup的resource control对于cpu的度量很困难; container随用户进程的停止而销毁; docker和LXC的区别: docker更专注于部署,而LXC专注于进程的隔离; docker有更好的api的方便对于docker容器的管理; dockerfile让image的创建变得容易; 通过docker hub方便image的分享; docker的未来: 网络 安全性 容器引擎

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

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应用均可从中受益。

Rocky Linux

Rocky Linux

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

用户登录
用户注册