首页 文章 精选 留言 我的

精选列表

搜索[web开发框架],共10000篇文章
优秀的个人博客,低调大师

hadoop mapreduce开发实践之本地文件分发by streaming

场景:程序运行所需要的文件、脚本程序或者配置文件不在hadoop集群上,则首先要将这些文件分发到hadoop集群上才可以进行计算; hadoop提供了自动分发文件也压缩包的功能,只需要在启动hadoop streaming作业的时候增加响应的配置参数(-file)即可实现。 在执行streaming程序时,使用 -file 选项指定需要分发的本地文件; 1、本地文件分发(-file) 1.1、需求:wordcount(只统计指定的单词【the,and,had】) 思路:在之前的Wordcount中,是统计了所有文本内单词的Wordcount,在此基础上修改程序,增加一个类似白名单的文本wordwhite记录只统计的单词;在编写mapper程序时候,如果从文本获取的单词只有在wordwhite中的单词在输出map,进而传给reduce;reducer程序不需要修改; 1.2、程序和文件 wordwhite (只统计的单词) $ vim wordwhite the and had mapper程序 $ vim mapper.py #!/usr/bin/env python import sys def read_wordwhite(file): word_set = set() with open(file, 'r') as fd: for line in fd: word = line.strip() word_set.add(word) return word_set def mapper(file_fd): word_set = read_wordwhite(file_fd) for line in sys.stdin: line = line.strip() words = line.split() for word in words: if word != "" and (word in word_set): print "%s\t%s" %(word, 1) if __name__ == "__main__": if sys.argv[1]: file_fd = sys.argv[1] mapper(file_fd) reducer程序 vim reducer.py #!/usr/bin/env python import sys def reducer(): current_word = None word_sum = 0 for line in sys.stdin: word_list = line.strip().split('\t') if len(word_list) < 2: continue word = word_list[0].strip() word_value = word_list[1].strip() if current_word == None: current_word = word if current_word != word: print "%s\t%s" %(current_word, str(word_sum)) current_word = word word_sum = 0 word_sum += int(word_value) print "%s\t%s" %(current_word, str(word_sum)) if __name__ == "__main__": reducer() run_streaming程序 $ vim runstreaming.sh #!/bin/bash HADOOP_CMD="/home/hadoop/app/hadoop/hadoop-2.6.0-cdh5.13.0/bin/hadoop" STREAM_JAR_PATH="/home/hadoop/app/hadoop/hadoop-2.6.0-cdh5.13.0/share/hadoop/tools/lib/hadoop-streaming-2.6.0-cdh5.13.0.jar" INPUT_FILE_PATH="/input/The_Man_of_Property" OUTPUT_FILE_PATH="/output/wordcount/wordwhitetest" # $HADOOP_CMD jar $STREAM_JAR_PATH \ -input $INPUT_FILE_PATH \ -output $OUTPUT_FILE_PATH \ -mapper "python mapper.py wordwhite" \ -reducer "python reducer.py" \ -file ./mapper.py \ -file ./reducer.py \ -file ./wordwhite 执行程序 首先需要将测试的文件:The_Man_of_Property上传到hdfs,同时创建wordcount输出目录;$ hadoop fs -put ./The_Man_of_Property /input/ $ hadoop fs -mkdir /output/wordcount 注:本次hadoop环境是伪分布式,hadoop 2.6版本。 $ ./runstreaming.sh 18/01/26 13:30:27 WARN streaming.StreamJob: -file option is deprecated, please use generic option -files instead. packageJobJar: [./mapper.py, ./reducer.py, ./wordwhite, /tmp/hadoop-unjar7204532228900236640/] [] /tmp/streamjob7580948745512643345.jar tmpDir=null 18/01/26 13:30:29 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032 18/01/26 13:30:29 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032 18/01/26 13:30:31 INFO mapred.FileInputFormat: Total input paths to process : 1 18/01/26 13:30:31 INFO mapreduce.JobSubmitter: number of splits:2 18/01/26 13:30:32 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1516345010544_0008 18/01/26 13:30:32 INFO impl.YarnClientImpl: Submitted application application_1516345010544_0008 18/01/26 13:30:32 INFO mapreduce.Job: The url to track the job: http://localhost:8088/proxy/application_1516345010544_0008/ 18/01/26 13:30:32 INFO mapreduce.Job: Running job: job_1516345010544_0008 18/01/26 13:30:40 INFO mapreduce.Job: Job job_1516345010544_0008 running in uber mode : false 18/01/26 13:30:40 INFO mapreduce.Job: map 0% reduce 0% 18/01/26 13:30:50 INFO mapreduce.Job: map 50% reduce 0% 18/01/26 13:30:51 INFO mapreduce.Job: map 100% reduce 0% 18/01/26 13:30:58 INFO mapreduce.Job: map 100% reduce 100% 18/01/26 13:30:59 INFO mapreduce.Job: Job job_1516345010544_0008 completed successfully 18/01/26 13:30:59 INFO mapreduce.Job: Counters: 49 File System Counters FILE: Number of bytes read=73950 FILE: Number of bytes written=582815 FILE: Number of read operations=0 FILE: Number of large read operations=0 FILE: Number of write operations=0 HDFS: Number of bytes read=636501 HDFS: Number of bytes written=27 HDFS: Number of read operations=9 HDFS: Number of large read operations=0 HDFS: Number of write operations=2 Job Counters Launched map tasks=2 Launched reduce tasks=1 Data-local map tasks=2 Total time spent by all maps in occupied slots (ms)=12815 Total time spent by all reduces in occupied slots (ms)=5251 Total time spent by all map tasks (ms)=12815 Total time spent by all reduce tasks (ms)=5251 Total vcore-milliseconds taken by all map tasks=12815 Total vcore-milliseconds taken by all reduce tasks=5251 Total megabyte-milliseconds taken by all map tasks=13122560 Total megabyte-milliseconds taken by all reduce tasks=5377024 Map-Reduce Framework Map input records=2866 Map output records=9243 Map output bytes=55458 Map output materialized bytes=73956 Input split bytes=198 Combine input records=0 Combine output records=0 Reduce input groups=3 Reduce shuffle bytes=73956 Reduce input records=9243 Reduce output records=3 Spilled Records=18486 Shuffled Maps =2 Failed Shuffles=0 Merged Map outputs=2 GC time elapsed (ms)=332 CPU time spent (ms)=3700 Physical memory (bytes) snapshot=707719168 Virtual memory (bytes) snapshot=8333037568 Total committed heap usage (bytes)=598736896 Shuffle Errors BAD_ID=0 CONNECTION=0 IO_ERROR=0 WRONG_LENGTH=0 WRONG_MAP=0 WRONG_REDUCE=0 File Input Format Counters Bytes Read=636303 File Output Format Counters Bytes Written=27 18/01/26 13:30:59 INFO streaming.StreamJob: Output directory: /output/wordcount/wordwhitetest 查看结果$ hadoop fs -ls /output/wordcount/wordwhitetest/ Found 2 items -rw-r--r-- 1 centos supergroup 0 2018-01-26 13:30 /output/wordcount/wordwhitetest/_SUCCESS -rw-r--r-- 1 centos supergroup 27 2018-01-26 13:30 /output/wordcount/wordwhitetest/part-00000 $ hadoop fs -text /output/wordcount/wordwhitetest/part-00000 and 2573 had 1526 the 5144 以上就完成了指定单词的wordcount. 2、hadoop streaming 语法参考 http://blog.51cto.com/balich/2065419 本文转自 巴利奇 51CTO博客,原文链接:http://blog.51cto.com/balich/2065424

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

hadoop mapreduce开发实践之HDFS文件分发by streaming

1、分发HDFS文件(-cacheFile) 需求:wordcount(只统计指定的单词),但是该文件非常大,可以先将该文件上传到hdfs,通过-cacheFile的方式进行分发; -cachefile hdfs://host:port/path/to/file#linkname #选项在计算节点上缓存文件,streaming程序通过./linkname的方式访问文件。 思路:mapper和reducer程序都不需要修改,只是在运行streaming的时候需要使用-cacheFile 指定hdfs上的文件; 1.1、streaming命令格式 $HADOOP_HOME/bin/hadoop jar hadoop-streaming.jar \ -jobconf mapred.job.name="streaming_wordcount" \ -jobconf mapred.job.priority=3 \ -input /input/ \ -output /output/ \ -mapper "python mapper.py whc" \ -reducer "python reducer.py" \ -cacheFile "hdfs://master:9000/cache_file/wordwhite#whc" -file ./mapper.py \ -file ./reducer.py 注:-cacheFile "hdfs://master:9000/cache_file/wordwhite#whc"whc表示在hdfs上该文件的别名,在-mapper "python mapper.py whc"就如同使用本地文件一样。 1.2、上传wordwhite $ hadoop fs -mkdir /input/cachefile $ hadoop fs -put wordwhite /input/cachefile $ hadoop fs -ls /input/cachefile Found 1 items -rw-r--r-- 1 hadoop supergroup 12 2018-01-26 15:02 /input/cachefile/wordwhite $ hadoop fs -text hdfs://localhost:9000/input/cachefile/wordwhite the and had 1.3 run_streaming程序 mapper和reducer程序参考本地分发实例 $ vim runstreaming_cachefile.sh #!/bin/bash HADOOP_CMD="/home/hadoop/app/hadoop/hadoop-2.6.0-cdh5.13.0/bin/hadoop" STREAM_JAR_PATH="/home/hadoop/app/hadoop/hadoop-2.6.0-cdh5.13.0/share/hadoop/tools/lib/hadoop-streaming-2.6.0-cdh5.13.0.jar" INPUT_FILE_PATH="/input/The_Man_of_Property" OUTPUT_FILE_PATH="/output/wordcount/wordwhitecachefiletest" $HADOOP_CMD jar $STREAM_JAR_PATH \ -input $INPUT_FILE_PATH \ -output $OUTPUT_FILE_PATH \ -jobconf "mapred.job.name=wordcount_wordwhite_cachefile_demo" \ -mapper "python mapper.py WHF" \ -reducer "python reducer.py" \ -cacheFile "hdfs://localhost:9000/input/cachefile/wordwhite#WHF" \ -file ./mapper.py \ -file ./reducer.py 1.4、执行程序 $ ./runstreaming_cachefile.sh 18/01/26 15:38:27 WARN streaming.StreamJob: -file option is deprecated, please use generic option -files instead. 18/01/26 15:38:28 WARN streaming.StreamJob: -cacheFile option is deprecated, please use -files instead. 18/01/26 15:38:28 WARN streaming.StreamJob: -jobconf option is deprecated, please use -D instead. 18/01/26 15:38:28 INFO Configuration.deprecation: mapred.job.name is deprecated. Instead, use mapreduce.job.name packageJobJar: [./mapper.py, ./reducer.py, /tmp/hadoop-unjar1709565523181962236/] [] /tmp/streamjob6164905989972408041.jar tmpDir=null 18/01/26 15:38:29 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032 18/01/26 15:38:29 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032 18/01/26 15:38:31 INFO mapred.FileInputFormat: Total input paths to process : 1 18/01/26 15:38:31 INFO mapreduce.JobSubmitter: number of splits:2 18/01/26 15:38:32 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1516345010544_0012 18/01/26 15:38:32 INFO impl.YarnClientImpl: Submitted application application_1516345010544_0012 18/01/26 15:38:32 INFO mapreduce.Job: The url to track the job: http://localhost:8088/proxy/application_1516345010544_0012/ 18/01/26 15:38:32 INFO mapreduce.Job: Running job: job_1516345010544_0012 18/01/26 15:38:40 INFO mapreduce.Job: Job job_1516345010544_0012 running in uber mode : false 18/01/26 15:38:40 INFO mapreduce.Job: map 0% reduce 0% 18/01/26 15:38:49 INFO mapreduce.Job: map 50% reduce 0% 18/01/26 15:38:50 INFO mapreduce.Job: map 100% reduce 0% 18/01/26 15:38:57 INFO mapreduce.Job: map 100% reduce 100% 18/01/26 15:38:57 INFO mapreduce.Job: Job job_1516345010544_0012 completed successfully 18/01/26 15:38:57 INFO mapreduce.Job: Counters: 49 File System Counters FILE: Number of bytes read=73950 FILE: Number of bytes written=582590 FILE: Number of read operations=0 FILE: Number of large read operations=0 FILE: Number of write operations=0 HDFS: Number of bytes read=636501 HDFS: Number of bytes written=27 HDFS: Number of read operations=9 HDFS: Number of large read operations=0 HDFS: Number of write operations=2 Job Counters Launched map tasks=2 Launched reduce tasks=1 Data-local map tasks=2 Total time spent by all maps in occupied slots (ms)=12921 Total time spent by all reduces in occupied slots (ms)=5641 Total time spent by all map tasks (ms)=12921 Total time spent by all reduce tasks (ms)=5641 Total vcore-milliseconds taken by all map tasks=12921 Total vcore-milliseconds taken by all reduce tasks=5641 Total megabyte-milliseconds taken by all map tasks=13231104 Total megabyte-milliseconds taken by all reduce tasks=5776384 Map-Reduce Framework Map input records=2866 Map output records=9243 Map output bytes=55458 Map output materialized bytes=73956 Input split bytes=198 Combine input records=0 Combine output records=0 Reduce input groups=3 Reduce shuffle bytes=73956 Reduce input records=9243 Reduce output records=3 Spilled Records=18486 Shuffled Maps =2 Failed Shuffles=0 Merged Map outputs=2 GC time elapsed (ms)=360 CPU time spent (ms)=3910 Physical memory (bytes) snapshot=719896576 Virtual memory (bytes) snapshot=8331550720 Total committed heap usage (bytes)=602931200 Shuffle Errors BAD_ID=0 CONNECTION=0 IO_ERROR=0 WRONG_LENGTH=0 WRONG_MAP=0 WRONG_REDUCE=0 File Input Format Counters Bytes Read=636303 File Output Format Counters Bytes Written=27 18/01/26 15:38:57 INFO streaming.StreamJob: Output directory: /output/wordcount/wordwhitecachefiletest 1.5、查看结果 $ hadoop fs -ls /output/wordcount/wordwhitecachefiletest Found 2 items -rw-r--r-- 1 hadoop supergroup 0 2018-01-26 15:38 /output/wordcount/wordwhitecachefiletest/_SUCCESS -rw-r--r-- 1 hadoop supergroup 27 2018-01-26 15:38 /output/wordcount/wordwhitecachefiletest/part-00000 $ hadoop fs -text /output/wordcount/wordwhitecachefiletest/part-00000 and 2573 had 1526 the 5144 以上就完成了分发HDFS上的文件并指定单词的wordcount. 2、hadoop streaming 语法参考 http://blog.51cto.com/balich/2065419 本文转自 巴利奇 51CTO博客,原文链接:http://blog.51cto.com/balich/2065812

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

hadoop mapreduce开发实践之输出数据压缩

1、hadoop 输出数据压缩 1.1、为什么要压缩? 输出数据较大时,使用hadoop提供的压缩机制对数据进行压缩,可以指定压缩的方式。减少网络传输带宽和存储的消耗; 可以对map的输出进行压缩(map输出到reduce输入的过程,可以shuffle过程中网络传输的数据量) 可以对reduce的输出结果进行压缩(最终保存到hdfs上的数据,主要是减少占用HDFS存储) mapper和reduce程序都不需要更改,只需要在streaming程序运行中指定参数即可; -jobconf "mapred.compress.map.output=true" \ -jobconf "mapred.map.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec" \ -jobconf "mapred.output.compress=true" \ -jobconf "mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec" \ 1.2、 run_streaming程序 #!/bin/bash HADOOP_CMD="/home/hadoop/app/hadoop/hadoop-2.6.0-cdh5.13.0/bin/hadoop" STREAM_JAR_PATH="/home/hadoop/app/hadoop/hadoop-2.6.0-cdh5.13.0/share/hadoop/tools/lib/hadoop-streaming-2.6.0-cdh5.13.0.jar" INPUT_FILE_PATH="/input/The_Man_of_Property" OUTPUT_FILE_PATH="/output/wordcount/CacheArchiveCompressFile" $HADOOP_CMD fs -rmr -skipTrash $OUTPUT_FILE_PATH $HADOOP_CMD jar $STREAM_JAR_PATH \ -input $INPUT_FILE_PATH \ -output $OUTPUT_FILE_PATH \ -jobconf "mapred.job.name=wordcount_wordwhite_cacheArchivefile_demo" \ -jobconf "mapred.compress.map.output=true" \ -jobconf "mapred.map.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec" \ -jobconf "mapred.output.compress=true" \ -jobconf "mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec" \ -mapper "python mapper.py WHF.gz" \ -reducer "python reducer.py" \ -cacheArchive "hdfs://localhost:9000/input/cachefile/wordwhite.tar.gz#WHF.gz" \ -file "./mapper.py" \ -file "./reducer.py" 1.3、 执行程序 $ chmod +x run_streaming_compress.sh $ ./run_streaming_compress.sh ... 中间输出省略 ... 18/02/02 10:51:50 INFO streaming.StreamJob: Output directory: /output/wordcount/CacheArchiveCompressFile 1.4、 查看结果 $ hadoop fs -ls /output/wordcount/CacheArchiveCompressFile Found 2 items -rw-r--r-- 1 hadoop supergroup 0 2018-02-02 10:51 /output/wordcount/CacheArchiveCompressFile/_SUCCESS -rw-r--r-- 1 hadoop supergroup 81 2018-02-02 10:51 /output/wordcount/CacheArchiveCompressFile/part-00000.gz $ hadoop fs -get /output/wordcount/CacheArchiveCompressFile/part-00000.gz ./ $ gunzip part-00000.gz $ cat part-00000 and 2573 had 1526 have 350 in 1694 or 253 the 5144 this 412 to 2782 2、hadoop streaming 语法参考 http://blog.51cto.com/balich/2065419 本文转自 巴利奇 51CTO博客,原文链接:http://blog.51cto.com/balich/2068046

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

windows 基于docker下的 spark 开发环境搭建

docker toolbox https://www.docker.com/products/docker-toolbox spark https://hub.docker.com/r/singularities/spark/~/dockerfile/ # start-hadoop-namenode # hadoop fs -mkdir /user # hadoop fs -mkdir /user/root/ # hadoop fs -put ./README.md /user/root # start-spark # start-spark worker [master] # spark-shell # spark-shell --master spark://a60b8c8f9653:7077 scala> val lines = sc.textFile("file:///usr/local/spark-2.1.0/README.md") scala> val lines = sc.textFile("hdfs:///usr/local/spark-2.1.0/README.md") lines: org.apache.spark.rdd.RDD[String] = file:///usr/local/spark-2.1.0/README.md MapPartitionsRDD[1] at textFile at <console>:24 scala> lines.count() res0: Long = 104 scala> lines.saveAsTextFile("hdfs:///user/root/README2.md") // 保存到hdfs 本文转自 拖鞋崽 51CTO博客,原文链接:http://blog.51cto.com/1992mrwang/1895904

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

Android学习笔记--Android开发时常用控件(三)

ProgressBar(进度条) ListView(很重要的显示控件) 例:<ProgressBarandroid:id="@+id/pBar" Style="?Android:attr/progressBarStyleHorizontal"--水平方向的进度条 Android:layout_width="200dp" Android:layout_height="wrap_content" Android:visibility="gone" Android:max=200 /> 代码:1.声明变量 2.根据ID取得控件对象findViewById 3.设置监听类 ClassButtonLinstenerimplementsOnClickListener{ PublicvoidonClick(Viewv){ If(i==0){ pBar.setVisibility(View.VISIBLE); } Elseif(i<pBar.getMax()){ pBar.setProgress(i);--设置主进度条的当前值 pBar.setSecondaryProgress(i+10);--设置第二进度条的当前值 } Else{ pBar.setVisbility(View.GONE); } I=i+10; } } 4.绑定事件 myButton.setOnClickListener(newButtonLinstener()); 例:main布局文件 <ListViewandroid:id="@id/android:list" Android:layout_width="fill_parent" Android:layout_height="wrap_content" Android:drawSelecrorOnTop="false" Android:scrollbars="vertical"/> User布局文件略(两个TextView) 代码:publicclassActivityextendsListActivity{ super.onCreate(savedInstanceState); setContentView(R.layout.main); //用一个集合对象装数据 ArrayList<HashMap<Stirng,String>>list=newArrayList<HashMap<Stirng,String>>(); HashMap<String,String>Map1=newHashMap<String,String>(); HashMap<String,String>Map2=newHashMap<String,String>(); HashMap<String,String>Map3=newHashMap<String,String>(); Map1.put("user_name","zhangsan"); Map1put("user_ip","192.168.0.1"); Map2.put("user_name","lisi"); Map2.put("user_ip","192.168.0.2"); Map3.put("user_name","wangwu"); Map3.put("user_ip","192.168.0.3"); List.add(Map1); List.add(Map2); List.add(Map3); //listActivity对象,map,第二个布局文件,对应hashMap的值对(可想象成列),控件显示的位置 SimpleAdapterlistAdapter=newSimpleAdapter(this,list,R.layout.user,newString[]{"user_name","user_ip"},newint[]{R.id.user_ip,R.id.user_name}); setListAdapter(listAdapter); } //重写 ProtectedvoidonListItemClick(ListViewlv,Viewv,intposition,longid){ super.onListItemClick(1,v,position,id); System.out.println("id--------"+id); System.out.println("position-------"+position) } 本文转自My_King1 51CTO博客,原文链接:http://blog.51cto.com/apprentice/1360573,如需转载请自行联系原作者

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

Android应用开发以及设计思想深度剖析(2)

特别声明:本系列文章LiAnLab.org著作权所有,转载请注明出处。作者系LiAnLab.org资深Android技术顾问吴赫老师。 上节讲述了应用编程的背景,本节主要讲述Android应用的编程思想。 Android 的系统设计,与别的智能手机操作系统有很大区别,甚至在以往的任何操作系统里,很难找到像Android这样进行全面地系统级创新的操作系统。从创新层面 上来说,Android编程上的思想和支持这种应用程序运行环境的系统,这种理念本身就是一种大胆的创新。 整个Android系统,实际主要目的,就是打造一个功能共享的世界。 功 能共享最重要的交互,于是Android创造出一种Intent和IntentFilter配合的低耦合的交互模型,Intent只是一种描述要完成什么 工作跨进程的结构体,而最终如何解析这些Intent并完成其响应,是由IntentFilter来进行换算,最终是由用户来决定如何完成。 而在Intent这种超级交互消息之上,Android进一步把应用程序的实现逻辑拆分成多种特殊的实现: ÞActivity:带显示与交互能力的部分 ÞService:不带显示与交互能力的部分 ÞContent Provider:在功能交互之外,提供数据交互能力的部分 ÞBroadcast Receiver:用来处理广播交互的部分 这四种功能上的拆分,也体现了Android设计者在设计上抽象思绪能力,即便是随着Android迅猛发展,目前已经到了4.1这么功能丰富、用户体验良好的状态,我们编程也还是与这四种功能组件打交道,可以满足我们任何的编程时所需要的任何行为。 而这四种基本组件组成部分,使Android应用程序反倒成了一个“空壳子”。静态上看,应用程序只是一种包装这些功能的容器;从运行态来看,所谓的应用程序,也只是承载某些功能的进程。 1.1 所谓的Android应用程序 我们从前面的例子中看到,无论是编写的代码,还是最后生成的.apk文件,都是没有所谓的应用程序的。应用程序本身是一种虚无的概念,只是一种以zip格式进行压缩的一个文件,一种容器而已。 如 我们前面的Helloworld的例子里所看到的那样,其实一个应用程序里最重要的一个配置文件就是AndroidManifest.xml文件。一个最 简单的项目,除了基本的代码与UI资源,也会需要有个AndroidManifest.xml文件。甚至一些极端一点的例子,我们去市场上下载一些什么主 题包、插件包、权限包之类的.apk文件,解压开,这时可以发现这样的.apk文件里,连代码都没有,只有一些图片之类的文件。 于是,我们 可以得到Android里关于应用程序的第一个印象,作为Android应用程序的载体,.apk文件只是一种进行包装与传输的格式,而每个.apk文件 必然包含一个AndroidManifest.xml文件,由这一文件来描述该.apk文件提供的内容。当然,我们在稍后会看到,这一文件里,还会包含一 些权限控制的信息。 我们可以给我们的应用程序创建两个一模一样的图形界面,直接从我们的前面的HelloWorld开始下手,比如将 HelloWorld.java在Eclipse里拷贝到HelloAgain.java(这样可以减少改代码的麻烦)。这时可以得到两个界面的应用程 序,然后我们再把我们的AndoridManifest.xml文件,改成如下的样子: <?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="org.lianlab.hello" android:versionCode="1" android:versionName="1.0"> <applicationandroid:label="@string/app_name"> <activityandroid:name=".Helloworld" android:label="@string/app_name"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activityandroid:name=".HelloAgain" android:label="@string/app_name"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest> 这时我们编译、安装到Android设备(或者是虚拟机)里,这时再打开主界面查看安装过的应用程序,这时是不是发生了什么很奇怪的现象?这时界面上会出现 两个叫Helloworld的应用程序。我们这时如果在设备里去“设置”à “应用程序”,我们仍只看到一个应用程序。 通过对 AndroidManifest.xml的小恶作剧,我们可以看到Android应用程序的第二个特点,就是没有所谓的主入口(即我们点击的图标时触发的 执行效果)。应用程序在安装完成后,只是通过AndroidManifest.xml来决定在系统上应该表现成什么样子。 如果希望应用程序 可以表现不如此变态,这时,我们可以回到AndroidManifest.xml里, 把<activityandroid:name=".HelloAgain"…这个标签里的<intent-filter>标签删掉, 这时应用程序的表现就正常了。 到目前为止,我们就已经接触了android编程里的两个概念,一个是Activity,另一个是 Intent(而我们AndroidManifest.xml文件里的Intent Filter实际是辅助Intent的)。Android毕竟是种图形界面的编程环境,我们常见的应用程序里,可能绝大部分只会与这两种概念打交道。而两 者的概念组合,就很容易体现出Android应用程序在编程上的“无界化”思想。 1.2 Android世界里的共享 作 为一个智能手机操作系统,其用户可能在功能上有各种各样的功能组合。比如最简单的打电话,则后续动作会有保存联系人,同时需要给联系人拍照做来电大头贴。 又比如需要来了个短信通信用户到某个地方干什么事情,这时,用户需要打开地图,搜索一下地址,然后还有可能需要定位到那个位置。 用户在主界面里点击相应功能的应用程序之后,就可能有非常多的功能性的组合,因为用户的想法是不可预估的。我们当然也可以限制用户当前菜单下可以干什么事情,但这样就失去了智能系统的意义。 我 们也可以假设用户都会按一个“Home”键回到主界面,这时原来的执行的程序就会被锁定当前状态,用户重新打开另外一个应用程序,操作完再按“Home” 键可以退回到原来的应用程序。通过这种“应用程序”到“Home”到“应用程序”的循环,我们也可以达到我们想要达到的目的。但这时,出于交互性的考虑, 我们也还是需要有限地提供一些交互手段,比如“短信”应用程序里包含地址信息,一点击可以直接打开“地图”进行后续操作,但这些有限交互是可以在系统设计 阶段被固化。这时,我们是不是就得到了我们想要的能够应付用户任何操作组合的系统?是的,恭喜您,您得到了iPhone的设计思路。但此时的用户交互流程 则被改变成这个样子: 这种解决问题的办法也不是不可以,但需要很固化的设计,应用程序的行为比较受限。虽然通过横扫全世界的 iPhone证明了这样的设计可能是比较合乎用户体验之道的(不容易出错),但这样的解决思路从系统设计角度来看,并不是很灵活。另外一个麻烦是必须要有 苹果级设计功底的“Home”键,山寨货则用不了多久就会因为键盘失灵而失效。当然即使苹果级设计,iPhone里的“Home”键还是会失效,于是又不 得不在屏幕上加上触摸的Home手势。 作为开源系统的Android,当然不可能基于iOS的交互思路来解决问题,何这种交互时多了一步不 停要回到主界面这一步。在Android的设计里,最重要的是能够解决一个应用程序之间进行交互的问题,然后可以实现我们想要在Android系统里完成 某种操作时,可以享受从一路顺畅完成的快感。 Android的解决之道,则是将传统意义上的应用程序,细化成一个个完成某项功能的部分,这 种功能部分,在Android世界里被称为Activity。Activity都应该被设计成可以独立地被执行以解决某个问题,当它完成或是用户选择退出 执行时,又会自动跳回到调用这一Activity的界面,当然这时跳回的位置肯定是另外一个Activity。当然,在一个Android系统里有可能存 在无限多的Activity,在他们进行跳转切换时,我们就需要一种很灵活的消息传输机制(因为我们必须兼容系统里所有可能的互相调用的情况)。而且这种 传输机制还必须能够跨进程,不然,我们所有的涉及Activity互相调用部分都必须在同一进程里完成。于是,Android系统里又有了Intent, 用于解决交互通信。 这样的编程模型也需要有一定前提,那就是我们Application概念必须被弱化,我们不能有main 函数入口(如果系统执行依赖main作入口,则不能实现Activity之间互相调用了,所有的Activity执行之前,必须先通过main入口来初始 化环境)。出于这样的设计,所以Application必须只是一个容器,将各种不同的Activity实现包装起来加载到系统里。 当然, 将功能拆分成一个个的单一功能界面之后,我们需要有种机制可以将用户一路点击过去历史记录下来,当用户处理完时,可以退回到他们之前操作过的界面,这次就 可以由多个应用程序组合出像是在用同一个应用程序的效果。有了Activity,有了Activity之间起到调用作用的Intent,这时所有界面间操 作变得有点像是函数调用一样,于是我们可以找函数调用时的基本数据结构—栈来帮忙,发生调用时,需要退出的Activity及其状态压栈,当从调用退出时 则进行栈的弹出操作,这时我们的Activity管理就演变成如下图所示的简单栈管理。 有了这样的概念,于是我们响应用户点 击操作的问题便迎刃而解,我们在设计应用程序时,不再是设计一个复杂的功能实现,而是实现一组完成单项功能的实现,也就是Activity。然后这些 Activity,只会通过用户点击来驱动它们之间是如何进行交互的。比如,我们前面看到的地图、搜索、定位三个功能,虽然它都会被包装到同一个地图的应 用程序里,但在实现上会是地图、搜索、定位三个不同的Activity。 因为现在我们的界面上的互相调用,已经变成了一种函数式的调用,这 样,整个手机上的功能都被切分成各个单一的小功能,而真正要在Android系统上完整地实现某复杂个操作,则会提交由用户的点击来组合生成。这样的复杂 功能,则已经不是一个编程上的概念了,在Android系统里,这种需要完成什么事情的操作被抽象成一个虚拟的概念Task。比如我们前面提到的打电话加 拍大头贴的操作组合,就构成一个Task,这一Task需要由Launcher.apk,Contacts.apk,Gallery.apk来协同完成。 如 果我们有两个能够提供同样功能的Activity,这种执行模式的灵活性表现得会更加明显。比如中间打电话的功能,我们系统里有三个 Activit(CallScreen, SipPhone, Dialer)都可以完成电话呼叫的功能,这时执行上的路径则会有三种可能性,会在进行跳转时弹出对话框由用户来选择: 通 过Activity的这种可以动态被用户选择的特点,当用户对某一功能不满意时,完全就有可能通过下载另一个能实现这种功能的应用程序进行替换,甚至可以 自己写一个。事实上,Android系统里除了系统状态条与锁屏界面之后,没有任何的不可被替换的功能,这也是Android设备总是会长得千奇百怪的原 因之一。 到这时,我们就可以看到Activity之所以会不被称为Window的原因,它也是单个界面或是MVC里的Controller 实现部分那么简单,Activity这个名字代表的是某种单一交互功能上的实现。这种功能的实现将在系统里通过Intent串接起来,构成了一个在功能上 具备极大可拓展性的系统。基于这样的特点,Android也就被称作是“无边界”系统,因为它在功能上延展不再受限于系统的能力,而只受限于智商与创意。 这就是Android世界里的功能共享。 在这种功能共享模型之下,可能还是会有一些微调的需求: 1.我 们有一些情况下不宜使用这种栈式Activity管理,比如我们写一个需要注册的应用程序,注册完开始使用,然后再按退出,我们又会一步步退回到注册填个 人信息的界面,而不合理地完全退出。这样可能不合适。这时,我们可以使用Intent的Flag参数, 加上Activity的Affinity属性进行组合控制。 2.如果不停地跳出对话框让用户选,用户会崩溃掉。 当然,用户可以在选择时点选一个“始终”的默认选择,这时下次就会使用默认的Activity处理某种操作。但还是有可能会不合理地使用跨.apk文件里 使用Activity,造成性能上的开销,这时,我们也可以在执行下次Activity执行操作时进行强制性地指定。 当然,我们通过 Activity这种概念还需要另外一个前提,这就是Android会有别于传统操作系统的前提,那就是单窗口。想像一下,在多窗口环境下,我们的栈式管 理Activity在进行跳转和返回时将会构成多大的灾难啊。好在使用电容屏的设备,单窗口是天生的需求。由于手指触摸的精度非常低,无法点准过小的按 钮,比如窗口上的关闭按钮,如果将这些按钮放大,又造成了屏幕显示空间上的浪费。iPhone带来的“后PC时代”革命,最重要的一点就是使用“返祖”式 的单窗口显示。 这种怪异的操作方式,实际上在我们生活中也有类似的例子,就比如说我们的动态网页。动态网页,特别是HTML5构建的网络应 用程序,其操作模式,就是可以在不同的链接里不断地点击下去,如果不是弹出新窗口,我们始终还可以退回到发起这一连串点击的起始页面。Android应用 程序,XML构成的UI语言的作用跟Html页面类似,而Java构建的Activity就相当与网页交互中使用的JavaScript,有了这样的相似 性,Android编程环境可以说是最接近HTML5的一种编程环境了,但可惜不能像HTML5那样可以跨平台。 我们解析了能完成单一功能 的Activty,这时还需要了解Intent,就像是我们了解过了函数实现原理,我们还需要掌握函数之间的参数传递。当然,一般在介绍编程的思路里,会 结合起来说明,或是先说明参数传递。但Android环境里有点特殊性,一是Intent是一种能够实现跨进程调用的信息传递机制,二是Intent在消 息传递上又很灵活,有一定的动态性。Intent不光服务于Activity之间的调用,还会用于一些不直接与界面打交道的逻辑实现部分,比如我们后面将 提到的Service,Broadcast Receiver,以及 Notification。 1.3 Intent与Intent Filter Intent, 英文原意就是要“干什么”的意思,之所以取这个名字,也是因为在Android系统里,Intent所起到的作用就是用来指明下一步具体是做什么,具体是 不是执行,由谁来执行,则会由根据当前的系统状态(能不能解析这个Intent请求)来决定。这不只是简简单单地发个消息而已,而是一种更安全的、更加松 散的消息机制。 在一个Intent消息对象里,共有六个成员(并不都是必须赋值的,只要一个Intent对象能够被解析,就会得以执行,否则就会会被舍弃): 成员 类型 说明 示例 ComponentName String 用于定义谁将处理这一Intent。它由一个Activity的具体实现的全名(加上包名)来指定 org.lianlab.hello.HelloActivity Action String 用于定义这一动作是做什么,可以被拓展自定义类型 ACTION_CALL 开始通话. ACTION_EDIT 进行编辑. Data String 用一个URI来指定Intent的操作对象,因为URI一般会包含种类信息,于是这个值也可能被用作MIME设别。 “content://contacts/people/1” 指定联系列表中的第一个 Category String 用来进一步明确什么样的可执行实体将处理这一Intent。是可选项,也可多选。 CATEGORY_HOME 主界面应用程序 CATEGORY_LAUNCHER 可在主界面里被点击 Type String 用来指定特定的MIME类型 "video/*" 视频 Extra Bundle 用来传递额外的数据传递,前面我们也介绍了Bundle是一种key:value配对的字典类型,于是Extra里可以转递复杂的数据 putExtra("sms_body", "some text"); 发短信时指定内容 Flags int 预定义一系列用来控制Intent行为的属性值 在 这个成员变量里,最能体现灵活性的就是Component,如果指定了这个值,则我们在通过startActivity()方法来发送Intent时,就 会自动启动Component指定的Activity。如果没有指定,则会由系统来选择一个能够处理这一Intent的Activity来执行,这时就引 入了Intent Filter的概念。 Intent Filter在Android里是一种类似于Windows里的注册表一样的东西,虽然我们也可以通过编程来进行Intent Filter的控制,但一般情况下,我们只在AndroidManifest.xml文件里进行定义,对它一个<intent- filter>的标签进行指定。应用程序在安装过程中,它的AndroidManifest.xml会被系统扫描并汇总到系统环境里,这 时<intent-filter>也会被导入。当Activity发送出来的Intent,没有指定Component时,系统就会通 过<intent-filter>找到合适的处理对象,如果只有一个或是用户设置了默认项,则启动这个功能部件来完成任务;如果有多 个<intent-filter>匹配同时用户又没有指定默认项,则会弹出对话框让用户选择。当然,默认项也会随着系统里新增了同一 Intent匹配项而失效,用户也可以通过“设置”à “应用程序”来取消默认值。 在AndroidManifest.xml里面定义<intent-filter>很简单,就是通过指定Intent对象的Action,Data,Type,和Category这四个成员变量来指定。比如: <activityandroid:name=".PlayerActivity"android:label="@string/app_name" android:configChanges="orientation"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> <intent-filter> <actionandroid:name="android.intent.action.VIEW"/> <categoryandroid:name="android.intent.category.DEFAULT"/> <dataandroid:scheme="file"/> </intent-filter> ... </activity> 当我们的某个Activity,发送了一个Intent,其Action是”android.intent.action.VIEW”,data又是以file:///开始的URI指定的内容(也就是文件类型),这时上面例子里的PlayerActivity就会成为播放时的候选项。 我 们可以继续修改我们前面的HelloWorld的例子,我们新建一个Intent,将Action设 成”android.intent.action.VIEW”(可以通过Intent.ACTION_VIEW这个预变量来转义),data使用某个文件 “file:///sd-ext/Movies/test.mp4”,这时就会匹配到我们上面的<intent-filter>定义: publicvoidonClick(Viewv) { Intent request =newIntent(Intent.ACTION_VIEW); request.putData(“file:///sd-ext/Movies/test.mp4”); startActivity(request); finish(); } 当然,我们并不一定需要代码来进行这样的测试,我们也可以使用设备上的am命令来完成。要完成与上面的点击操作一样的功能,也可以通过adb来执行这条命令: $adb shell am start –aandroid.intent.action.VIEW –d file:///sd-ext/Movies/test.mp4 在我们具体写代码过程中,我们可以根据需求来定义我们所需要的<intent-filter>,可以将过滤规则写得很细,也可以写得很粗,让我们的Activity有更多地被执行到的机会。在这些规则里,可能最重要的规则,就是我们前面也示范过的: <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> 这两行<intent-filter>规则,将使用我们的应用程序可以被主界面所收集,使用户可以在主界面里点击运行这个Activity。 有了Activity,我们就可以构建基于功能共享而实现所谓应用程序,而有了Intent,使用我们在共享时所受的限制可以变得更小。而且,由于是简单化的单窗口模式,再加上一些在性能设计上的精细设计,于是我们的Android系统便有了良好的人机交互体验。 1.4 编程角度的应用程序 光 有Activity与Intent,并不是Android应用程序编程时的全部。应用程序除了有人机交互界面之外,有可能还需要使用到一些不直接与人交互 而在后台长期运行操作;我们还需要有某种机制,能够提供数据共享,并且在数据共享时能使用统一的访问机制;最后,我们可能还需要处理以广播方式发送的消 息,广播与Intent不同之处在于一到多的方式传播,同时消息只在某个时间段内有效。 事实上,我们的Android编程,是被包装成四个不同的类型,同时通过Intent将这些类包装起来,以解决我们上面提到的,在编写图形应用程序里可能遇到的问题的: lIntent: 全局性的、松散的消息传递机制 lActivity:带图形界面的,可以与用户进行交互的逻辑实现。 lService: 不带图形界面的,不直接与用户交互的代码。一般会被用于在后台做些什么事情,比如监听网络、下载、拷贝文件等。(这可能是一般的Android工程师觉 得没有必要实现的部分,笔者在讲解Android应用程序相关的课程时,就常有问及,Actiivity会进入到后台,然后有可能被杀死掉,这样的问题如 何解决?实际上Activity只解决交互,需要在后台时还需要继续执行的代码,需要用Service来实现。只自己可访问的Service,可以使用简 单的本地Service,而需要提供给别的进程来访问的情况下,我们需要通过AIDL编写Remote Service。Service的实现,我们在后台再详细说明,因为Android系统的核心Framework,本身就是由大量这样的Remove Service来组成的。) lContent Provider: 提供数据层共享,以CRUD(Create Read Update Delete)方式进行数据访问来统一化数据读写指口一种模型。如果使用了Sqlite做后台的数据支持(实际上相当于应用程序MVC模型里的Model 部分被Sqlite延展开来),我们可以通过ContentProvider来各系统内的其他部分提供数据源,当然系统本身也给我们提供了大量这样的 ContentProvider,像Setting里的设置的值、联系列表、多媒体文件扫描结果等。(这种数据层上的共享机制,也是应用程序编程上需要加 强的技巧之一,因为有了Content Provider,我们则有可能使用Cursor式进行访问,这时我们就可以使用CursorAdapter来自动化地处理数据源。) lBroadcast Receiver: 处理广播类消息的监听器,从而可以给应用程序提供广播式的信息处理,同时也提供系统消息的广播式分发。比如,Android会将一些系统事件广播出来,像 电话振铃、电量状态变化、网络状态变化等,我们需要能够处理这样的事件,电话振铃时我们写的多媒体播放器就应该静音、电量过低时需要保存状态等。对我们应 用程序而言,广播方式也是一种很好的通信机制,我们不需要写一个循环通知所有的Activity、Service我们状态发生了改变,而只需要发一个广 播,则所有关心这一事件的部分都可以收到。 这些功能实体,都是我们通过Java代码根据不同的基类(Service、 ContentProvider、BroadcastReceiver)派生出相应的子类,再加以具体实现。这样的功能实现不需要自己去创建这个对象,会 通过AndroidManifest.xml里的定义,由系统按执行的需要自动创建。有了这些不同的功能实体,我们最后的应用程序,实际上就成了这个样 子: 而我们的所有代码,从运行态行为来看,都不再是直接的互相调用关系,而是全部都通过Intent来进行彼此之间的交互。而这样的交互,也不再是传统式地自己陪自己玩,而是会进入到一个大的功能集合体时,提供功能给系统内其他应用程序所使用,而自己也会调用其他部分的代码。 当然,随着Android版本变更,Android系统又新增了一些新的概念,比如针对多窗口功能的Fragment、针对于使用异步机制操作Cursor的Loader等。但万变不离其宗,这些Android的核心原理则一直如此。 总 结一下Android编程思想,我们就会知道其实在Android整个生态环境最重要的元素,应用程序,反倒是Android编程上最不重要的。所谓的 Android编程,就是要通过编写一个个的Activity、Service、Content Provider、Broadcast Receiver实现,通过功能上的共享与数据上的共享进一步丰富用户可用的功能。当用户可以通过Market或自己下载取得我们封装到.apk文件里的 实现之后,这些功能就会无缝地被Intent整合到了一起。 从Android这个编程原则来看,我们可以看到,如果我们使用某种Java执 行环境,将Android应用程序的这些组成部分的支持都加入进来,我们也可以得到一个Android兼容的环境。的确如此,已经有人在打这方面的主意, 有将Android环境移植到Windows环境里的BlueStack商业解决方案,也有号称兼容Android应用程序,通过一个类似于JAVA ME的虚拟机环境来支持Android应用程序的BlackBerryOS。但我们可以再来看看Android的真正的支持环境,我们可以看 到,Android有其独特的特性,也不是那么容易被取代。 本文转自 21cnbao 51CTO博客,原文链接:http://blog.51cto.com/21cnbao/975590,如需转载请自行联系原作者

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

iOS开发:Objective-C数据类型转换

按照数据类型占用存储不同可以自动类型转换或强制类型转换,总的原则是小存储容量数据类型可以自动转换成为大存储容量数据类型。 不同类型数据间按照下面关系的从左到右(从低到高)自动转换, _Bool 、 char 、 short int 、枚举类型 -> int ->long int->long long-> float -> double -> long double 。 如果这些数据类型进行混合运算,运算中不同类型的数据先转化为同一类型,然后进行运算,转换从左到右自动转换,如表 2-3 所示。 表 2-3 类型转换先后顺序表 如果有下面的表示式,其中, f 是 float 类型, i 为 int 类型, l 为 long int 类型, s 为 short int 类型,结果是什么类型? f * i + l /s 运行结果为 float 类型,这是因为 f 是 float 其它的操作数与 float 运算其结果就是 float 类型。 如果遵守类型转换是右到左情况,就需要强制类型转换 了,强制类型转换语法形式上很简单,就是在数据前面加上(目标类型),但是这种转换是存在风险的,有可能造成数据的丢失,需要谨慎进行。例如: long int l = 6666666666; NSLog(@"l = %li",l); int i = (int)l; NSLog(@"i = %i",i); 运行的结果是,其中 6666666666 数值已经超出了 int 类型的容量,因此出现了数据的丢失。 l = 6666666666 i = -1923267926 强制转换有的时候嵌入在其它的表达式里面,它会与运行的优先级交织在一起,情况就会变的更加复杂,假设有下面的几条语句: int total = 3446; int n = 6; float average = total / n; 运行完成 float 的变量 average 结果是 574 ,小数点内容被截取掉了,如果我们采用下面的语句实现: int total = 3446; int n = 6; float average = (float)total / n; 运行完成 float 的变量 average 结果是 574.333 ,这个数据要比上面计算的精确,这是因为 (float)total 先把 int 类型的 total 变量转换成为 float 类型的 total 变量。 本文转自 wws5201985 51CTO博客,原文链接:http://blog.51cto.com/wws5201985/818591,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

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

Nacos

Nacos

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

Sublime Text

Sublime Text

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

用户登录
用户注册