首页 文章 精选 留言 我的

精选列表

搜索[programming],共1202篇文章
优秀的个人博客,低调大师

Programming access to Android Market

如果你在Android Market上发布了程序,怎么通过程序访问,查看程序的信息呢?谷歌大神为我们提供了--An open-source API for the Android Market,另外,也给Ruby和PHP都留了接口,当然了访问是需要Google帐户滴,更多信息请看考:http://code.google.com/p/android-market-api/ OK,废话少说,That's it! Current progress¶ You can browse market with any carrier or locale you want. Search for apps using keywords or package name. Retrieve an app info using an app ID. Retrieve comments using an app ID. Get PNG screenshots and icon Requirement: A google account is required. Include androidmarketapi-X.Y.jar and protobuf-java-X.Y.Z.jar in your classpath ,下载地址:http://code.google.com/p/android-market-api/downloads/list 需要把这两个JAR导入项目中,由于很好理解,代码就不加注释了 :-) HowToSearchApps: You can search by package using : Stringquery="pname:<package>"; By developper name : Stringquery="pub:<name>"; String query = "pname:com.luckyxmobile.timers4me";// 通过包名查找程序 MarketSessionsession=newMarketSession(); session.login("yourgmailaccount","yourpassword"); AppsRequestappsRequest=AppsRequest.newBuilder().setQuery(query).setStartIndex(0).setEntriesCount(10).setWithExtendedInfo(true).build(); session.append(appsRequest,newMarketSession.Callback<AppsResponse>(){ @Override publicvoidonResult(ResponseContextcontext,AppsResponseresponse){ TextViewtext=(TextView)findViewById(R.id.text); Stringid=response.getApp(0).getId(); StringcreatorID=response.getApp(0).getCreatorId(); Stringcreator=response.getApp(0).getCreator(); StringpackageName=response.getApp(0).getPackageName(); Stringprice=response.getApp(0).getPrice(); Stringrating=response.getApp(0).getRating(); intratingCount=response.getApp(0).getRatingsCount(); Stringtitle=response.getApp(0).getTitle(); Stringversion=response.getApp(0).getVersion(); intversionCode=response.getApp(0).getVersionCode(); intserializedSize=response.getApp(0).getSerializedSize(); ExtendedInfoextendedInfo=response.getApp(0).getExtendedInfo(); text.setText("id:"+id+"\nCreatorId:"+creatorID +"\nCreator:"+creator+"\nPackageName:"+packageName+"\nPrice:"+price+"\nrating:"+rating+"\nRatingCount:"+ratingCount+"\ntitle:" +title+"\nVersion:"+version+"\nversionCode:" +versionCode+"\nDownloadsCount:" +extendedInfo.getDownloadsCount() +"\nDownloadsCountText:"+extendedInfo.getDownloadsCountText()+"\nInstallSize:"+extendedInfo.getInstallSize() +"\nSerializedSize:"+serializedSize+"\nDecription:"+extendedInfo.getDescription()+"\nContactEmail:"+extendedInfo.getContactEmail()+"\nContactPhone:"+extendedInfo.getContactPhone()+"\nContactWebsite:" +extendedInfo.getContactWebsite()); } }); session.flush();//发送并刷新 这是Timers4Me的运行结果: HowToGetAppComments: CommentsRequestcommentsRequest=CommentsRequest.newBuilder().setAppId("7065399193137006744").setStartIndex(0).setEntriesCount(10).build();session.append(commentsRequest,newCallback<CommentsResponse>(){ @OverridepublicvoidonResult(ResponseContextcontext,CommentsResponseresponse){ System.out.println("Response:"+response); //response.getComments(0).getAuthorName() //response.getComments(0).getCreationTime() //... }}); session.flush(); HowToGetAppScreenshot : GetImageRequestimgReq=GetImageRequest.newBuilder().setAppId("-7934792861962808905").setImageUsage(AppImageUsage.SCREENSHOT).setImageId("1").build(); session.append(imgReq,newCallback<GetImageResponse>(){ @OverridepublicvoidonResult(ResponseContextcontext,GetImageResponseresponse){ try{ FileOutputStreamfos=newFileOutputStream("icon.png"); fos.write(response.getImageData().toByteArray()); fos.close(); }catch(Exceptionex){ ex.printStackTrace(); }}}); session.flush(); 以上只是抛砖引玉,更多精彩,只有动手才能看到,good luck! 本文转自 breezy_yuan 51CTO博客,原文链接:http://blog.51cto.com/lbrant/431834,如需转载请自行联系原作者

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

Flink DataStream API Programming Guide

Example Program The following program is a complete, working example of streaming window word count application, that counts the words coming from a web socket in 5 second windows. public class WindowWordCount { public static void main(String[] args) throws Exception { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); DataStream<Tuple2<String, Integer>> dataStream = env .socketTextStream("localhost", 9999) .flatMap(new Splitter()) .keyBy(0) .timeWindow(Time.of(5, TimeUnit.SECONDS)) .sum(1); dataStream.print(); env.execute("Window WordCount"); } public static class Splitter implements FlatMapFunction<String, Tuple2<String, Integer>> { @Override public void flatMap(String sentence, Collector<Tuple2<String, Integer>> out) throws Exception { for (String word: sentence.split(" ")) { out.collect(new Tuple2<String, Integer>(word, 1)); } } } } Flink应用的代码结构如下, Flink DataStream programs look like regular Java programs with amain()method. Each program consists of the same basic parts: Obtaining aStreamExecutionEnvironment, Connecting to data stream sources, Specifying transformations on the data streams, Specifying output for the processed data, Executing the program. 以这个例子,说明 首先会创建socketTextStream,从socket读入text流 接着是个flatMap,和map的不同是,map,1->1,而flatMap为1->n,而这个splitter就是将text用“”分割,将每个word作为一个tuple输出 最后,keyBy产生一个有key的tuple流,这里是以word为key 基于5s的timeWindow,对后面的计数进行sum 最终,output是print Transformations 太常用的就不列了 ============================================================================================== Reduce KeyedStream → DataStream A "rolling" reduce on a keyed data stream. Combines the current element with the last reduced value and emits the new value. keyedStream.reduce(new ReduceFunction<Integer>() { @Override public Integer reduce(Integer value1, Integer value2) throws Exception { return value1 + value2; } }); Fold KeyedStream → DataStream A "rolling" fold on a keyed data stream with an initial value. Combines the current element with the last folded value and emits the new value. A fold function that, when applied on the sequence (1,2,3,4,5), emits the sequence "start-1", "start-1-2", "start-1-2-3", ... DataStream<String> result = keyedStream.fold("start", new FoldFunction<Integer, String>() { @Override public String fold(String current, Integer value) { return current + "-" + value; } }); Fold和reduce的区别,fold可以有个初始值,而且foldfunciton可以将一种类型fold到另一种类型 而reduce function,只能是一种类型 Aggregations KeyedStream → DataStream Rolling aggregations on a keyed data stream. The difference between min and minBy is that min returns the minimun value, whereas minBy returns the element that has the minimum value in this field (same for max and maxBy). keyedStream.sum(0); keyedStream.sum("key"); keyedStream.min(0); keyedStream.min("key"); keyedStream.max(0); keyedStream.max("key"); keyedStream.minBy(0); keyedStream.minBy("key"); keyedStream.maxBy(0); keyedStream.maxBy("key"); 可以认为是特殊的reduce 不带by,只是返回value 带by,返回整个element ============================================================================================= Union DataStream* → DataStream Union of two or more data streams creating a new stream containing all the elements from all the streams. Node: If you union a data stream with itself you will get each element twice in the resulting stream. dataStream.union(otherStream1, otherStream2, ...); Connect DataStream,DataStream → ConnectedStreams "Connects" two data streams retaining their types. Connect allowing for shared state between the two streams. DataStream<Integer> someStream = //... DataStream<String> otherStream = //... ConnectedStreams<Integer, String> connectedStreams = someStream.connect(otherStream); connect就是两个不同type的流可以共享一个流,tuple可以同时拿到来自两个流的数据 CoMap, CoFlatMap ConnectedStreams → DataStream Similar to map and flatMap on a connected data stream connectedStreams.map(new CoMapFunction<Integer, String, Boolean>() { @Override public Boolean map1(Integer value) { return true; } @Override public Boolean map2(String value) { return false; } }); Split DataStream → SplitStream Split the stream into two or more streams according to some criterion. SplitStream<Integer> split = someDataStream.split(new OutputSelector<Integer>() { @Override public Iterable<String> select(Integer value) { List<String> output = new ArrayList<String>(); if (value % 2 == 0) { output.add("even"); } else { output.add("odd"); } return output; } }); Select SplitStream → DataStream Select one or more streams from a split stream. SplitStream<Integer> split; DataStream<Integer> even = split.select("even"); DataStream<Integer> odd = split.select("odd"); DataStream<Integer> all = split.select("even","odd"); ==================================================================================== Project DataStream → DataStream Selects a subset of fields from the tuples DataStream<Tuple3<Integer, Double, String>> in = // [...] DataStream<Tuple2<String, Integer>> out = in.project(2,0); =========================================================================================== Window KeyedStream → WindowedStream Windows can be defined on already partitioned KeyedStreams. Windows group the data in each key according to some characteristic (e.g., the data that arrived within the last 5 seconds). Seewindowsfor a complete description of windows. dataStream.keyBy(0).window(TumblingTimeWindows.of(Time.of(5, TimeUnit.SECONDS))); // Last 5 seconds of data 基于keyedStream的window WindowAll DataStream → AllWindowedStream Windows can be defined on regular DataStreams. Windows group all the stream events according to some characteristic (e.g., the data that arrived within the last 5 seconds). Seewindowsfor a complete description of windows. WARNING:This is in many cases anon-paralleltransformation. All records will be gathered in one task for the windowAll operator. dataStream.windowAll(TumblingTimeWindows.of(Time.of(5, TimeUnit.SECONDS))); // Last 5 seconds of data 主要,由于没有key,所以如果要对all做transform,是无法parallel的,只能在一个task里面做 Window Apply WindowedStream → DataStream AllWindowedStream → DataStream Applies a general function to the window as a whole. Below is a function that manually sums the elements of a window. Note:If you are using a windowAll transformation, you need to use an AllWindowFunction instead. Window Reduce WindowedStream → DataStream Applies a functional reduce function to the window and returns the reduced value. Aggregations on windows WindowedStream → DataStream Aggregates the contents of a window. The difference between min and minBy is that min returns the minimun value, whereas minBy returns the element that has the minimum value in this field (same for max and maxBy). windowedStream.sum(0); windowedStream.sum("key"); Window Join DataStream,DataStream → DataStream Join two data streams on a given key and a common window. dataStream.join(otherStream) .where(0).equalTo(1) .window(TumblingTimeWindows.of(Time.of(3, TimeUnit.SECONDS))) .apply (new JoinFunction () {...}); Physical partitioning 类似storm的group方式,可以自己配置 Hash partitioning, 等同于 groupby field DataStream → DataStream Identical to keyBy but returns a DataStream instead of a KeyedStream. dataStream.partitionByHash("someKey"); dataStream.partitionByHash(0); Custom partitioning DataStream → DataStream Uses a user-defined Partitioner to select the target task for each element. dataStream.partitionCustom(new Partitioner(){...}, "someKey"); dataStream.partitionCustom(new Partitioner(){...}, 0); Random partitioning,等同于shuffle DataStream → DataStream Partitions elements randomly according to a uniform distribution. dataStream.partitionRandom(); Rebalancing (Round-robin partitioning) DataStream → DataStream Partitions elements round-robin, creating equal load per partition. Useful for performance optimization in the presence of data skew. dataStream.rebalance(); 这个保证数据不会skew,round-robin就是每个一条,轮流来 Broadcasting,等同于globle DataStream → DataStream Broadcasts elements to every partition. dataStream.broadcast(); Task chaining and resource groups Chaining two subsequent transformations means co-locating them within the same thread for better performance. Flink by default chains operators if this is possible (e.g., two subsequent map transformations). The API gives fine-grained control over chaining if desired: A resource group is a slot in Flink, seeslots. You can manually isolate operators in separate slots if desired. Start new chain Begin a new chain, starting with this operator. The two mappers will be chained, and filter will not be chained to the first mapper. someStream.filter(...).map(...).startNewChain().map(...); 注意startNewChain是应用于,左边的那个operator,所以上面从第一个map开始start new chain Disable chaining Do not chain the map operator someStream.map(...).disableChaining(); Start a new resource group Start a new resource group containing the map and the subsequent operators. someStream.map(...).startNewResourceGroup(); 意思就是他们share同一个slot? Isolate resources Isolate the operator in its own slot. someStream.map(...).isolateResources(); 使用独立的slot Execution Configuration 只有下面两个和batch的配置不同, Parameters in theExecutionConfigthat pertain specifically to the DataStream API are: enableTimestamps()/disableTimestamps(): Attach a timestamp to each event emitted from a source.areTimestampsEnabled()returns the current value. setAutoWatermarkInterval(long milliseconds): Set the interval for automatic watermark emission. You can get the current value withlong getAutoWatermarkInterval() Debugging A LocalEnvironment is created and used as follows: final StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironment(); DataStream<String> lines = env.addSource(/* some source */); // build your program env.execute(); Collection data sources can be used as follows: final StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironment(); // Create a DataStream from a list of elements DataStream<Integer> myInts = env.fromElements(1, 2, 3, 4, 5); // Create a DataStream from any Java collection List<Tuple2<String, Integer>> data = ... DataStream<Tuple2<String, Integer>> myTuples = env.fromCollection(data); // Create a DataStream from an Iterator Iterator<Long> longIt = ... DataStream<Long> myLongs = env.fromCollection(longIt, Long.class); Flink also provides a sink to collect DataStream results for testing and debugging purposes. It can be used as follows: import org.apache.flink.contrib.streaming.DataStreamUtils DataStream<Tuple2<String, Integer>> myResult = ... Iterator<Tuple2<String, Integer>> myOutput = DataStreamUtils.collect(myResult) Windows Working with Time 3种时间, Processing time,真正的处理时间 Event time, 事件真正发生的时间 Ingestion time,数据进入flink时间,在data source env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime); env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime); env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime); 默认是用processing 时间, 如果要用event time,you need to follow four steps: Setenv.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) UseDataStream.assignTimestamps(...)in order to tell Flink how timestamps relate to events (e.g., which record field is the timestamp) SetenableTimestamps(), as well the interval for watermark emission (setAutoWatermarkInterval(long milliseconds)) inExecutionConfig. For example, assume that we have a data stream of tuples, in which the first field is the timestamp (assigned by the system that generates these data streams), and we know that the lag between the current processing time and the timestamp of an event is never more than 1 second: DataStream<Tuple4<Long,Integer,Double,String>> stream = //... stream.assignTimestamps(new TimestampExtractor<Tuple4<Long,Integer,Double,String>>{ @Override public long extractTimestamp(Tuple4<Long,Integer,Double,String> element, long currentTimestamp) { return element.f0; } @Override public long extractWatermark(Tuple4<Long,Integer,Double,String> element, long currentTimestamp) { return element.f0 - 1000; } @Override public long getCurrentWatermark() { return Long.MIN_VALUE; } }); Basic Window Constructs Tumbling time window,非滑动 KeyedStream → WindowedStream Defines a window of 5 seconds, that "tumbles". keyedStream.timeWindow(Time.of(5, TimeUnit.SECONDS)); Sliding time window,滑动 KeyedStream → WindowedStream Defines a window of 5 seconds, that "slides" by 1 seconds. keyedStream.timeWindow(Time.of(5, TimeUnit.SECONDS), Time.of(1, TimeUnit.SECONDS)); Tumbling count window KeyedStream → WindowedStream keyedStream.countWindow(1000); Sliding count window KeyedStream → WindowedStream keyedStream.countWindow(1000, 100) Advanced Window Constructs The general recipe for building a custom window is to specify (1) aWindowAssigner, (2) aTrigger(optionally), and (3) anEvictor(optionally). 上面的如timeWindow,是封装好的,而如果用advanced构建方式,需要3步, 1. 首先是WindowAssigner,主要是滑动和非滑动两类,解决主要的是where的问题 Global window KeyedStream → WindowedStream All incoming elements of a given key are assigned to the same window. The window does not contain a default trigger, hence it will never be triggered if a trigger is not explicitly specified. stream.window(GlobalWindows.create()); 用于count window Tumbling time windows KeyedStream → WindowedStream stream.window(TumblingTimeWindows.of(Time.of(1, TimeUnit.SECONDS))); The window comes with a default trigger. For event/ingestion time, a window is triggered when a watermark with value higher than its end-value is received, whereas for processing time when the current processing time exceeds its current end value. 默认的trigger, 先理解watermark的含义:当我收到一个watermark时,表示我不可能收到event time 小于该water mark的数据 所以我收到的water mark都大于我window的结束时间,说明,window的数据已经到齐了,可以触发trigger Sliding time windows KeyedStream → WindowedStream stream.window(SlidingTimeWindows.of(Time.of(5, TimeUnit.SECONDS), Time.of(1, TimeUnit.SECONDS))); 默认的trigger与上同, 2. 第二步,是定义trigger,何时触发,解决的是when的问题 TheTriggerspecifies when the function that comes after the window clause (e.g.,sum,count) is evaluated (“fires”) for each window. If a trigger is not specified, a default trigger for each window type is used (that is part of the definition of theWindowAssigner). Processing time trigger A window is fired when the current processing time exceeds its end-value. The elements on the triggered window are henceforth discarded. windowedStream.trigger(ProcessingTimeTrigger.create()); Watermark trigger A window is fired when a watermark with value that exceeds the window's end-value has been received. The elements on the triggered window are henceforth discarded. windowedStream.trigger(EventTimeTrigger.create()); Continuous processing time trigger A window is periodically considered for being fired (every 5 seconds in the example). The window is actually fired only when the current processing time exceeds its end-value. The elements on the triggered window are retained. windowedStream.trigger(ContinuousProcessingTimeTrigger.of(Time.of(5, TimeUnit.SECONDS))); Continuous watermark time trigger A window is periodically considered for being fired (every 5 seconds in the example). A window is actually fired when a watermark with value that exceeds the window's end-value has been received. The elements on the triggered window are retained. windowedStream.trigger(ContinuousEventTimeTrigger.of(Time.of(5, TimeUnit.SECONDS))); 这个和上面的不同,在于,window在触发后,不会被discard,而是会保留,并且每隔一段时间会反复的触发 Count trigger A window is fired when it has more than a certain number of elements (1000 below). The elements of the triggered window are retained. windowedStream.trigger(CountTrigger.of(1000)); 按count触发,window会被保留 Purging trigger Takes any trigger as an argument and forces the triggered window elements to be "purged" (discarded) after triggering. windowedStream.trigger(PurgingTrigger.of(CountTrigger.of(1000))); 上面有些trigger是会retain数据的,如果你想discard,怎么搞? 用PurgingTrigger Delta trigger A window is periodically considered for being fired (every 5000 milliseconds in the example). A window is actually fired when the value of the last added element exceeds the value of the first element inserted in the window according to a `DeltaFunction`. windowedStream.trigger(new DeltaTrigger.of(5000.0, new DeltaFunction<Double>() { @Override public double getDelta (Double old, Double new) { return (new - old > 0.01); } })); Delta trigger,即,每次会通过getDelta比较新来的值和旧值的delta,当delta大于定义的阈值时,就会fire 3. 最后,指定Evictor After the trigger fires, and before the function (e.g.,sum,count) is applied to the window contents, an optionalEvictorremoves some elements from the beginning of the window before the remaining elements are passed on to the function. 说白了,当windows被触发时,我们可以选取部分数据进行处理, evictor,清除者,即清除部分数据,保留你想要的 Time evictor Evict all elements from the beginning of the window, so that elements from end-value - 1 second until end-value are retained (the resulting window size is 1 second). triggeredStream.evictor(TimeEvictor.of(Time.of(1, TimeUnit.SECONDS))); Count evictor Retain 1000 elements from the end of the window backwards, evicting all others. triggeredStream.evictor(CountEvictor.of(1000)); 逻辑是保留,而不是清除,比如CountEvictor.of(1000)是保留最后1000个,有点不好理解 Delta evictor Starting from the beginning of the window, evict elements until an element with value lower than the value of the last element is found (by a threshold and a DeltaFunction). triggeredStream.evictor(DeltaEvictor.of(5000, new DeltaFunction<Double>() { public double (Double oldValue, Double newValue) { return newValue - oldValue; } })); Recipes for Building Windows 下面给出一些window定义的例子,理解一下,例子给的太简单 Windows on Unkeyed Data Streams window,也可以用于unkeyed的数据流, 不同,是在window后面加上all, Tumbling time window all DataStream → WindowedStream Defines a window of 5 seconds, that "tumbles". This means that elements are grouped according to their timestamp in groups of 5 second duration, and every element belongs to exactly one window. The notion of time used is controlled by the StreamExecutionEnvironment. nonKeyedStream.timeWindowAll(Time.of(5, TimeUnit.SECONDS)); Sliding time window all DataStream → WindowedStream Defines a window of 5 seconds, that "slides" by 1 seconds. This means that elements are grouped according to their timestamp in groups of 5 second duration, and elements can belong to more than one window (since windows overlap by at least 4 seconds) The notion of time used is controlled by the StreamExecutionEnvironment. nonKeyedStream.timeWindowAll(Time.of(5, TimeUnit.SECONDS), Time.of(1, TimeUnit.SECONDS)); Tumbling count window all DataStream → WindowedStream Defines a window of 1000 elements, that "tumbles". This means that elements are grouped according to their arrival time (equivalent to processing time) in groups of 1000 elements, and every element belongs to exactly one window. nonKeyedStream.countWindowAll(1000) Sliding count window all DataStream → WindowedStream Defines a window of 1000 elements, that "slides" every 100 elements. This means that elements are grouped according to their arrival time (equivalent to processing time) in groups of 1000 elements, and every element can belong to more than one window (as windows overlap by at least 900 elements). nonKeyedStream.countWindowAll(1000, 100) Working with State All transformations in Flink may look like functions (in the functional processing terminology), but are in fact stateful operators. You can makeeverytransformation (map,filter, etc) stateful by declaring local variables or using Flink’s state interface. You can register any local variable asmanagedstate by implementing an interface. In this case, and also in the case of using Flink’s native state interface, Flink will automatically take consistent snapshots of your state periodically, and restore its value in the case of a failure. The end effect is that updates to any form of state are the same under failure-free execution and execution under failures. First, we look at how to make local variables consistent under failures, and then we look at Flink’s state interface. By default state checkpoints will be stored in-memory at the JobManager. For proper persistence of large state, Flink supports storing the checkpoints on file systems (HDFS, S3, or any mounted POSIX file system), which can be configured in theflink-conf.yamlor viaStreamExecutionEnvironment.setStateBackend(…). 这块是Flink流式处理的核心价值,可以方便的checkpoint的local state,有几种方式,后面会具体说; 默认情况下,这些checkpoints 是存储在JobManager的内存中的,当然也可以配置checkpoint到文件系统 Checkpointing Local Variables 这个比较好理解 Local variables can be checkpointed by using theCheckpointedinterface. When the user-defined function implements theCheckpointedinterface, thesnapshotState(…)andrestoreState(…)methods will be executed to draw and restore function state. public class CounterSum implements ReduceFunction<Long>, Checkpointed<Long> { // persistent counter private long counter = 0; @Override public Long reduce(Long value1, Long value2) { counter++; return value1 + value2; } // regularly persists state during normal operation @Override public Serializable snapshotState(long checkpointId, long checkpointTimestamp) { return counter; } // restores state on recovery from failure @Override public void restoreState(Long state) { counter = state; } } 如上,只是实现snapshotState和restoreState,就可以对local变量counter实现checkpoint,这个很好理解 n addition to that, user functions can also implement theCheckpointNotifierinterface to receive notifications on completed checkpoints via thenotifyCheckpointComplete(long checkpointId)method. Note that there is no guarantee for the user function to receive a notification if a failure happens between checkpoint completion and notification. The notifications should hence be treated in a way that notifications from later checkpoints can subsume missing notifications.、 除此,还能实现CheckpointNotifier,这样当完成checkpoints时,会调用notifyCheckpointComplete,但不能保证一定触发 Using the Key/Value State Interface 这个是显式调用state interface The state interface gives access to key/value states, which are a collection of key/value pairs. Because the state is partitioned by the keys (distributed accross workers), it can only be used on theKeyedStream, created viastream.keyBy(…)(which means also that it is usable in all types of functions on keyed windows). The handle to the state can be obtained from the function’sRuntimeContext. The state handle will then give access to the value mapped under the key of the current record or window - each key consequently has its own value. The following code sample shows how to use the key/value state inside a reduce function. When creating the state handle, one needs to supply a name for that state (a function can have multiple states of different types), the type of the state (used to create efficient serializers), and the default value (returned as a value for keys that do not yet have a value associated). public class CounterSum implements RichReduceFunction<Long> { /** The state handle */ private OperatorState<Long> counter; @Override public Long reduce(Long value1, Long value2) { counter.update(counter.value() + 1); return value1 + value2; } @Override public void open(Configuration config) { counter = getRuntimeContext().getKeyValueState("myCounter", Long.class, 0L); } } State updated by this is usually kept locally inside the flink process (unless one configures explicitly an external state backend). This means that lookups and updates areprocess localand this very fast. The important implication of having the keys set implicitly is that it forces programs to group the stream by key (via thekeyBy()function), making the key partitioning transparent to Flink. That allows the system to efficiently restore and redistribute keys and state. The Scala API has shortcuts that for statefulmap()orflatMap()functions onKeyedStream, which give the state of the current key as an option directly into the function, and return the result with a state update: val stream: DataStream[(String, Int)] = ... val counts: DataStream[(String, Int)] = stream .keyBy(_._1) .mapWithState((in: (String, Int), count: Option[Int]) => count match { case Some(c) => ( (in._1, c), Some(c + in._2) ) case None => ( (in._1, 0), Some(in._2) ) }) State Checkpoints in Iterative Jobs Flink currently only provides processing guarantees for jobs without iterations. Enabling checkpointing on an iterative job causes an exception. In order to force checkpointing on an iterative program the user needs to set a special flag when enabling checkpointing:env.enableCheckpointing(interval, force = true). Please note that records in flight in the loop edges (and the state changes associated with them) will be lost during failure. 对于iterative,即有环的case,做checkpoint更加复杂点,并且恢复后,会丢失中间过程,比如n次迭代,执行到n-1次,失败,还是要从1开始 Iterations For example, here is program that continuously subtracts 1 from a series of integers until they reach zero: DataStream<Long> someIntegers = env.generateSequence(0, 1000); IterativeStream<Long> iteration = someIntegers.iterate(); DataStream<Long> minusOne = iteration.map(new MapFunction<Long, Long>() { @Override public Long map(Long value) throws Exception { return value - 1 ; } }); DataStream<Long> stillGreaterThanZero = minusOne.filter(new FilterFunction<Long>() { @Override public boolean filter(Long value) throws Exception { return (value > 0); } }); iteration.closeWith(stillGreaterThanZero); DataStream<Long> lessThanZero = minusOne.filter(new FilterFunction<Long>() { @Override public boolean filter(Long value) throws Exception { return (value <= 0); } }); 这个直接看例子, 首先,someIntegers是一个由0到1000的DataStream 对于每个tuple,都需要迭代的执行一个map function,在这儿,会不断减一 什么时候结束, 根据iteration.closeWith,closeWith后面是一个filter,如果filter返回为true,这个tuple就继续iterate,如果返回为false,就close iterate 而最后的lessThanZero是someIntegers经过iterate后,最终产生的输出DataStream Connectors Connectors provide code for interfacing with various third-party systems. Currently these systems are supported: Apache Kafka(sink/source) Elasticsearch(sink) Hadoop FileSystem(sink) RabbitMQ(sink/source) Twitter Streaming API(source) To run an application using one of these connectors, additional third party components are usually required to be installed and launched, e.g. the servers for the message queues. Further instructions for these can be found in the corresponding subsections.Docker containersare also provided encapsulating these services to aid users getting started with connectors. 只看下kafka, Then, import the connector in your maven project: <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-connector-kafka</artifactId> <version>0.10.2</version> </dependency> 使用的例子, Properties properties = new Properties(); properties.setProperty("bootstrap.servers", "localhost:9092"); properties.setProperty("zookeeper.connect", "localhost:2181"); properties.setProperty("group.id", "test"); DataStream<String> stream = env .addSource(new FlinkKafkaConsumer082<>("topic", new SimpleStringSchema(), properties)) .print(); 如何fault tolerance? With Flink’s checkpointing enabled, the Flink Kafka Consumer will consume records from a topic and periodically checkpoint all its Kafka offsets, together with the state of other operations, in a consistent manner. In case of a job failure, Flink will restore the streaming program to the state of the latest checkpoint and re-consume the records from Kafka, starting from the offsets that where stored in the checkpoint. 原理就是会和其他state一起把所有的kafka partition的offset都checkpoint下来,这样恢复的时候,可以从这些offset开始读; To use fault tolerant Kafka Consumers, checkpointing of the topology needs to be enabled at the execution environment: final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.enableCheckpointing(5000); // checkpoint every 5000 msecs If checkpointing is not enabled, the Kafka consumer will periodically commit the offsets to Zookeeper. 由于用的是simple consumer,所以就算不开checkpoint,offset也要被记录;这里使用通常的做法把kafka的offset记录到zookeeper 也可以把数据写入kafka,FlinkKafkaProducer TheFlinkKafkaProducerwrites data to a Kafka topic. The producer can specify a custom partitioner that assigns recors to partitions. tream.addSink(new FlinkKafkaProducer<String>("localhost:9092", "my-topic", new SimpleStringSchema()));

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

Flink DataSet API Programming Guide

Example Program 编程的风格和spark很类似, ExecutionEnvironment -- SparkContext DataSet – RDD Transformations 这里用Java的接口,所以传入function需要用FlatMapFunction类对象 public class WordCountExample { public static void main(String[] args) throws Exception { final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); DataSet<String> text = env.fromElements( "Who's there?", "I think I hear them. Stand, ho! Who's there?"); DataSet<Tuple2<String, Integer>> wordCounts = text .flatMap(new LineSplitter()) .groupBy(0) .sum(1); wordCounts.print(); } public static class LineSplitter implements FlatMapFunction<String, Tuple2<String, Integer>> { @Override public void flatMap(String line, Collector<Tuple2<String, Integer>> out) { for (String word : line.split(" ")) { out.collect(new Tuple2<String, Integer>(word, 1)); } } } } Specifying Keys 如何定义key, 1. 用tuple的index,如下用tuple的第一个和第二个做联合key DataSet<Tuple3<Integer,String,Long>> input = // [...] DataSet<Tuple3<Integer,String,Long> grouped = input .groupBy(0,1) .reduce(/*do something*/); 2. 对于POJO对象,使用Field Expressions // some ordinary POJO (Plain old Java Object) public class WC { public String word; public int count; } DataSet<WC> words = // [...] DataSet<WC> wordCounts = words.groupBy("word").reduce(/*do something*/); 3. 使用Key Selector Functions // some ordinary POJO public class WC {public String word; public int count;} DataSet<WC> words = // [...] DataSet<WC> wordCounts = words .groupBy( new KeySelector<WC, String>() { public String getKey(WC wc) { return wc.word; } }) .reduce(/*do something*/); Passing Functions to Flink 1. 实现function interface class MyMapFunction implements MapFunction<String, Integer> { public Integer map(String value) { return Integer.parseInt(value); } }); data.map (new MyMapFunction()); 或使用匿名类, data.map(new MapFunction<String, Integer> () { public Integer map(String value) { return Integer.parseInt(value); } }); 2. 使用Rich functions Rich functions provide, in addition to the user-defined function (map, reduce, etc), four methods:open,close,getRuntimeContext,andsetRuntimeContext. These are useful for parameterizing the function (seePassing Parameters to Functions), creating and finalizing local state, accessing broadcast variables (seeBroadcast Variables, and for accessing runtime information such as accumulators and counters (seeAccumulators and Counters, and information on iterations (seeIterations). Rich functions的使用和普通的function是一样的,不同的就是,多4个接口函数,可以用于一些特殊的场景,比如给function传参,或访问broadcast变量,accumulators和counter,因为这些场景你需要先getRuntimeContext class MyMapFunction extends RichMapFunction<String, Integer> { public Integer map(String value) { return Integer.parseInt(value); } }); Execution Configuration ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); ExecutionConfig executionConfig = env.getConfig(); enableClosureCleaner()/disableClosureCleaner(). The closure cleaner is enabled by default. The closure cleaner removes unneeded references to the surrounding class of anonymous functions inside Flink programs. With the closure cleaner disabled, it might happen that an anonymous user function is referencing the surrounding class, which is usually not Serializable. This will lead to exceptions by the serializer. 对于Java,比如传入function也要生成function对象,这样里面的function是会reference这个对象的,其实这种情况,你需要的只是function逻辑,所以closureCleaner会去掉这个reference 这样的好处是,传输类对象时候,是要求对象可序列化的,如果每个去实现序列号接口很麻烦,不实现又会报错,所以这里干脆clean掉这个reference getParallelism()/setParallelism(int parallelism)Set the default parallelism for the job. 设置Job的全局的parallelism getExecutionRetryDelay()/setExecutionRetryDelay(long executionRetryDelay)Sets the delay in milliseconds that the system waits after a job has failed, before re-executing it. The delay starts after all tasks have been successfully been stopped on the TaskManagers, and once the delay is past, the tasks are re-started. This parameter is useful to delay re-execution in order to let certain time-out related failures surface fully (like broken connections that have not fully timed out), before attempting a re-execution and immediately failing again due to the same problem. This parameter only has an effect if the number of execution re-tries is one or more.getExecutionMode()/setExecutionMode(). The default execution mode is PIPELINED. Sets the execution mode to execute the program. The execution mode defines whether data exchanges are performed in a batch or on a pipelined manner. 和失败重试相关的配置 enableObjectReuse()/disableObjectReuse()By default, objects are not reused in Flink. Enabling theobject reuse modewill instruct the runtime to reuse user objects for better performance. Keep in mind that this can lead to bugs when the user-code function of an operation is not aware of this behavior. 这个由于Java什么都要生成对象,比如function,所以会生成大量重复对象,这个可以打开object重用,提高性能 enableSysoutLogging()/disableSysoutLogging()JobManager status updates are printed toSystem.outby default. This setting allows to disable this behavior. 打开和关闭系统日志 getGlobalJobParameters()/setGlobalJobParameters()This method allows users to set custom objects as a global configuration for the job. Since theExecutionConfigis accessible in all user defined functions, this is an easy method for making configuration globally available in a job. 可以设置Job全局参数 其他的参数都是序列化相关的,不列了 Data Sinks Data sinks consume DataSets and are used to store or return them. Data sink operations are described using anOutputFormat. 可以custom output format: 比如写数据库, DataSet<Tuple3<String, Integer, Double>> myResult = [...] // write Tuple DataSet to a relational database myResult.output( // build and configure OutputFormat JDBCOutputFormat.buildJDBCOutputFormat() .setDrivername("org.apache.derby.jdbc.EmbeddedDriver") .setDBUrl("jdbc:derby:memory:persons") .setQuery("insert into persons (name, age, height) values (?,?,?)") .finish() ); 还有个功能,可以做locally的排序, DataSet<Tuple3<Integer, String, Double>> tData = // [...] DataSet<Tuple2<BookPojo, Double>> pData = // [...] DataSet<String> sData = // [...] // sort output on String field in ascending order tData.print().sortLocalOutput(1, Order.ASCENDING); // sort output on Double field in descending and Integer field in ascending order tData.print().sortLocalOutput(2, Order.DESCENDING).sortLocalOutput(0, Order.ASCENDING); Debugging 本地执行,LocalEnvironement final ExecutionEnvironment env = ExecutionEnvironment.createLocalEnvironment(); DataSet<String> lines = env.readTextFile(pathToTextFile); // build your program env.execute(); 便于调式的datasouce, final ExecutionEnvironment env = ExecutionEnvironment.createLocalEnvironment(); // Create a DataSet from a list of elements DataSet<Integer> myInts = env.fromElements(1, 2, 3, 4, 5); // Create a DataSet from any Java collection List<Tuple2<String, Integer>> data = ... DataSet<Tuple2<String, Integer>> myTuples = env.fromCollection(data); // Create a DataSet from an Iterator Iterator<Long> longIt = ... DataSet<Long> myLongs = env.fromCollection(longIt, Long.class); 便于输出的datasink, DataSet<Tuple2<String, Integer>> myResult = ... List<Tuple2<String, Integer>> outData = new ArrayList<Tuple2<String, Integer>>(); myResult.output(new LocalCollectionOutputFormat(outData)); Iteration Operators Iterations implement loops in Flink programs. The iteration operators encapsulate a part of the program and execute it repeatedly, feeding back the result of one iteration (the partial solution) into the next iteration. There are two types of iterations in Flink:BulkIterationandDeltaIteration. 参考,https://ci.apache.org/projects/flink/flink-docs-release-0.10/apis/iterations.html BulkIteration就是正常的Iteration,每次都处理全量数据 DeltaIteration,就是每次都只处理部分数据并delta更新,效率更高 Semantic Annotations Semantic annotations can be used to give Flink hints about the behavior of a function. 目的是做性能优化,优化器在明确知道function读参数的使用情况,比如如果知道某些field只是做forward,就可以保留它的sorting or partitioning信息 有3种语义annotation, Forwarded Fields Annotation 表示,输入的某个field会原封不动的copy到输出的某个field 下面的例子,表示输入的第一个field会copy到输出的第3个field 可以看到,输出tuple的第三个field是val.f0 @ForwardedFields("f0->f2") public class MyMap implements MapFunction<Tuple2<Integer, Integer>, Tuple3<String, Integer, Integer>> { @Override public Tuple3<String, Integer, Integer> map(Tuple2<Integer, Integer> val) { return new Tuple3<String, Integer, Integer>("foo", val.f1 / 2, val.f0); } } Non-Forwarded Fields 和上面相反,除指定的fields,其他fields都是原位置copy 例子,除输入的第二个field,其他都是原位置copy @NonForwardedFields("f1") // second field is not forwarded public class MyMap implements MapFunction<Tuple2<Integer, Integer>, Tuple2<Integer, Integer>> { @Override public Tuple2<Integer, Integer> map(Tuple2<Integer, Integer> val) { return new Tuple2<Integer, Integer>(val.f0, val.f1 / 2); } } Read Fields 表明这个fields会在function被读到或用到, 表明,输入的第一个field和第4个field会被读到或用到 @ReadFields("f0; f3") // f0 and f3 are read and evaluated by the function. public class MyMap implements MapFunction<Tuple4<Integer, Integer, Integer, Integer>, Tuple2<Integer, Integer>> { @Override public Tuple2<Integer, Integer> map(Tuple4<Integer, Integer, Integer, Integer> val) { if(val.f0 == 42) { return new Tuple2<Integer, Integer>(val.f0, val.f1); } else { return new Tuple2<Integer, Integer>(val.f3+10, val.f1); } } } Broadcast Variables Broadcast variables allow you to make a data set available to all parallel instances of an operation, in addition to the regular input of the operation. This is useful for auxiliary data sets, or data-dependent parameterization. The data set will then be accessible at the operator as a Collection. Broadcast: broadcast sets are registered by name viawithBroadcastSet(DataSet, String), and Access: accessible viagetRuntimeContext().getBroadcastVariable(String)at the target operator. // 1. The DataSet to be broadcasted DataSet<Integer> toBroadcast = env.fromElements(1, 2, 3); DataSet<String> data = env.fromElements("a", "b"); data.map(new RichMapFunction<String, String>() { @Override public void open(Configuration parameters) throws Exception { // 3. Access the broadcasted DataSet as a Collection Collection<Integer> broadcastSet = getRuntimeContext().getBroadcastVariable("broadcastSetName"); } @Override public String map(String value) throws Exception { ... } }).withBroadcastSet(toBroadcast, "broadcastSetName"); // 2. Broadcast the DataSet 这个场景,就是有些不大的公共数据,是要被所有的实例访问到的,比如一些查询表 上面的例子,会将toBroadcast设置为广播变量broadcastSetName,这样在运行时,可以用getRuntimeContext().getBroadcastVariable获取该变量使用 Passing Parameters to Functions 应该是如果将参数传递给function类,这个完全由java冗余导致的 首先,当然可以用类构造函数来传参数, ataSet<Integer> toFilter = env.fromElements(1, 2, 3); toFilter.filter(new MyFilter(2)); private static class MyFilter implements FilterFunction<Integer> { private final int limit; public MyFilter(int limit) { this.limit = limit; } @Override public boolean filter(Integer value) throws Exception { return value > limit; } } 自定义MyFilter,构造函数可以传入limit 也可以使用withParameters(Configuration) DataSet<Integer> toFilter = env.fromElements(1, 2, 3); Configuration config = new Configuration(); config.setInteger("limit", 2); toFilter.filter(new RichFilterFunction<Integer>() { private int limit; @Override public void open(Configuration parameters) throws Exception { limit = parameters.getInteger("limit", 0); } @Override public boolean filter(Integer value) throws Exception { return value > limit; } }).withParameters(config); 可以用withParameters将定义好的config传入function 然后用RichFunction的Open接口,将参数解析出来使用 这样和上面的比有啥好处,我怎么觉得上面那个看着更方便些?可以用匿名类? 当然你也可以用全局参数,这个和广播变量有什么区别?相同点就是都是全局可见,全局参数只能用于参数形式,广播变量可以是任意dataset Setting a custom global configuration Configuration conf = new Configuration(); conf.setString("mykey","myvalue"); final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); env.getConfig().setGlobalJobParameters(conf); Accessing values from the global configuration public static final class Tokenizer extends RichFlatMapFunction<String, Tuple2<String, Integer>> { private String mykey; @Override public void open(Configuration parameters) throws Exception { super.open(parameters); ExecutionConfig.GlobalJobParameters globalParams = getRuntimeContext().getExecutionConfig().getGlobalJobParameters(); Configuration globConf = (Configuration) globalParams; mykey = globConf.getString("mykey", null); } // ... more here ... Accumulators & Counters 用于分布式计数,job结束的时候,会全部汇总 Flink currently has the followingbuilt-in accumulators. Each of them implements theAccumulatorinterface. IntCounter,LongCounterandDoubleCounter: See below for an example using a counter. Histogram: A histogram implementation for a discrete number of bins. Internally it is just a map from Integer to Integer. You can use this to compute distributions of values, e.g. the distribution of words-per-line for a word count program. //定义和注册counter private IntCounter numLines = new IntCounter(); getRuntimeContext().addAccumulator("num-lines", this.numLines); //在任意地方进行计数 this.numLines.add(1); //最终取得结果 myJobExecutionResult.getAccumulatorResult("num-lines") Execution Plans 首先可以打印出执行plan,json格式, final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); ... System.out.println(env.getExecutionPlan()); 打开这个网页, The HTML document containing the visualizer is located undertools/planVisualizer.html. 将Json贴入,就可以看到执行计划, Web Interface Flink offers a web interface for submitting and executing jobs. If you choose to use this interface to submit your packaged program, you have the option to also see the plan visualization. The script to start the webinterface is located underbin/start-webclient.sh. After starting the webclient (per default onport 8080), your program can be uploaded and will be added to the list of available programs on the left side of the interface. 也可以通过web interface来提交job和查看执行计划

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

【转】iOS Programming – 触摸事件处理

iphone/ipad无键盘的设计是为屏幕争取更多的显示空间,大屏幕在观看图片、文字、视频等方面为用户带来了更好的用户体验。而触摸屏幕是iOS设备接受用户输入的主要方式,包括单击、双击、拨动以及多点触摸等,这些操作都会产生触摸事件。 在Cocoa中,代表触摸对象的类是UITouch。当用户触摸屏幕后,就会产生相应的事件,所有相关的UITouch对象都被包装在事件中,被程序交由特定的对象来处理。UITouch对象直接包括触摸的详细信息。 UITouch类中包含5个属性: window:触摸产生时所处的窗口。由于窗口可能发生变化,当前所在的窗口不一定是最开始的窗口。 view:触摸产生时所处的视图。由于视图可能发生变化,当前视图也不一定时最初的视图。 tapCount:轻击(Tap)操作和鼠标的单击操作类似,tapCount表示短时间内轻击屏幕的次数。因此可以根据tapCount判断单击、双击或更多的轻击。 timestamp:时间戳记录了触摸事件产生或变化时的时间。单位是秒。 phase:触摸事件在屏幕上有一个周期,即触摸开始、触摸点移动、触摸结束,还有中途取消。而通过phase可以查看当前触摸事件在一个周期中所处的状态。phase是UITouchPhase类型的,这是一个枚举配型,包含了 ·UITouchPhaseBegan(触摸开始) ·UITouchPhaseMoved(接触点移动) ·UITouchPhaseStationary(接触点无移动) ·UITouchPhaseEnded(触摸结束) ·UITouchPhaseCancelled(触摸取消) UITouch类中包含如下成员函数: - (CGPoint)locationInView:(UIView *)view:函数返回一个CGPoint类型的值,表示触摸在view这个视图上的位置,这里返回的位置是针对view的坐标系的。调用时传入的view参数为空的话,返回的时触摸点在整个窗口的位置。 - (CGPoint)previousLocationInView:(UIView *)view:该方法记录了前一个坐标值,函数返回也是一个CGPoint类型的值, 表示触摸在view这个视图上的位置,这里返回的位置是针对view的坐标系的。调用时传入的view参数为空的话,返回的时触摸点在整个窗口的位置。 当手指接触到屏幕,不管是单点触摸还是多点触摸,事件都会开始,直到用户所有的手指都离开屏幕。期间所有的UITouch对象都被包含在UIEvent事件对象中,由程序分发给处理者。事件记录了这个周期中所有触摸对象状态的变化。 只要屏幕被触摸,系统就会报若干个触摸的信息封装到UIEvent对象中发送给程序,由管理程序UIApplication对象将事件分发。一般来说,事件将被发给主窗口,然后传给第一响应者对象(FirstResponder)处理。 关于响应者的概念,通过以下几点说明: 响应者对象(Response object) 响 应者对象就是可以响应事件并对事件作出处理。在iOS中,存在UIResponder类,它定义了响应者对象的所有方法。UIApplication、 UIView等类都继承了UIResponder类,UIWindow和UIKit中的控件因为继承了UIView,所以也间接继承了 UIResponder类,这些类的实例都可以当作响应者。 第一响应者(First responder) 当前接受触摸的响应者对象被称为第一响应者,即表示当前该对象正在与用户交互,它是响应者链的开端。 响应者链(Responder chain) 响 应者链表示一系列的响应者对象。事件被交由第一响应者对象处理,如果第一响应者不处理,事件被沿着响应者链向上传递,交给下一个响应者(next responder)。一般来说,第一响应者是个视图对象或者其子类对象,当其被触摸后事件被交由它处理,如果它不处理,事件就会被传递给它的视图控制器 对象(如果存在),然后是它的父视图(superview)对象(如果存在),以此类推,直到顶层视图。接下来会沿着顶层视图(top view) 到窗口(UIWindow对象)再到程序(UIApplication对象)。如果整个过程都没有响应这个事件,该事件就被丢弃。一般情况下,在响应者链 中只要由对象处理事件,事件就停止传递。但有时候可以在视图的响应方法中根据一些条件判断来决定是否需要继续传递事件。 管理事件分发 视图对触摸事件是否需要作处回应可以通过设置视图的userInteractionEnabled属 性。默认状态为YES,如果设置为NO,可以阻止视图接收和分发触摸事件。除此之外,当视图被隐藏(setHidden:YES)或者透明(alpha值 为0)也不会收事件。不过这个属性只对视图有效,如果想要整个程序都步响应事件,可以调用UIApplication的beginIngnoringInteractionEvents方法来完全停止事件接收和分发。通过endIngnoringInteractionEvents方法来恢复让程序接收和分发事件。 如果要让视图接收多点触摸,需要设置它的multipleTouchEnabled属性为YES,默认状态下这个属性值为NO,即视图默认不接收多点触摸。 首先触摸的对象是视图,而视图的类UIView继承了UIRespnder类,但是要对事件作出处理,还需要重写UIResponder类中定义的事件处理函数。根据不通的触摸状态,程序会调用相应的处理函数,这些函数包括以下几个: -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; 当手指接触屏幕时,就会调用touchesBegan:withEvent方法; 当手指在屏幕上移时,动就会调用touchesMoved:withEvent方法; 当手指离开屏幕时,就会调用touchesEnded:withEvent方法; 当触摸被取消(比如触摸过程中被来电打断),就会调用touchesCancelled:withEvent方法。而这几个方法被调用时,正好对应了UITouch类中phase属性的4个枚举值。 上面的四个事件方法,在开发过程中并不要求全部实现,可以根据需要重写特定的方法。对于这4个方法,都有两个相同的参数:NSSet类型的touches和UIEvent类型的event。其中touches表示触摸产生的所有UITouch对象,而event表示特定的事件。因为UIEvent包含了整个触摸过程中所有的触摸对象,因此可以调用allTouches方法获取该事件内所有的触摸对象,也可以调用touchesForVIew:或者touchesForWindows:取出特定视图或者窗口上的触摸对象。在这几个事件中,都可以拿到触摸对象,然后根据其位置,状态,时间属性做逻辑处理。 例如: -(void)touchesEnded:(NSSet*)toucheswithEvent:(UIEvent*)event { UITouch*touch=[touchesanyObject]; if(touch.tapCount==2) { self.view.backgroundColor=[UIColorredColor]; } } 复制代码 上面的例子说明在触摸手指离开后,根据tapCount点击的次数来设置当前视图的背景色。不管时一个手指还是多个手指,轻击操作都会使每个触摸对象的tapCount加1,由于上面的例子不需要知道具体触摸对象的位置或时间等,因此可以直接调用touches的anyObject方法来获取任意一个触摸对象然后判断其tapCount的值即可。 检测tapCount可以放在touchesBegan也可以touchesEnded,不过一般后者跟准确,因为touchesEnded可以保证所有的手指都已经离开屏幕,这样就不会把轻击动作和按下拖动等动作混淆。 轻击操作很容易引起歧义,比如当用户点了一次之后,并不知道用户是想单击还是只是双击的一部分,或者点了两次之后并不知道用户是想双击还是继续点击。为了解决这个问题,一般可以使用“延迟调用”函数。 例如: -(void)touchesEnded:(NSSet*)toucheswithEvent:(UIEvent*)event { UITouch*touch=[touchesanyObject]; if(touch.tapCount==1) { [selfperformSelector:@selector(setBackground:)withObject:[UIColorblueColor]afterDelay:2]; self.view.backgroundColor=[UIColorredColor]; } } 复制代码 上面代码表示在第一次轻击之后,没有直接更改视图的背景属性,而是通过performSelector:withObject:afterDelay:方法设置2秒中后更改。 -(void)touchesEnded:(NSSet*)toucheswithEvent:(UIEvent*)event { UITouch*touch=[touchesanyObject]; if(touch.tapCount==2) { [NSObjectcancelPreviousPerformRequestsWithTarget:selfselector:@selector(setBackground:)object:[UIColorredColor]]; self.view.backgroundColor=[UIColorredColor]; } } 复制代码 双击就是两次单击的组合,因此在第一次点击的时候,设置背景色的方法已经启动,在检测到双击的时候先要把先前对应的方法取消掉,可以通过调用NSObject类的cancelPreviousPerformRequestWithTarget:selector:object方法取消指定对象的方法调用,然后调用双击对应的方法设置背景色为红色。 下面举个例子创建可以拖动的视图,这个主要通过触摸对象的位置坐标来实现。因此调用触摸对象的locationInView:方法即可。 例如: CGPointoriginalLocation; -(void)touchesBegan:(NSSet*)toucheswithEvent:(UIEvent*)event { UITouch*touch=[touchesanyObject]; originalLocation=[touchlocationInView:self.view]; } -(void)touchesMoved:(NSSet*)toucheswithEvent:(UIEvent*)event { UITouch*touch=[touchesanyObject]; CGPointcurrentLocation=[touchlocationInView:self.view]; CGRectframe=self.view.frame; frame.origin.x+=currentLocation.x-originalLocation.x; frame.origin.y+=currentLocation.y-originalLocation.y; self.view.frame=frame; } 复制代码 这里先在touchesBegan中通过[touch locationInView:self.view]获取手指触摸在当前视图上的位置,用CGPoint变量记录,然后在手指移动事件touchesMoved方法中获取触摸对象当前位置,并通过于与原始位置的差值计算出移动偏移量,再设置当前视图的位置。 本文转自编程小翁博客园博客,原文链接:http://www.cnblogs.com/wengzilin/archive/2012/03/18/2404394.html,如需转载请自行联系原作者

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

书籍:python网络编程 Python Network Programming - 2019

简介 主要特点 掌握Python技能,开发强大的网络应用程序 掌握SDN的基本原理和功能 为echo和chat服务器设计多线程,事件驱动的体系结构 此学习路径强调了Python网络编程的主要方面,例如编写简单的网络客户端,创建和部署SDN和NFV系统,以及使用Mininet扩展您的网络。您还将学习如何自动化传统和最新的网络设备。在阅读这些章节的过程中,您将使用Python for DevOps和开源工具来测试,保护和分析您的网络。最后,您将使用套接字编程开发客户端应用程序,例如Web API客户端,电子邮件客户端,SSH和FTP。 到本学习路径结束时,您将学习如何使用高级网络数据包捕获和分析技术分析网络的安全漏洞。 你会学到什么 使用异步模型创建基于套接字的网络 为Web API开发客户端应用程序,包括S3 Amazon和Twitter 与具有不同协

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

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

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文件系统,支持十年生命周期更新。

用户登录
用户注册