Android应用:实现网络加载商品数据【OKHttp、Glide、Gson】

实现网络加载商品数据的功能:

1、在AndroidManifest.xml中声明网络权限;

2、在app/build.gradle中添加okhttp, glide, gson等必需的第3方库;

3、在MainActivity中通过OkHttpClient连接给定的Web服务,获取商品数据;对应的json数据为本地的json文件,名字为goods_list_data.json;数据内容为:[

{"id":1,"count":"5.4万","goodsName":"富士拍立得相机","goodsPic":"/img/polaroid.png"},

{"id":2,"count":"5.3万","goodsName":"格兰仕微波炉","goodsPic":"/img/microwave_oven.png"},

{"id":3,"count":"1.4万","goodsName":"新国标电动车","goodsPic":"/img/electric_vehicle.png"},

{"id":4,"count":"1.6万","goodsName":"官方订制投影仪","goodsPic":"/img/projector.png"},

{"id":5,"count":"0.4万","goodsName":"美的35L烤箱","goodsPic":"/img/oven.png"},

{"id":6,"count":"3.3万","goodsName":"儿童学习桌","goodsPic":"/img/learning_table.png"}

]

对应的图片也存储在本地的img文件中

4、使用gson库解析JSON格式的商品数据,转成java bean商品数据对象(Goods类)的列表;

5、创建MsgHandler类,用于异步更新商品列表;

6、在GoodsAdapter中通过glide控件加载并显示网络图片。


1.部署网络图片资源

首先,我们需要将对应的文件部署在一个简易的服务器(Tomcat)中,服务器中存放数据的目录结构如下图所示

E:.
├─goods
│  └─img
│  └─goods_list_data.json
└─WEB-INF

其中,ROOT目录在"apache-tomcat-9.0.65-windows-x64\webapps\ROOT"下,表示Tomcat服务器的根目录。

  • goods文件夹存放的是商品列表所用到的数据
  • 其中goods\img文件夹存放的是商品的图片资源
  • goods_list_data.json文件存放的是商品列表的数据,具体如下所示
json 复制代码
[
  {"id":1,"count":"5.4万","goodsName":"富士拍立得相机","goodsPic":"/img/polaroid.png"},
  {"id":2,"count":"5.3万","goodsName":"格兰仕微波炉","goodsPic":"/img/microwave_oven.png"},
  {"id":3,"count":"1.4万","goodsName":"新国标电动车","goodsPic":"/img/electric_vehicle.png"},
  {"id":4,"count":"1.6万","goodsName":"官方订制投影仪","goodsPic":"/img/projector.png"},
  {"id":5,"count":"0.4万","goodsName":"美的35L烤箱","goodsPic":"/img/oven.png"},
  {"id":6,"count":"3.3万","goodsName":"儿童学习桌","goodsPic":"/img/learning_table.png"}
]

启动tomcat后,可访问http://localhost:8080/goods/goods_list_data.json展示信息

2.创建项目

  1. 打开Android Studio,并创建一个新的Android项目。
  2. 命名项目并选择适当的目标API级别和设备类型。
  3. 创建一个新的空白活动(Empty Activity)。

3.在AndroidManifest.xml中声明网络权限

在 AndroidManifest.xml 文件中添加以下权限声明,以便应用可以访问网络:

xml 复制代码
<uses-permission android:name="android.permission.INTERNET" />

由于网络安全策略导致的问题,即不允许在明文(非加密)的情况下与 localhost 进行通信。这通常涉及到网络安全配置,特别是在 Android 9.0(API级别28)及更高版本中引入了更严格的网络安全策略;因此我们还需要进行配置网络安全配置文件

解决此问题的方法之一是使用 HTTPS 协议而不是 HTTP,因为 HTTPS 是加密的。

如果在本地测试应用,可以使用 Android 的网络安全配置文件来允许明文通信。

  1. res/xml 文件夹中创建一个名为 network_security_config.xml 的网络安全配置文件。如果该文件夹不存在,请手动创建。
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
</network-security-config>
  1. AndroidManifest.xml 文件中,将这个网络安全配置文件应用于你的应用。在 <application> 元素内添加 android:networkSecurityConfig 属性,如下所示:
xml 复制代码
<application
    android:networkSecurityConfig="@xml/network_security_config"
    <!-- 其他属性和元素 -->
    >
    <!-- 其他元素 -->
</application>

这将允许你的应用在本地开发和测试过程中与 localhost 进行明文通信。但请注意,在生产环境中,强烈建议使用 HTTPS 以确保数据的安全传输。

如果你使用的是模拟器或真机设备,请确保重新构建和部署应用,以使配置生效。此外,如果你的服务器正在本地运行,请确保服务器端口和地址正确。

4.添加依赖库

app/build.gradle文件中添加OkHttp、Glide、Gson依赖库。

groovy 复制代码
    implementation("com.squareup.okhttp3:okhttp:4.9.1")
    implementation("com.squareup.okhttp3:logging-interceptor:4.9.1")
    implementation("com.google.code.gson:gson:2.8.8")
    implementation("com.github.bumptech.glide:glide:4.12.0")
    annotationProcessor("com.github.bumptech.glide:compiler:4.12.0")

进行同步

等待安装依赖......

5.创建一个XML布局文件

res/layout文件夹中创建一个布局文件,例如activity_main.xml,用于显示商品数据。

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"/>


创建一个XML布局文件用于显示商品项

res/layout文件夹中创建一个布局文件,例如item_goods.xml,用于显示每个商品项。

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <ImageView
        android:id="@+id/goodsImageView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/goodsNameTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp" />
</LinearLayout>

6.创建一个Java Bean类

创建一个Goods类,用于表示商品数据。

java 复制代码
public class Goods {
    private int id;
    private String count;
    private String goodsName;
    private String goodsPic;

    // Getters and setters
}

7.创建一个适配器类

创建一个自定义适配器类GoodsAdapter,用于将商品数据绑定到RecyclerView中。

java 复制代码
public class GoodsAdapter extends RecyclerView.Adapter<GoodsAdapter.ViewHolder> {
    private List<Goods> goodsList;
    private Context context;

    public GoodsAdapter(Context context, List<Goods> goodsList) {
        this.context = context;
        this.goodsList = goodsList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_goods, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Goods goods = goodsList.get(position);
        holder.goodsNameTextView.setText(goods.getGoodsName());

        // Load and display image using Glide
        Glide.with(context)
            .load(goods.getGoodsPic())
            .into(holder.goodsImageView);
    }
    @Override
    public int getItemCount() {
        if (goodsList != null) {
            return goodsList.size();
        } else {
            return 0; // 返回0表示没有数据
        }
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView goodsNameTextView;
        ImageView goodsImageView;

        ViewHolder(View itemView) {
            super(itemView);
            goodsNameTextView = itemView.findViewById(R.id.goodsNameTextView);
            goodsImageView = itemView.findViewById(R.id.goodsImageView);
        }
    }
}

8.实现网络加载数据

MainActivity.java中实现网络加载商品数据的功能。请确保你的goods_list_data.json文件位于app/src/main/assets文件夹下。

java 复制代码
package com.leo.network;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.google.gson.Gson;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private GoodsAdapter adapter;
    private List<Goods> goodsList;

    private static final int MSG_UPDATE_DATA = 1;
    private Handler msgHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == MSG_UPDATE_DATA) {
                adapter.notifyDataSetChanged();
            }
            return true;
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapter = new GoodsAdapter(this, goodsList);
        recyclerView.setAdapter(adapter);

        // Fetch data from the network
        fetchGoodsData();
    }

    private void fetchGoodsData() {

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    OkHttpClient client = new OkHttpClient();
                    Request request = new Request.Builder()
                            .url("http://10.0.2.2:8080/goods/goods_list_data.json")
                            .build();
                    Response response = client.newCall(request).execute();
                    if (response.isSuccessful()) {
                        String jsonData = response.body().string();
                        Log.d("Network", "Data fetched successfully: " + jsonData);

                        Gson gson = new Gson();
                        Goods[] goodsArray = gson.fromJson(jsonData, Goods[].class);

                        // 补全图片URL
                        for (Goods goods : goodsArray) {
                            goods.setGoodsPic("http://10.0.2.2:8080//goods" + goods.getGoodsPic());
                        }

                        goodsList = Arrays.asList(goodsArray);
                        msgHandler.sendEmptyMessage(MSG_UPDATE_DATA);

                        // 切换到主线程以更新UI
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                // 设置RecyclerView的适配器
                                adapter = new GoodsAdapter(MainActivity.this, goodsList);
                                recyclerView.setAdapter(adapter);
                            }
                        });

                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.e("Network", "Error fetching data: " + e.getMessage());
                }
            }
        }).start();
    }
}

替换"URL_TO_YOUR_JSON_DATA"为你的本地JSON文件的路径,例如:http://localhost:8080/goods/goods_list_data.json

注意,如果你是本地部署的tomcat,需要在Android默认的虚拟器中访问,需要改为"10.0.2.2"

以下是对代码的一些说明:

  1. fetchGoodsData() 方法中创建了一个新的线程来执行网络请求。这是一个良好的实践,因为它确保网络请求不会阻塞主线程,以避免应用的响应性问题。

  2. 在网络请求成功后使用 Gson 库将 JSON 数据解析为 Goods 对象的数组,并补全了图片的URL。这确保了 Glide 能够正确加载图片。

  3. 使用 Handler 来更新UI,因为 UI更新必须在主线程中执行。

  4. 在网络请求失败时,通过 Log.e 打印了错误消息,这有助于调试和问题排查。

实现效果

相关推荐
gywl1 小时前
openEuler VM虚拟机操作(期末考试)
linux·服务器·网络·windows·http·centos
WTT00112 小时前
2024楚慧杯WP
大数据·运维·网络·安全·web安全·ctf
C4rpeDime2 小时前
自建MD5解密平台-续
android
杨德杰3 小时前
QT网络(一):主机信息查询
网络·qt
007php0073 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
yang_shengy3 小时前
【JavaEE】网络(6)
服务器·网络·http·https
鲤籽鲲4 小时前
C# Random 随机数 全面解析
android·java·c#
zquwei4 小时前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
Aimin20224 小时前
路由器做WPAD、VPN、透明代理中之间一个
网络
群联云防护小杜5 小时前
如何给负载均衡平台做好安全防御
运维·服务器·网络·网络协议·安全·负载均衡