1.httpUrlConnection写源代码查看器
HttpUrlConnection:用于发送或接收数据
1、manifest文件添加访问网络权限
**2、读取输入流的工具类StreamTool **
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class StreamTool {
public static String readStream(InputStream inputStream) throws IOException {
//定义一个内存输出流
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
int len=-1;
byte[] buffer=new byte[1024];
while ((len=inputStream.read(buffer))!=-1){
byteArrayOutputStream.write(buffer,0,len);
}
inputStream.close();
String content=new String(byteArrayOutputStream.toByteArray());
return content;
}
}
3、mainActivity类
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
private EditText edPath;
private Button gonet;
private TextView showInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edPath=findViewById(R.id.edPath);
gonet=findViewById(R.id.button);
showInfo=findViewById(R.id.tvresualt);
}
public void checkClick(View view){
//1、获取源码路径
String path=edPath.getText().toString().trim();
//2、创建url对象
try {
URL url=new URL(path);
//3、拿到HTTPURLConnection对象,用于发送或接收数据
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
//4、设置发送get请求
connection.setRequestMethod("GET");//get要求大写,默认是get
//5、设置请求的超市时间
connection.setConnectTimeout(5000);
//6、获取服务器返回的状态码
int code= connection.getResponseCode();
//7、判断状态码
if (code==200){
//8、获取服务器返回的数据,以流的形式返回的
InputStream inputstream= connection.getInputStream();
//9、把流里的数据展示到textView上以工具类的形式
String content=StreamTool.readStream(inputstream);
showInfo.setText(content);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.线程
只有主线程才能更新UI
耗时操作都在子线程
子线程逻辑单独设计一个类来实现
public void btnClick(View view){
//创建一个子线程
new Thread(){
@Override
public void run() {
try {
Thread.sleep(6000);
Log.d("TAG", "btnClick: "+Thread.currentThread());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
3.Handler线程的消息机制
- 子线程更新主线程更新不了,则找一个助手(Handler)来完成
- handler是用来发消息和处理消息的
- Looper的作用是去消息队列中取消息,交给handler来处理
- 只要做耗时操作,就自己开一个子线程,获取数据后想要更新ui就使用handler就可以了
handler使用步骤
- 1、在主线程定义个handler
private Handler mHandler=new Handler(){
};
- 2、重写handler里面的handmessage方法
private Handler mHandler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
//在主线程中更新UI
String content=(String)msg.obj;
Log.d("TAG", "handleMessage: "+content+" "+Thread.currentThread());
}
};
-3、拿着在主线程创建的handler对象去子线程发消息
hadler.senderMessage(msg)
-4、handMessage方法就会执行,在这个方法里面去更新ui
完整代码:
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
//在主线程中创建Handler对象
private Handler mHandler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
//在主线程中更新UI
String content=(String)msg.obj;
Log.d("TAG", "handleMessage: "+content+" "+Thread.currentThread());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("TAG", "onCreate: "+Thread.currentThread());
}
public void btnClick(View view){
//创建一个子线程
new Thread(){
@Override
public void run() {
try {
//子线程中创建Message对象并在对象中添加信息,并在子线程中发送消息
Message message=new Message();
message.obj="my message for send";
mHandler.sendMessage(message);//发了一条消息
Thread.sleep(6000);
Log.d("TAG", "btnClick: "+Thread.currentThread());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
打印:
2020-08-18 10:49:49.074 5417-5417/com.fengray.ex050 D/TAG: onCreate: Thread[main,5,main]
2020-08-18 10:49:51.978 5417-5417/com.fengray.ex050 D/TAG: handleMessage: my message for send Thread[main,5,main]
2020-08-18 10:49:57.978 5417-5458/com.fengray.ex050 D/TAG: btnClick: Thread[Thread-2,5,main]
4.Handler传递消息来创建一个简单的图片查看器
步骤
- 把流信息转换成bitmap对象
- 使用bitmapFactory.decodestrem(inputstream in)从流中获取图片
- manifest文件中加上网络访问权限
package com.fengray.ex051;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
private EditText inputText;
private Button mybtn;
private ImageView imageView;
//创建handler对象
private Handler myhanderl=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
//用一个位图对象来接收msg对象
Bitmap bitmap=(Bitmap)msg.obj;
//在主线程中更新UI
imageView.setImageBitmap(bitmap);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
inputText=findViewById(R.id.inputurl);
mybtn=findViewById(R.id.button);
imageView=findViewById(R.id.imageView);
}
public void doCheck(View view){
new Thread(){
@Override
public void run() {
//1、获取访问的路径
String urlstr=inputText.getText().toString().trim();
//2、创建url对象
try {
URL url=new URL(urlstr);
//3、获取HttpURLConnection对象
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
//4、设置请求方式
connection.setRequestMethod("GET");
//5、设置连接超时时间
connection.setConnectTimeout(5000);
//6、获取服务器返回的状态码
int code=connection.getResponseCode();
if (code==200){
//7、获取图片的数据
InputStream inputStream=connection.getInputStream();
//8、使用BitmapFactory工厂类将流转换成位图
Bitmap bitmap=BitmapFactory.decodeStream(inputStream);
//把图像显示到图形控件上,子线程不能更新主线程UI需要借助handler来发送消息
Message msg=Message.obtain();//静态方法形式返回msg对象,这个方法使用了线程池,比new方法效率高
msg.obj=bitmap;//将位图放入到message对象中去
myhanderl.sendMessage(msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
5.使用缓存图片来创建一个简单的图片查看器
package com.fengray.ex051;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
private EditText inputText;
private Button mybtn;
private ImageView imageView;
//创建handler对象
private Handler myhanderl=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
//用一个位图对象来接收msg对象
Bitmap bitmap=(Bitmap)msg.obj;
//在主线程中更新UI
imageView.setImageBitmap(bitmap);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
inputText=findViewById(R.id.inputurl);
mybtn=findViewById(R.id.button);
imageView=findViewById(R.id.imageView);
}
public void doCheck(View view){
new Thread(){
@Override
public void run() {
//7.1.1从缓存文件里创建一个缓存目录
File file=new File(getCacheDir(),"temp.jpg");
if (file.exists() && file.length()>0){
//使用缓存的图片
Log.d("TAG", "使用缓存图片");
Bitmap cacheBitmap=BitmapFactory.decodeFile(file.getAbsolutePath());
//将缓存图片显示到主线程UI上
Message msg=Message.obtain();
msg.obj=cacheBitmap;
myhanderl.sendMessage(msg);
}else{
//第一次访问
Log.d("TAG", "使用网络图片");
//1、获取访问的路径
String urlstr=inputText.getText().toString().trim();
//2、创建url对象
try {
URL url=new URL(urlstr);
//3、获取HttpURLConnection对象
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
//4、设置请求方式
connection.setRequestMethod("GET");
//5、设置连接超时时间
connection.setConnectTimeout(5000);
//6、获取服务器返回的状态码
int code=connection.getResponseCode();
if (code==200){
//7、获取图片的数据
InputStream inputStream=connection.getInputStream();
//7.1缓存图片
FileOutputStream fileOutputStream = new FileOutputStream(file);
int len=-1;
byte[] buffer=new byte[1024];//1kb
//循环写入到缓存文件中
while ((len=inputStream.read(buffer))!=-1){//读完了
fileOutputStream.write(buffer,0,len);
}
fileOutputStream.close();
inputStream.close();
//8、使用BitmapFactory工厂类将流转换成位图
Bitmap bitmap=BitmapFactory.decodeFile(file.getAbsolutePath());
//把图像显示到图形控件上,子线程不能更新主线程UI需要借助handler来发送消息
Message msg=Message.obtain();//静态方法形式返回msg对象,这个方法使用了线程池,比new方法效率高
msg.obj=bitmap;//将位图放入到message对象中去
myhanderl.sendMessage(msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
6.RunOnUIThread
runOnUIThread不管运行在主线程还是子线程上都会执行。实际上也是通过handler来完成的,但是谷歌已经封装好了
使用场景:
- 如果仅仅更新UI
- 有时候可以通过handler发消息,其消息可以携带数据
//8、使用BitmapFactory工厂类将流转换成位图
final Bitmap bitmap=BitmapFactory.decodeFile(file.getAbsolutePath());
//把图像显示到图形控件上,子线程不能更新主线程UI需要借助handler来发送消息
//使用runOnUIThread,直接在UI线程上添加动作
runOnUiThread(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
完整代码:
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
private EditText inputText;
private Button mybtn;
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
inputText=findViewById(R.id.inputurl);
mybtn=findViewById(R.id.button);
imageView=findViewById(R.id.imageView);
}
public void doCheck(View view){
new Thread(){
@Override
public void run() {
//7.1.1从缓存文件里创建一个缓存目录
File file=new File(getCacheDir(),"temp.jpg");
if (file.exists() && file.length()>0){
//使用缓存的图片
Log.d("TAG", "使用缓存图片");
final Bitmap cacheBitmap=BitmapFactory.decodeFile(file.getAbsolutePath());
//将缓存图片显示到主线程UI上
runOnUiThread(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(cacheBitmap);
}
});
}else{
//第一次访问
Log.d("TAG", "使用网络图片");
//1、获取访问的路径
String urlstr=inputText.getText().toString().trim();
//2、创建url对象
try {
URL url=new URL(urlstr);
//3、获取HttpURLConnection对象
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
//4、设置请求方式
connection.setRequestMethod("GET");
//5、设置连接超时时间
connection.setConnectTimeout(5000);
//6、获取服务器返回的状态码
int code=connection.getResponseCode();
if (code==200){
//7、获取图片的数据
InputStream inputStream=connection.getInputStream();
//7.1缓存图片
FileOutputStream fileOutputStream = new FileOutputStream(file);
int len=-1;
byte[] buffer=new byte[1024];//1kb
//循环写入到缓存文件中
while ((len=inputStream.read(buffer))!=-1){//读完了
fileOutputStream.write(buffer,0,len);
}
fileOutputStream.close();
inputStream.close();
//8、使用BitmapFactory工厂类将流转换成位图
final Bitmap bitmap=BitmapFactory.decodeFile(file.getAbsolutePath());
//把图像显示到图形控件上,子线程不能更新主线程UI需要借助handler来发送消息
//使用runOnUIThread,直接在UI线程上添加动作
runOnUiThread(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
7.常见消息API
handler
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//相当于一个定时器操作
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Log.d("TAG", "run: 演示延时处理");
}
}, 5000);
}
}
Timer
不能用于主线程UI的更新
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个定时器
Timer timer=new Timer();
//创建一个用来执行的任务
TimerTask task=new TimerTask() {
@Override
public void run() {
Log.d("TAG", "run: timer定时器执行的任务");
}
};
//2秒后执行一次
//timer.schedule(task,2000);//只执行一次
//三秒后每隔一秒执行一次
timer.schedule(task,3000,1000);
}
由于不能更新主线程UI可以结合runOnUIThread来进行主线程的UI更新
如下
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
private TextView mytext;
private int i=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mytext=findViewById(R.id.mytext);
//创建一个定时器
Timer timer=new Timer();
//创建一个用来执行的任务
TimerTask task=new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
i++;
mytext.setText(i+"");
}
});
}
};
//2秒后执行一次
//timer.schedule(task,2000);//只执行一次
//三秒后每隔一秒执行一次
timer.schedule(task,3000,1000);
}
}
8.一则新闻客户端案例
- 1、UI是美工在做
- 2、应用的传输数据,定义接口
- 3、xml的数据时服务器开发人员通过一定的技术手段返回的,对应android开发人员要会解析xml文件,并展现到控件上
文档结构
00创立服务器及相应目录下的news.xm文件
文件访问地址为:
http://192.168.1.64:8080/AndroidPhone/news.xml
1、news模型
package com.fengray.ex052;
public class News {
private String title;
private String description;
private String image;
private String type;
private String comment;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}
2、xml文档解析工具类
package com.fengray.ex052;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class XmlParserUtils {
public static List<News> parserXml(InputStream in){
List<News> newsLists=null;
News news=null;
//1、获取XML的解析器
XmlPullParser parser= Xml.newPullParser();
try {
//2、设置解析器的要解析的内容
parser.setInput(in,"utf-8");
//3、设置解析的事件类型
int type=parser.getEventType();
//4、不停地向下解析
while (type!=XmlPullParser.END_DOCUMENT){
// 具体判断一下解析的事开始节点还是结束节点
switch (type){
case XmlPullParser.START_TAG://解析开始节点
//具体判断一下解析的是哪个开始标签
if ("channel".equals(parser.getName())){
//创建一个list集合
newsLists=new ArrayList<News>();
}else if ("item".equals(parser.getName())){
//创建news对象
news=new News();
}else if("title".equals(parser.getName())){
news.setTitle(parser.nextText());//取出标签对内的内容
}else if("description".equals(parser.getName())){
news.setDescription(parser.nextText());//取出标签对内的内容
}else if("image".equals(parser.getName())){
news.setImage(parser.nextText());//取出标签对内的内容
}else if("type".equals(parser.getName())){
news.setType(parser.nextText());//取出标签对内的内容
}else if("comment".equals(parser.getName())){
news.setComment(parser.nextText());//取出标签对内的内容
}
break;
case XmlPullParser.END_TAG://解析结束节点
if ("item".equals(parser.getName())){
//把javabean添加到集合
newsLists.add(news);
}
break;
}
//不停地向下解析
type=parser.next();
}
} catch (Exception e) {
e.printStackTrace();
}
return newsLists;
}
}
3、manifest添加网络访问许可
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fengray.ex052">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:usesCleartextTraffic="true"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
4、主activity文件
package com.fengray.ex052;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView mylistView;
List<News> newsLists;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mylistView=findViewById(R.id.mylistview);
//准备listView要显示的数据,去服务器去数据,进行封装到javabean中
initListData();
}
//准备listView的数据
public void initListData(){
new Thread(){
@Override
public void run() {
//1、去服务器取数据http://192.168.1.64:8080/AndroidPhone/news.xml
String path="http://192.168.1.64:8080/AndroidPhone/news.xml";
try {
//2、创建URL对象
URL url=new URL(path);
//3、获取HttpURLConnection对象
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
//4、设置get请求方式
connection.setRequestMethod("GET");
//5、设置请求超时时间
connection.setConnectTimeout(5000);
//6、获取服务器返回的状态码
int code=connection.getResponseCode();
//7、判断状态码
if (code==200){
//8、以流的形式返回数据
InputStream inputStream=connection.getInputStream();
//9、解析XML数据
newsLists=XmlParserUtils.parserXml(inputStream);
Log.d("TAG", "run: "+newsLists.size());
//10、更新UI,把数据显示到住主线程listView上
runOnUiThread(new Runnable() {
@Override
public void run() {
//给listView设置适配器
mylistView.setAdapter(new MyAdapter());
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
//定义数据适配器
private class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return newsLists.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView==null){
view=View.inflate(getApplicationContext(),R.layout.cell,null);
}else{
view=convertView;
}
//找到控件,显示集合内的数据
ImageView imageView = view.findViewById(R.id.myimage);
TextView mytitle=view.findViewById(R.id.mytitle);
TextView description=view.findViewById(R.id.mydescription);
TextView mytype=view.findViewById(R.id.mytype);
//展示图片的数据
String imagUrl=newsLists.get(position).getImage();
//显示数据
mytitle.setText(newsLists.get(position).getTitle());
description.setText(newsLists.get(position).getDescription());
String newsType=newsLists.get(position).getType();
String comment=newsLists.get(position).getComment();
int type=Integer.parseInt(newsType);
switch (type){
case 1:
mytype.setText("国内新闻");
break;
case 2:
mytype.setText("国际新闻");
break;
case 3:
mytype.setText(comment+" 跟帖");
break;
case 4:
mytype.setText("体育新闻");
break;
}
return view;
}
}
}