A simple example with Socket

A simple example with Socket

Concepts:

  1. socket:

  2. thread

  3. I/O stream

    Output stream -> Sending buffer queue (SendQ)-> Network

    Network-> Receiving buffer queue (RecvQ)->Input Stream

Example:

Write a net program, include a server and client, client will send a string to the server, and server should print the string to the terminal, and return the length of string to the client, and finally the client should print the length sent from server. You should do it in TCP and UDP way.

如何使用Android Studio自带的http解析器制作简单的静态网页爬虫APP

1.使用Andriod Studio的http解析器

​ Android Studio 在高版本后自带了Jsoup解析器,要使用Jsoup解析器,首先要在

scripts:build.gradle:dependencies```中加入```implementation 'org.jsoup:jsoup:1.9.2'``` ,其后,在class里可以使用```import org.jsoup.Jsoup;``` 导入。Android Studio 默认关闭了APP的网络访问,所以要在```manifests:AndroidManifest.xml```
1
2
3
4

中加入两行代码

```<usespermissionandroid:name="android.permission.INTERNET" />
android:name
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- more --> 
#### 2.获取以及解析静态网页

##### (1)获取网页

首先创建一个```private Document getDocument(Stirng url)``` ,以Math1310的课程网页为例,令```String url = "http://math.yorku.ca/~lishu3/math1310.html" ``` 此时,构建一个简单的 try catch模块。

```java
try{
return Jsoup.connect(url).timeout(5000).get();
}catch (IOException e){
e.printStackTrace();
}

需要注意的是,Jsoup.connect后需要加get()才能取得解析结果,而timeout则要加在两者之间。

这个function 返回的Document格式是Jsoup独有的格式。所以需要导入import org.jsoup.nodes.Document才不会报错。

(2)解析网页

首先分析网页结构

需要抓取的结构通过分析我们可以看出位于<ul></ul>内 , 此时令Document doc = getDocument(url) 添加Jsoup选择器Element ul = doc.select("ul").first() 这段代码的意思是从整个被解析出的html文件中选取第一个ul作为Element。需要注意的是,这个网页中含有两个<ul>element 而如果不使用.first()去选择第一个ul作为element则必须使用Elements作为数据容器。

此时我们已经选择第一个<ul>作为目标,使用 Elements elements= ul.select("li");选取ul内所有的li作为目标。 迭代循环并输出每一个element的内容。

3.多线程更新View

在Android中,原始的主线程不允许参与与网络有关的模块运行,因为非常容易造成卡顿,那么要运行刚刚的程序,必须开启一个新的线程。

1
2
3
4
5
new Thread(){
@Override
public void run(){
}
}.start();

而如果要更新View,则必须使用Handler才能进行

1
2
3
Handler  handler=new Handler();
以及
handler.post();

但是如果直接使用两者来setContentoftextView就会遇到一个问题:报错

1
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

翻译过来就是,只有创建view的那个线程(这里是主线程)才能跟新view,而我们创建的子线程new thread如果直接运行setContentOfTextView则会报错。

这里就要使用这种方法才能避开这个问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
new Thread(){
@Override
public void run(){
GetInfo info=new GetInfo();
final String output=info.getInfo("http://math.yorku.ca/~lishu3/math1310.html");
handler.post(new Runnable() {
@Override
public void run() {
setContentOftextView(R.id.outputInfo,output);
}
});
}

}.start();

通过在handler.post里再创建一个新的Runnable event在里面跑setContentofTextView就可以成功的避开这个问题了。

4.GGWP其他一些小的经验

(1)在设置textView的时候,如果加一行textView.setMovementMethod(ScrollingMovementMethod.getInstance());

则textview可以触屏滚动

(2)在制作这个简单的爬虫APP的时候,我并没有考虑脱离网络的情况,实际上,如果不加入判断手机是否有网络的代码,则这个APP会直接崩溃,推荐在之后的APP里加入判断手机是否有Wifi或者是数据的功能。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×