精选列表

搜索[初体验],共231篇文章
优秀的个人博客,低调大师

Docker初体验,向Docker Hub推送第一个Docker镜像

一、注册Docker Hub账号 打开Docker Hub网站,找到注册选项,按照常规注册流程进行注册即可。需要注意的是,有时候可能需要进行人机识别验证,这需要调用Google的验证服务。众所周知Google在国内的情况,需要自己想办法搞定。如果人机验证这一步过不去,那么Docker Hub的账号是无法注册成功的。 二、通过Dockerfile构建镜像 这一步在之前的文章中有所涉及,操作如下: [root@ChatDevOps docker-test]# docker build -f /root/docker-test/Dockerfile -t chatdevops/myapp . Sending build context to Docker daemon 157.4 MB Step 1/7 : FROM python:2.7-slim ---> 46ba956c5967 Step 2/7 : WORKDIR /app ---> Using cache ---> 874ecbc1dfc0 Step 3/7 : ADD . /app ---> Using cache ---> fe2d0e196a64 Step 4/7 : RUN pip install --trusted-host pypi.python.org -r requirements.txt ---> Running in caf394f66822 ... ... 以上命令中,选项-f指定了Dockerfile的路径,选项-t指定了新的镜像的仓库名称及镜像名称,还可以指定镜像的标签。命令末尾的点代表构建新镜像的当前目录,也可以写成完整路径。 [root@ChatDevOps docker-test]# docker build -f /root/docker-test/Dockerfile -t chatdevops/myapp:1.01 /root/docker-test/ 三、登录Docker Hub 我在Docker Hub注册的账号为chatdevops,现在使用该账号进行登录。完整命令如下: [root@ChatDevOps docker-test]# docker login Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username (chatdevops): chatdevops Password: Login Succeeded 四、给新构建的本地镜像打标签 如果本地镜像的仓库名与你新注册的Docker Hub账号名称不一致,就需要使用docker tag进行重新打标签,具体命令格式为: docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] 因为我注册的账号与我本地仓库的名称都是chatdevops,所以我在操作过程中省略了tag这一步。但是为了演示这个例子,我再次tag一下。 [root@ChatDevOps docker-test]# docker tag chatdevops/myapp:1.01 chatdevops/myapp:1.02 [root@ChatDevOps docker-test]# docker image ls chatdevops/myapp REPOSITORY TAG IMAGE ID CREATED SIZE chatdevops/myapp 1.01 c4bec2582bf3 47 minutes ago 309 MB chatdevops/myapp 1.02 c4bec2582bf3 47 minutes ago 309 MB chatdevops/myapp latest c4bec2582bf3 47 minutes ago 309 MB 五、将新构建的本地镜像推送到Docker Hub 通过docker push命令可以将一个或多个本地镜像推送到Docker Hub。 [root@ChatDevOps docker-test]# docker push chatdevops/myapp 该命令将镜像myapp的所有标签全部推送到Docker Hub。我们看一下效果:我们可以在其他机器上直接创建容器。例如:我们使用镜像chatdevops/myapp:1.02在10.1.1.12这台机器上创建一个名为test-app的容器。 [root@ChatDevOps ~]# docker run -i -t --name test-app chatdevops/myapp:1.02 Unable to find image 'chatdevops/myapp:1.02' locally Trying to pull repository docker.io/chatdevops/myapp ... 1.02: Pulling from docker.io/chatdevops/myapp 4d0d76e05f3c: Pull complete da828db4a2d5: Pull complete dae8f1abda34: Pull complete 7f80c063ca4d: Pull complete 4ad5318a2b9b: Pull complete 95a59aa8e00b: Pull complete 776fee21eb8e: Pull complete Digest: sha256:4de441303d87d392b36fc1218a1be18e3b2bf5b81c9e88eed8688c402f06a793 Status: Downloaded newer image for docker.io/chatdevops/myapp:1.02 [root@ChatDevOps ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 09fe7a428ecc chatdevops/myapp:1.02 "python app.py" About a minute ago Up About a minute 80/tcp test-app 在运行这个容器的过程中,docker会从Docker Hub拉取镜像chatdevops/myapp:1.02存放于本地,再创建容器。当然也可以先将Docker Hub的镜像拉取到本地再创建容器。 六、总结 通过以上步骤,我们将自己创建的容器上传的Docker Hub的仓库中,无论我们在哪里,只要网络能顺利与Docker Hub互联,我们就可以随时随地运行我们自己构建的镜像创建的容器,非常方便。此处我们使用的是公开的仓库,还可以将我们的镜像共享给其他需要的人呢,非常方便。可以通过关键字搜索一下我刚刚创建的镜像。

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

Docker初体验,创建并导出第一个本地镜像

准备工作,创建一个目录docker-test,用来存放创建镜像所需的文件,同事完成相关文件的创建。 [root@ChatDevOps ~]# mkdir docker-test [root@ChatDevOps ~]# cd docker-test/ [root@ChatDevOps docker-test]# touch Dockerfile [root@ChatDevOps docker-test]# touch app.py [root@ChatDevOps docker-test]# touch requirements.txt 在Dockerfile中加入以下内容: # Use an official Python runtime as a parent image FROM python:2.7-slim # Set the working directory to /app WORKDIR /app # Copy the current directory contents into the container at /app ADD . /app # Install any needed packages specified in requirements.txt RUN pip install --trusted-host pypi.python.org -r requirements.txt # Make port 80 available to the world outside this container EXPOSE 80 # Define environment variable ENV NAME World # Run app.py when the container launches CMD ["python", "app.py"] 在app.py中增加以下内容: from flask import Flask from redis import Redis, RedisError import os import socket # Connect to Redis redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2) app = Flask(__name__) @app.route("/") def hello(): try: visits = redis.incr("counter") except RedisError: visits = "<i>cannot connect to Redis, counter disabled</i>" html = "<h3>Hello {name}!</h3>" \ "<b>Hostname:</b> {hostname}<br/>" \ "<b>Visits:</b> {visits}" return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits) if __name__ == "__main__": app.run(host='0.0.0.0', port=80) 在requirements.txt中添加以下内容: Flask Redis 安装pip,并使用pip安装Flask和Redis: [root@ChatDevOps docker-test]# curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py [root@ChatDevOps docker-test]# python get-pip.py [root@ChatDevOps docker-test]# pip install -r requirements.txt [root@ChatDevOps docker-test]# rm -rf get-pip.py [root@ChatDevOps docker-test]# ls app.py Dockerfile requirements.txt 执行构建命令,使用-t选项指定镜像的仓库、标签。注意,镜像名称必须小写。 [root@ChatDevOps docker-test]# docker build -t local/chatdevops . Sending build context to Docker daemon 4.608 kB Step 1/7 : FROM python:2.7-slim Trying to pull repository docker.io/library/python ... 2.7-slim: Pulling from docker.io/library/python ... ... [root@ChatDevOps docker-test]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE local/chatdevops latest fc26e265213a 21 minutes ago 151 MB docker.io/fedora latest cc510acfcd70 2 weeks ago 253 MB 使用刚刚创建的镜像构建一个容器,并将容器的80端口映射到本机的4000端口。 [root@ChatDevOps docker-test]# docker run -p 4000:80 local/chatdevops * Serving Flask app "app" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:80/ (Press CTRL+C to quit) 172.17.0.1 - - [23/May/2018 04:21:04] "GET / HTTP/1.1" 200 - 172.17.0.1 - - [23/May/2018 04:21:04] "GET /favicon.ico HTTP/1.1" 404 - 172.17.0.1 - - [23/May/2018 04:22:24] "GET / HTTP/1.1" 200 - 在浏览器看一下效果:镜像制作完成,导出镜像,选项-o表示将导出内容写入一个文件,替代了标准输出。 [root@ChatDevOps docker-test]# docker save -o chatdevops.tar local/chatdevops [root@ChatDevOps docker-test]# ll 总用量 153716 -rw-r--r--. 1 root root 666 5月 23 09:52 app.py -rw-------. 1 root root 157392896 5月 23 11:47 chatdevops.tar -rw-r--r--. 1 root root 509 5月 23 11:12 Dockerfile -rw-r--r--. 1 root root 12 5月 23 09:51 requirements.txt 在异机上导入刚刚创建的镜像。 [root@ChatDevOps docker-test]# scp chatdevops.tar root@10.1.1.1.12:/root/ [root@ChatDevOps ~]# ll 总用量 153704 -rw-------. 1 root root 157392896 5月 23 14:30 chatdevops.tar [root@ChatDevOps ~]# docker load --input chatdevops.tar ba291263b085: Loading layer [==================================================>] 82.94 MB/82.94 MB 10dd6271862c: Loading layer [==================================================>] 7.487 MB/7.487 MB 4e1a46391216: Loading layer [==================================================>] 46.96 MB/46.96 MB a40d037570f2: Loading layer [==================================================>] 7.649 MB/7.649 MB d9bad830e350: Loading layer [==================================================>] 1.536 kB/1.536 kB 16b29278858d: Loading layer [==================================================>] 5.12 kB/5.12 kB b6e1c4419841: Loading layer [==================================================>] 12.32 MB/12.32 MB Loaded image: local/chatdevops:latest [root@ChatDevOps ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE local/chatdevops latest dea564c3cb05 3 hours ago 151 MB 本文是Docker官方文档的实例的实践与拓展,刚刚学习Docker,诸多问题还望大家海涵和指教。

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

Spark2.1.0之初体验

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/80042366 在《Spark2.1.0之运行环境准备》一文中,已经介绍了如何准备好基本的Spark运行环境,现在是时候实践一下,以便于在使用过程中提升读者对于Spark最直接的感触!本文通过Spark的基本使用,让读者对Spark能有初步的认识,便于引导读者逐步深入学习。 运行spark-shell 在《Spark2.1.0之运行环境准备》一文曾经简单运行了spark-shell,并用下图进行了展示(此处再次展示此图)。 图1执行spark-shell进入Scala命令行 图1中显示了很多信息,这里进行一些说明: 在安装完Spark 2.1.0后,如果没有明确指定log4j的配置,那么Spark会使用core模块的org/apache/spark/目录下的log4j-defaults.properties作为log4j的默认配置。log4j-defaults.properties指定的Spark日志级别为WARN。用户可以到Spark安装目录的conf文件夹下从log4j.properties.template复制一份log4j.properties文件,并在其中增加自己想要的配置。 除了指定log4j.properties文件外,还可以在spark-shell命令行中通过sc.setLogLevel(newLevel)语句指定日志级别。 SparkContext的Web UI的地址是:http://192.168.0.106:4040。192.168.0.106是笔者安装Spark的机器的ip地址,4040是SparkContext的Web UI的默认监听端口。 指定的部署模式(即master)为local[*]。当前应用(Application)的ID为local-1497084620457。 可以在spark-shell命令行通过sc使用SparkContext,通过spark使用SparkSession。sc和spark实际分别是SparkContext和SparkSession在Spark REPL中的变量名,具体细节已在《Spark2.1.0之剖析spark-shell》一文有过分析。 由于Spark core的默认日志级别是WARN,所以看到的信息不是很多。现在我们将Spark安装目录的conf文件夹下的log4j.properties.template以如下命令复制出一份: cp log4j.properties.template log4j.properties 并将log4j.properties中的log4j.logger.org.apache.spark.repl.Main=WARN修改为log4j.logger.org.apache.spark.repl.Main=INFO,然后我们再次运行spark-shell,将打印出更丰富的信息,如图2所示。 图2 Spark启动过程打印的部分信息 从图2展示的启动日志中我们可以看到SecurityManager、SparkEnv、BlockManagerMasterEndpoint、DiskBlockManager、MemoryStore、SparkUI、Executor、NettyBlockTransferService、BlockManager、BlockManagerMaster等信息。它们是做什么的?刚刚接触Spark的读者只需要知道这些信息即可,具体内容将在后边的博文给出。 执行word count 这一节,我们通过word count这个耳熟能详的例子来感受下Spark任务的执行过程。启动spark-shell后,会打开Scala命令行,然后按照以下步骤输入脚本: 步骤1 输入val lines =sc.textFile("../README.md", 2),以Spark安装目录下的README.md文件的内容作为word count例子的数据源,执行结果如图3所示。 图3 步骤1执行结果 图3告诉我们lines的实际类型是MapPartitionsRDD。 步骤2 textFile方法对文本文件是逐行读取的,我们需要输入val words =lines.flatMap(line => line.split(" ")),将每行文本按照空格分隔以得到每个单词,执行结果如图4所示。 图4 步骤2执行结果 图4告诉我们lines在经过flatMap方法的转换后得到的words的实际类型也是MapPartitionsRDD。 步骤3 对于得到的每个单词,通过输入val ones = words.map(w => (w,1)),将每个单词的计数初始化为1,执行结果如图5所示。 图5 步骤3执行结果 图5告诉我们words在经过map方法的转换后得到的ones的实际类型也是MapPartitionsRDD。 步骤4 输入val counts = ones.reduceByKey(_ + _),对单词进行计数值的聚合,执行结果如图6所示。 图6 步骤4执行结果 图6告诉我们ones在经过reduceByKey方法的转换后得到的counts的实际类型是ShuffledRDD。 步骤5 输入counts.foreach(println),将每个单词的计数值打印出来,作业的执行过程如图7和图8所示。作业的输出结果如图9所示。 图7 步骤5执行过程第一部分 图8 步骤5执行过程第二部分 图7和图8展示了很多作业提交、执行的信息,这里挑选关键的内容进行介绍: SparkContext为提交的Job生成的ID是0。 一共有四个RDD,被划分为ResultStage和ShuffleMapStage。ShuffleMapStage的ID为0,尝试号为0。ResultStage的ID为1,尝试号也为0。在Spark中,如果Stage没有执行完成,就会进行多次重试。Stage无论是首次执行还是重试都被视为是一次Stage尝试(Stage Attempt),每次Attempt都有一个唯一的尝试号(AttemptNumber)。 由于Job有两个分区,所以ShuffleMapStage和ResultStage都有两个Task被提交。每个Task也会有多次尝试,因而也有属于Task的尝试号。从图中看出ShuffleMapStage中的两个Task和ResultStage中的两个Task的尝试号也都是0。 HadoopRDD则用于读取文件内容。 图9 步骤5输出结果 图9展示了单词计数的输出结果和最后打印的任务结束的日志信息。 笔者在本文介绍的word count例子是以SparkContext的API来实现的,读者朋友们也可以选择在spark-shell中通过运用SparkSession的API来实现。 有了对Spark的初次体验,下面可以来分析下spark-shell的实现原理了,请看——《Spark2.1.0之剖析spark-shell》 关于《Spark内核设计的艺术 架构设计与实现》经过近一年的准备,基于Spark2.1.0版本的《 Spark内核设计的艺术 架构设计与实现》一书现已出版发行,图书如图: 纸质版售卖链接如下: 京东: https://item.jd.com/12302500.html 电子版售卖链接如下: 京东: https://e.jd.com/30389208.html

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

Kotlin初体验

距离kotlin成为Android一级开发语言已经一年了,这节将从零开始,实现kotlin的几个小知识点。 以下操作是在AndroidStudio3.0.1下完成的,如果是3.0以下版本的AndroidStudio,需要安装好kotlin插件才能使用Kotlin进行开发 Kotlin教程推荐 官网文档,黑马教程,《Kotlin for android developers》中文版翻译 相关代码已经上传到Github的KotlinPractice文件夹下了 创建项目: 在创建项目中勾选kolin支持后直接下一步即可 勾选kotlin支持 创建完项目后我们发现主类已经是使用了kotlin代码了,我们去project的build.gradle目录下可以看到 ext.kotlin_version = '1.1.51' kotlin //版本号 dependencies { classpath 'com.android.tools.build:gradle:3.0.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"//依赖 } 以及module下build.gradle的: apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' 实际上这就是我们刚才勾选kotlin后给我们自动生成的,如果我们想要在现有Java代码项目中使用kotlin,那么我们就需要手动的去添加这些依赖,或者使用方便的java代码转kotlin来进行配置,我们看到MainActivity默认已经是kotlin类了 /** * : AppCompatActivity() * :类名,表示继承于AppCompatActivity类 */ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } 为TextView控件赋值: 我们在布局从添加一个TextView,id命名为text_01 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.administrator.kotlin.MainActivity"> <TextView android:id="@+id/txt_01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试文本" /> </LinearLayout> 回到Activity,在activity的导包中添加这一行 import kotlinx.android.synthetic.main.activity_main.* 它的作用现在只要知道添加了这一行后我们就不需要再findViewById就可以了,activity_main的意思是Activity布局的包名。 import kotlinx.android.synthetic.main.activity_main.* /** * : AppCompatActivity() :类名,表示继承与什么类 */ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 为TextView设置值,koltin的语句后面是不需要;的,但是如果你加上也不会报错的 txt_01.setText("你好,世界") } } 运行程序,确实和我们想要的是一样的 设置按钮点击事件 我们再为布局添加3个button按钮 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.administrator.kotlin.MainActivity"> <TextView android:id="@+id/txt_01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试文本" /> <Button android:id="@+id/btn_01" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮1" /> <Button android:id="@+id/btn_02" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮2" /> <Button android:id="@+id/btn_03" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮3" /> </LinearLayout> 回到Activity,让MainActivity类继承于View.OnClickListener接口,我们可以看到koltin继承接口是使用,号进行的,如果我们想要继承多个接口,只需要使用多个,分隔开来就行了 /** * : AppCompatActivity() :类名,表示继承于什么类 * ,View.OnClickListener, View.OnLongClickListener 表示继承于 View.OnClickListener 点击事件接口, View.OnLongClickListener 长按事件接口 */ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClickListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 为TextView设置值,koltin的语句后面是不需要;的,但是如果你加上也不会报错的 txt_01.setText("你好,世界") } /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { } /** * 重写OnLongClickListener接口的onLongClick方法 */ override fun onLongClick(p0: View?): Boolean { return false } } 然后就是我们熟悉的在点击事件里面使用switch找到对应控件的id了,只是在kotlin里面是使用when /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { when (p0!!.id) { R.id.btn_01 -> { Toast.makeText(this, "按钮1", Toast.LENGTH_LONG).show() } R.id.btn_02 -> { Toast.makeText(this, "按钮2", Toast.LENGTH_LONG).show() } R.id.btn_03 -> { Toast.makeText(this, "按钮3", Toast.LENGTH_LONG).show() } } } 最后要注意,虽然我们通过import kotlinx.android.synthetic.main.activity_main.*使得不需要写控件的fndId,但是我们仍然是要写setOnClickListener(this)控件点击回调监听的 完整代码: import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.Toast import kotlinx.android.synthetic.main.activity_main.* /** * : AppCompatActivity() :类名,表示继承与什么类 */ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClickListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 为TextView设置值,koltin的语句后面是不需要;的,但是如果你加上也不会报错的 txt_01.setText("你好,世界") // 设置控件的回调监听 init() } /** * 设置控件的回调监听 */ private fun init() { btn_01.setOnClickListener(this) btn_02.setOnClickListener(this) btn_03.setOnClickListener(this) } /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { when (p0!!.id) { R.id.btn_01 -> { Toast.makeText(this, "按钮1", Toast.LENGTH_LONG).show() } R.id.btn_02 -> { Toast.makeText(this, "按钮2", Toast.LENGTH_LONG).show() } R.id.btn_03 -> { Toast.makeText(this, "按钮3", Toast.LENGTH_LONG).show() } } } /** * 重写OnLongClickListener接口的onLongClick方法 */ override fun onLongClick(p0: View?): Boolean { return false } } 运行程序点击按钮后,出现了我们想要的吐司 实现网络请求 开始之前我们先在module下配置anko依赖,这是为了等下线程调度用的 module: dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' // kotlin插件anko implementation "org.jetbrains.anko:anko-common:0.10.4" } 然后实现我们的network()请求网络方法,最后不要忘了在AndroidManifest.xml下添加网络权限 <uses-permission android:name="android.permission.INTERNET" /> /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { when (p0!!.id) { R.id.btn_01 -> { // 只进行网络请求 network(); } R.id.btn_02 -> { // 进行网路请求,并且进行json数据解析 Toast.makeText(this, "按钮2", Toast.LENGTH_LONG).show() } R.id.btn_03 -> { Toast.makeText(this, "按钮3", Toast.LENGTH_LONG).show() } } } /** * 网络请求 */ private fun network() { // 声明要请求的网址,在kotlin中,var能声明一切类型,而后面的:String其实是可以不加的 var string: String = "http://www.wanandroid.com/tools/mockapi/2872/k1" // 作用类似java在子线程中进行网络请求,但是async在kotlin中叫做协程 async() { val fore = URL(string).readText() Log.d("tonjies", fore) } } 观察日志,我们可以看到确实已经获取了Json数据 这里写图片描述 Json数据解析 接下来我们进行json数据的解析,首先添加gson解析依赖 // goso解析 compile "com.google.code.gson:gson:2.4" 我们创建bean实体类包,在包下创建解析实体类Student,我们不需要像Java那样去生成get和set对象,因为这kotlin已经帮我们生成好啦! /** * Created by 舍长 on 2018/4/28. * 描述: 数据请求实体类 */ class Student { var name:String?=null var age:String?=null } 在按钮2的点击事件里面写一个gson方法,在gson方法里将网络请求到的数据转换成实体类,并且回到UI线程,显示在文字控件上 /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { when (p0!!.id) { R.id.btn_01 -> { // 只进行网络请求 network(); } R.id.btn_02 -> { // 进行网路请求,并且进行json数据解析 Toast.makeText(this, "按钮2", Toast.LENGTH_LONG).show() gson(); } R.id.btn_03 -> { Toast.makeText(this, "按钮3", Toast.LENGTH_LONG).show() } } } /** * 网络请求并使用gson解析数据 */ private fun gson() { // 声明要请求的网址,在kotlin中,var能声明一切类型,而后面的:String其实是可以不加的 var string: String = "http://www.wanandroid.com/tools/mockapi/2872/student" // 作用类似java在子线程中进行网络请求,但是async在kotlin中叫做协程 async() { val fore = URL(string).readText() var fromJson: Student = Gson().fromJson(fore, Student::class.java) // 回到UI线程中去更新数据,这里的${属性名}是字符串模板,作用于Java的+属性名+相同 uiThread { txt_01.setText("学生的名字是${fromJson.name},年龄是${fromJson.age}") } } } 运行程序,点击按钮二,可以看到文字确实变成了我们想要的json数据:学习的名字是tonjies,年龄是18 这一小节的完整代码: 布局文件activity_main: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.administrator.kotlin.MainActivity"> <TextView android:id="@+id/txt_01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试文本" /> <Button android:id="@+id/btn_01" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮1" /> <Button android:id="@+id/btn_02" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮2" /> <Button android:id="@+id/btn_03" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮3" /> </LinearLayout> MainActivity package com.example.administrator.kotlin import android.icu.lang.UCharacter.GraphemeClusterBreak.L import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.util.Log import android.view.View import android.widget.Toast import com.example.administrator.kotlin.R.id.async import com.example.administrator.kotlin.bean.Student import com.google.gson.Gson import kotlinx.android.synthetic.main.activity_main.* import java.net.URL import org.jetbrains.anko.custom.async import org.jetbrains.anko.uiThread /** * : AppCompatActivity() :类名,表示继承与什么类 */ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClickListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 为TextView设置值,koltin的语句后面是不需要;的,但是如果你加上也不会报错的 txt_01.setText("你好,世界") // 设置控件的回调监听 init() } /** * 设置控件的回调监听 */ private fun init() { btn_01.setOnClickListener(this) btn_02.setOnClickListener(this) btn_03.setOnClickListener(this) } /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { when (p0!!.id) { R.id.btn_01 -> { // 只进行网络请求 network(); } R.id.btn_02 -> { // 进行网路请求,并且进行json数据解析 Toast.makeText(this, "按钮2", Toast.LENGTH_LONG).show() gson(); } R.id.btn_03 -> { Toast.makeText(this, "按钮3", Toast.LENGTH_LONG).show() } } } /** * 网络请求并使用gson解析数据 */ private fun gson() { // 声明要请求的网址,在kotlin中,var能声明一切类型,而后面的:String其实是可以不加的 var string: String = "http://www.wanandroid.com/tools/mockapi/2872/student" // 作用类似java在子线程中进行网络请求,但是async在kotlin中叫做协程 async() { val fore = URL(string).readText() var fromJson: Student = Gson().fromJson(fore, Student::class.java) // 回到UI线程中去更新数据,这里的${属性名}是字符串模板,作用于Java的+属性名+相同 uiThread { txt_01.setText("学生的名字是${fromJson.name},年龄是${fromJson.age}") } } } /** * 网络请求 */ private fun network() { // 声明要请求的网址,在kotlin中,var能声明一切类型,而后面的:String其实是可以不加的 var string: String = "http://www.wanandroid.com/tools/mockapi/2872/student" // 作用类似java在子线程中进行网络请求,但是async在kotlin中叫做协程 async() { val fore = URL(string).readText() Log.d("tonjies", fore) } } /** * 重写OnLongClickListener接口的onLongClick方法 */ override fun onLongClick(p0: View?): Boolean { return false } } 好了,这一小节就到这里啦!在学习的过程中,参考开源项目和巧妙使用Java代码转kotlin的快捷键是挺有用的

资源下载

更多资源
Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

Apache Tomcat7、8、9(Java Web服务器)

Apache Tomcat7、8、9(Java Web服务器)

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。

Eclipse(集成开发环境)

Eclipse(集成开发环境)

Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。

Java Development Kit(Java开发工具)

Java Development Kit(Java开发工具)

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。