2020

Hi,虽然今天吃了一颗糖,其实也没啥庆祝的,一个后端的假的程序员,花了一下午弄的博客,简洁的很啊。

-开始前的准备

系统环境:在Windows上测试的,Django版本是1.6,python 2.7.13

1
<!-- more -->

1.创建工程

1
django-admin.py startproject yoursitename

工程文件夹下三个重要的文件

manage.py —– Django项目里面的工具,通过它可以调用django shell和数据库等。

settings.py —- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。

urls.py —– 负责把URL模式映射到应用程序。(后两个文件在工程文件夹的同名文件夹内)

2.运行服务

在工程文件夹下,也就是manage.py所在文件夹。

1
python manage.py runserver

然后打开浏览器,访问http://127.0.0.1:8000即可看到运行状态。

3.创建blog应用

1
python manage.py startapp blog # 这也是在工程文件夹下

在工程文件夹下会生成blog文件夹,里面生成:

1
__init__.py, admin.py, models.py, test.py, views.py # 5个文件

4.编辑blog文件夹下的models.py

1
2
3
4
5
6
7
8
9
from django.db import models
# Create your models here.
class BlogsPost(models.Model):
''' 创建一个BlogsPost类,继承django.db.models.Model父类'''
title = models.CharField(max_length = 150)
body = models.TextField()
timestamp = models.DateTimeField()

5.创建数据库

python中自带SQLite数据库,所以无需修改

如果使用Mysql数据库需要修改工程文件夹下同名文件夹的settings.py

1
2
3
4
5
6
7
8
9
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'xblog', ## 数据库名称
'USER': 'root',
'PASSWORD': 'password', ## 安装 mysql 数据库时,输入的 root 用户的密码
'HOST': '127.0.0.1',
}
}

然后执行创建命令:

1
python manage.py syncdb

创建过程中会出现选择:输入yes,然后是超级用户名,邮箱,密码(自定义,不是邮箱密码)用于登录管理系统。

6.添加blog应用到settings.py

1
2
3
4
5
6
7
8
9
10
11
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog', # 只是添加这一项
)

修改跟settings.py同文件夹的urls.py

原文件:

1
2
3
4
5
6
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'mysite.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
# url(r'^admin/', include(admin.site.urls)),
)

修改成:

1
2
3
4
5
6
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'mysite.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
)

7.将创建数据添加到后台

编辑blog文件夹下的models.py

1
2
3
4
5
6
7
8
9
10
from django.db import models
from django.contrib import admin
# Create your models here.
class BlogsPost(models.Model):
title = models.CharField(max_length = 150)
body = models.TextField()
timestamp = models.DateTimeField()
admin.site.register(BlogsPost) # 添加这一行

再次初始化数据库

1
2
python manage.py syncdb
python manage.py runserver # 访问后台,http://127.0.0.1:8000/admin/ 输入用户名,密码,登录

然后随意创建post,后面会用于显示。

8.创建模板

在blog文件夹下新建一个templates文件夹,然后在该文件夹下新建一个archive.html文件

1
2
3
4
5
{% for post in posts %}
<h2>{{ post.title }}</h2>
<p>{{ post.timestamp }}</p>
<p>{{ post.body }}</p>
{% endfor%}

然后设置模板路径,修改settings.py

在最后面添加

1
2
3
4
#template
TEMPLATE_DIRS=(
'/home/fnngj/djpy/mysite/blog/templates'
)

在blog文件夹下的views.py中创建试图函数

1
2
3
4
5
6
7
8
9
10
from django.template import loader,Context
from django.http import HttpResponse
from blog.models import BlogsPost
# Create your views here.
def archive(request):
posts = BlogsPost.objects.all()
t = loader.get_template("archive.html")
c = Context({'posts':posts})
return HttpResponse(t.render(c))

posts = BlogPost.objects.all() :获取数据库里面所拥有BlogPost对象

t = loader.get_template(“archive.html”):加载模板

c = Context({‘posts’:posts}):模板的渲染的数据是有一个字典类的对象Context提供,这里的是一对键值对。

9.创建blog的url模式

原文件:

1
2
3
4
5
6
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'mysite.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
)

修改后:

1
2
3
4
5
6
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'mysite.views.home', name='home'),
url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
)

10.blog的urls

在blog文件夹下新建一个urls.py

1
2
3
4
5
6
from django.conf.urls import *
from blog.views import archive
urlpatterns = patterns('',
url(r'^$',archive),
)

最后可以选择给博客添加样式

在blog/templates/创建一个html文件,然后让archive.html引用就完成了。

1
2
3
4
{% extends "united.html" %}
{% block content %}
archive.html内容
{% endblock %}

然后找一个美化的样式写到united.html中就行了。

Python爬虫遇到的多线程的坑

先谈谈我的认识

  • 其实还没弄懂并发并行,然后依照自己的想法去做,别人是用多线程下载网页的,我爬的是网易云音乐的评论数,而用到多线程去解析,做了三个脚本:

  • 第一个是只用threading的方法和类去弄。

  • 第二个是比第一个多了Queue模块。

  • 第三个想法行不通(看到别人提到可以用map函数提高效率,但结果是脚本没有运行成功,一直卡着)。

  • 虽然想到要用多进程去弄,但还没看明白,所以算了。

    讲给未来的自己吧

  • 多线程的知识:

  • 线程模块

    • Python通过两个标准库thread和threading提供对线程的支持。thread提供了低级别的、原始的线程以及一个简单的锁。
    • thread 模块提供的其他方法:
    • threading.currentThread(): 返回当前的线程变量。
    • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
    • 除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
    • run(): 用以表示线程活动的方法。
    • start(): 启动线程活动。
    • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
    • isAlive(): 返回线程是否活动的。
    • getName(): 返回线程名。
    • setName(): 设置线程名。

重要的代码块

一个最基本的线程运用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python
# encoding: utf-8
import threading
class ThreadingTest(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
# you function code run here
# 或者在定义一个函数然后,实例函数写到run函数里面
for i in range(num):
# num 是想要执行多少的线程
t = ThreadingTest()
t.start()
t.join()

但是上面没有Queue模块,Queue模块是提供队列操作的模块,对于多线程而言,访问共享变量时,队列queue是线程安全的。So 来一个!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env python
# encoding: utf-8
import threading
import Queue
class ThreadingTest(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
# queue需要写在循环里面
while True:
# 将需要共享的内容读取到queue里面
somenthing = self.queue.get()
# you function code run here
# 当线程(不是函数)运行得到结果后,queue队列任务结束,并进行下一循环
self.queue.task_done()
# 或者在定义一个函数然后,实例函数写到run函数里面
# 用循环将共享的内容读取到queue队列
def QueueRun():
queue = Queue.Queue()
for i in something:
# 或 for i in range(num):
queue.put(i)
# 运行线程
for i in range(num):
t = ThreadingTest()
t.setDaemon(True) # 设置子线程不跟随主线程结束而结束
t.start()
queue.join()

多线程只适用与IO密集型任务,还有讲到并发和并行:

  • 并发性(concurrency),又称共行性,是指能处理多个同时性活动的能力,并发事件之间不一定要同一时刻发生。

  • 并行性(parallelism)是指同时发生的两个并发事件,具有并发的含义,而并发则不一定并行。

##还有就这样吧

float图来了,18号想弄的,非得拖到今天。

先前想到用svg格式嵌入的,但写在markdown里面没法弄,以后多找找些js工具来弄图表,

虽然博客是静态的,但只写字太单调了,加点东西装饰,先弄第一个吧



按钮没弄是因为css没学,现学现卖也没那能力。暂且就这样吧。

1 照例安装:先安装virtualenv, 再安装Django

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo pip install virtualenv
'''然后新建一个文件夹,转到该文件夹运行,
新建一个文件夹的目的是将要隔离运行的python版本和
django工程在同一文件夹下,方便管理,当然也不必这么做。
'''
virualenv project # 在这里写的例子是project,文件夹名称自定义
source project/bin/activate # 运行隔离环境,然后用隔离环境的python工具pip下载django
pip install django # 可以指定任一版本
django-admin --version # 查看Django的版本
deactivate # 关闭隔离环境

2 建立项目(或工程):

1
2
3
django-admin startproject website # 在隔离环境下运行,名称自定义
python manage.py runserver # 启动服务,然后用浏览器打开127.0.0.1:8000,可以改ip和端口

3 创建app(相当与网站的内容页)

建立工程后用浏览器打开127.0.0.1:8000,就可以看到服务启动成功的页面。接下来建立一个 web app

1
2
# 进入website文件夹运行如下代码
python manage.py startapp music # 这里用music作例子,

在创建工程和应用之后未作任何改动时,文件目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
website
|----website
| |----__init__.py
"""__init__.py文件需要使Python将目录视为包含的包;
这样做可以防止具有公共名称的目录(如字符串)无意中隐藏模块搜索路径上稍后发生的有效模块。
在最简单的情况下,__init__.py可以是一个空文件,
但也可以执行包的初始化代码或设置__all__变量,稍后再描述。
"""
| |----settings.py # 网站的功能设置
| |----urls.py # 主要的apps地址链接
| |----wsgi.py # 用于你的项目的与WSGI兼容的Web服务器入口
|----music
| |----__init__.py # 同上
| |----admin.py # 管理应用
| |----apps.py # 跟新建应用有关,管理子链接
| |----models.py # 用一个 Python 类来描述数据表,模型(model), 可以用python代替SQL
| |----tests.py # 做个人测试
| |----views.py # 主要编写视图函数,返回html页面或者404页面,
|----db.sqlite3 # 数据库文件
|----manage.py # 可以创建应用,用户,打开shell,数据库同步,启动关闭服务等

4 修改app(丰富应用,添加各种功能)

写一个简单的music主页面

编辑views.py, 清空文件内容,并编写如下代码:

1
2
3
4
from django.http import HttpResponse
def index(request):
return HttpResponse("<h1>a string content.")

要调用views,我们需要将其映射到URL, 在music文件夹下新建urls.py, 添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
from django.conf.urls import url
from . import views
# 第二行注释,从同应用中引入其他模块
app_name = 'music'
urlpatterns = [
url(r'^$', views.index, name='index'), # 在views.py中添加index函数,链接后执行该函数
url(r'^(?P<album_id>[0-9]+)/$', views.detail, name='detail'), # 获取多个id进行多个分页,
]

编辑website/website/urls.py, 文件内初始一个urlpattern列表,用来链接用户指定的apps或新建一个链接

include()函数允许引用其他URLconfs。 请注意,include()函数的正则表达式不具有$(字符串匹配字符),而是尾部斜线。 每当Django遇到include()时,它将删除与此相匹配的URL的任何部分,并将剩余的字符串发送到包含的URLconf进行进一步处理。(translate from python.usyiyi.cn)

1
2
3
4
5
6
7
8
9
10
11
12
# 原urlpatterns:
urlpatterns = [url(r'^admin/', admin.site.urls),]
# 新建一个app后,添加一个app链接:
# 在urls.py首行修改(添加 include ):
from django.conf.urls import include, url
urlpatterns = [
'''在music应用建一个urls.py管理music更多的子链接'''
url(r'^music/', include('music.urls')),
url(r'^admin/', admin.site.urls),
]

在INSTALLED_APPS列表中添加新建的music应用(每次添加一个app记得加上逗号):

1
2
# 在website/website/settings.py 中找到INSTALLED_APPS列表,添加music
'music.apps.MusicConfig',

设置数据库(本例就用简单的sqlite3)

1
2
3
4
5
'''
到website目录下用python运行manage.py用于将应用的内容与数据库同步,
一般建立一个app后都要执行迁移指令(migrate),
'''
python manage.py migrate # 迁移指令,使之与数据库连接和同步

##为应用添加任何内容

编辑models.py 新建两个类,内容来自(thenewboston on youtube):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
'''
在这里,用歌曲和专辑两个类作内容,
在Song类中有个ForeignKey()函数,该函数会分配一个id给Album
类似于数据库table中每一项的id
作者写的教程用于每张专辑分配一个链接,例子:
http://127.0.0.1:8000/music/1
http://127.0.0.1:8000/music/2
http://127.0.0.1:8000/music/3
分别对应三张专辑,每张专辑一个html页面
on_delete参数是指每当删除专辑时,相关联的歌曲也会被删除
'''
from django.db import models
class Album(models.Model):
artist = models.CharField(max_length=250)
album_title = models.CharField(max_length=500)
genre = models.CharField(max_length=100)
album_logo = models.CharField(max_length=1000)
def __str__(self):
'''函数作用是返回对象内容'''
return self.album_title # 前面四个内容任意
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(max_length=10)
song_title = models.CharField(max_length=250)

register应用内容:

1
2
3
4
5
# 在music/admin.py 中添加如下代码
from .models import Album, Song
admin.site.register(Album)
admin.site.register(Song)

在website目录下执行如下指令

1
2
3
python manage.py makemigrations music # 个人理解是将两个类内容转换成数据库table的内容
python manage.py migrate # 迁移指令,使之与数据库连接和同步

因为在models.py中只是定义类而已,并没有创建实例和添加内容,而添加内容是很简单的所以不多以详解首先要在virtualenv环境下(因为我安装的django是在隔离环境,所以编写django都要开启virtualenv)在website目录下运行,

1
2
3
4
5
6
7
python manage.py shell
# 运行后会进入一个python命令行的解释器
# 引入包
from music.models import Album, Song # 写的什么类就导入什么类
# 然后创建实例,将类中的变量都赋值,比如:
a = Album(artist="abcd",......)
a.save() # 保存内容

现在打开http://127.0.0.1:8000/music/ 还是显示 a string content.一段文字,要添加什么内容就写在models.py里面,要引用页面html之类的就写在views.py里面

重构music页面,添加404页面

重新编写views.py,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.http import Http404
from django.shortcuts import render, get_object_or_404
from django.template import loader
from .models import Album
def index(request):
all_albums = Album.objects.all()
context = {'all_albums': all_albums}
return render(request, 'music/index.html', context)
def detail(request, album_id):
album = get_object_or_404(Album, pk=album_id)
return rander(request, 'music/detail.html', {'album': album})

编写两个函数,index函数用于music页面内容, detail函数用于http://127.0.0.1:8000/music/album_id/ (album_id是数字,用每张专辑album的id作分页)分页内容,虽然现在写好了,但是还是无法打开music页面,因为没有编写页面的html。

使用templates模板

在music文件夹下创建一个新的文件夹templates,然后在里面再建一个music(注意是music)文件夹,然后在 templates/music 下建一个index.html文件,并编写如下代码:

1
2
3
4
5
6
7
8
9
{% if all_albums %}
<ul>
{% for album in all_albums %}
<li><a href="{% url 'music:detail' album.id %}/">{{ album.album_title }}</a></li>
{% endfor %}
</ul>
{% else %}
<h3>No content</h3>
{% endif %}

再建一个detail.html:

1
2
3
4
5
6
7
8
9
<img src="{{ album.album_logo }}">
<h1>{{ album.album_title }}</h1>
<h2>{{ artist }}</h2>
<ul>
{% for song in album.song_set.all %}
<li>{{ song.song_title }} - {{ song.file_type }} </li>
{% endfor %}
</ul>

重写view.py

让view更简单

1
2
3
4
5
6
7
8
9
10
11
12
from django.views import generic
from .models import Album
class IndexView(generic.ListView):
template_name = 'music/index.html'
context_object_name = 'all_albums' # 如果写这行就不用更改indx.html
def get_queryset(self):
return Album.objects.all()
class DetailView(generic.DetailView):
model = Album
template_name = 'music/detail.html'

更改urls.py

1
2
3
4
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'), # 这是更改之后
url(r'^(?P<album_id>[0-9]+)/$', views.DetailView.as_view(), name='detail'), # 同上
]

修改index.html

1
2
3
4
5
6
7
8
9
{% if all_albums %}
<ul>
{% for album in object_list %} /* 改动在这里 */
<li><a href="{% url 'music:detail' album.id %}/">{{ album.album_title }}</a></li>
{% endfor %}
</ul>
{% else %}
<h3>No content</h3>
{% endif %}

5 创建管理用户

1
2
3
4
5
6
python manage.py createsuperuser
# 虽然创建成功了,但我们创建的应用还未在管理页面显示
# 编辑app_name的admin.py文件,添加如下代码
from .models import Album
admin.site.register(Album)

6 网页前端样式模板

在music文件夹下新建一个static文件夹,然后在static下再建一个music文件夹,然后在music文件夹下新建一个style.css文件,样式随意,但是在index.html中要引用style.css的话,要在index.html加个语句

1
2
3
{% load staticfiles %}
<!-- 下面的语句是个例子,href后面用{% static '路径' %}-->
<link rel="stylesheet" type="type/css" href="{% static 'music/style.css' %}"

在考虑到每个网页用到相同样式的风格,所以将样式或js内容写在一个base.html里面(在music/templates/music文件夹下新建一个base.html),然后在用index.html扩展

1
2
3
4
5
6
7
8
9
10
<!-- 在base.html 的body标签写两个语句-->
{% block body %}
{% endblock %}
<!-- 在index.html要扩展base.html的内容要写一个语句-->
{% extends 'music/base.html' %}
<!-- 要扩展body部分还要写如下语句 -->
{% block body %}
<!-- 在这body中间写index.html的body部分-->
{% endblock %}

即index.html中的内容如下(例子):

1
2
3
4
5
6
7
8
9
10
11
12
13
{% extends 'music/base.html' %}
{% block body %}
{% if all_albums %}
<ul>
{% for album in all_albums %}
<li><a href="{% url 'music:detail' album.id %}/">{{ album.album_title }}</a></li>
{% endfor %}
</ul>
{% else %}
<h3>No content</h3>
{% endif %}
{% endblock %}

1 ag 代码搜索工具

1
$ sudo apt-get install silversearcher-ag

编辑器集成 vim 您可以通过将以下行添加到~/.vimrc:[ack.vim][]来使用Ag

1
let g:ackprg = 'ag --nogroup --nocolor --column'

2 autojump 一个更快的方式来导航你的文件系统

1
$ sudo apt-get install autojump

oh-my-zsh配置,编辑~/.zshrc,然后source ~/.zshrc 命令使配置文件生效

1
2
plugins+=(autojump)
[[ -s ~/.autojump/etc/profile.d/autojump.sh ]] && . ~/.autojump/etc/profile.d/autojump.sh

3 axel 多线程下载工具,下载文件时可以替代curl、wget

1
$ sudo apt-get install axel

4 bpkg 一个bash包管理器

1
$ curl -sLo- http://get.bpkg.sh | bash

源码安装

1
2
3
$ git clone https://github.com/bpkg/bpkg.git
$ cd bpkg
$ ./setup.sh install

5 cloc 计算代码行数

1
$ sudo apt-get install cloc # Debian, Ubuntu

6 figlet 不寻常的创建大字符的程序

1
2
3
# 解压进入目录
figlet$ make
figlet$ make install

7 fzf 一个通用的命令行模糊查找器

使用git

1
2
$ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
$ ~/.fzf/install

vim 插件集成

1
Plugin 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }

8 screenfetch Bash截图信息工具

1
$ sudo apt-get install screenfetch

9 thefuck 纠正您的以前的控制台命令

通过pip安装

1
2
3
$ sudo apt update
$ sudo apt install python3-dev python3-pip
$ sudo pip3 install thefuck

10 mycli MySQL的命令行客户端,可以执行自动完成和语法高亮显示

1
2
3
$ pip install -U mycli
# 或者
$ sudo apt-get install mycli # Only on debian or ubuntu

11 htop 提供更美观、更方便的进程监控工具

1
$ sudo apt-get install htop

12 lolcat 在 Linux 终端中为文本添加彩虹般的色彩

1
2
3
4
5
$ sudo apt-get install ruby
$ wget https://github.com/busyloop/lolcat/archive/master.zip
$ unzip master.zip
$ cd lolcat-master/bin
$ gem install lolcat

13 cowsay 可配置的正在思考或说话的奶牛

1
$ npm install -g cowsay

14 tldr 简化和社区驱动的手册页的集合

1
$ sudo npm install -g tldr

15 pm2 PM2是具有内置负载平衡器的Node.js应用程序的生产过程管理器

1
$ npm install pm2 -g

16 ls++ 上色版ls

1
2
3
4
5
6
$ cpan Term::ExtendedColor
$ git clone git://github.com/trapd00r/ls--.git
$ cd ls--
$ perl Makefile.PL
$ make && su -c 'make install' # 若权限禁止,则使用root模式执行
$ cp ls++.conf $HOME/.ls++.conf

17 scrot 屏幕截图

1
$ sudo apt-get install scrot

18 font manager 字体管理器(带界面)

1
$ sudo apt-get install font-manager

19 trash cli 将文件和文件夹移动到垃圾箱

1
$ npm install --global trash-cli

20 alder 递归目录列表程序,支持文件大小报告和模式匹配

1
$ npm install -g @aweary/alder

21 bd-zsh 快速进入父目录

这里写的是,安装zsh插件(不单独安装)

1
2
3
$ mkdir -p $HOME/.zsh/plugins/bd
$ curl https://raw.githubusercontent.com/Tarrasch/zsh-bd/master/bd.zsh > $HOME/.zsh/plugins/bd/bd.zsh
$ print -- "\n# zsh-bd\n. \$HOME/.zsh/plugins/bd/bd.zsh" >> $HOME/.zshrc

22 tmux 多终端复用

1
$ sudo apt-get install tmux

教程

#开发一个简单的Toast应用

##1 下载 Android Studio 并安装

1
进入官网 https://developer.android.com/studio/ 下载

一路确认安装后,打开 Android Studio 新建项目, 到选择Activity布局时,选择空白布局。

完成选择后等待下载gradle, 进入工程界面后,在activity_main.xml 的设计那里选择主题才会出现布局效果。

2 编写一个Toast 应用

###1添加按钮

在布局界面(activity_main.xml)Design, 拖动一个按钮到主界面上,点击上方的魔棒按钮(Infer Constraints)。
  

2 编写按钮事件

找到工程的MainActivity.java 写一个按钮实例,然后再写一个按钮事件,按钮事件监听单击显示Toast。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 此处省略包名
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
Button bt1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt1 = findViewById(R.id.button);
bt1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "你好,安卓", Toast.LENGTH_LONG).show();
}
});
}
}

完成