Android application: realize network loading of product data [OKHttp, Glide, Gson]

Implement the function of loading product data over the network:

1. Declare network permissions in AndroidManifest.xml;

2. Add necessary third-party libraries such as okhttp, glide, gson, etc. to app/build.gradle;

3. Connect to the given Web service through OkHttpClient in MainActivity to obtain product data; the corresponding json data is a local json file named goods_list_data.json; the data content is: [
{“id”:1,”count”:”54,000″,”goodsName”:”Fuji Polaroid Camera”,”goodsPic”:”/img/polaroid.png”},
{“id”:2,”count”:”53,000″,”goodsName”:”Ganz Microwave Oven”,”goodsPic”:”/img/microwave_oven.png”},
{“id”:3,”count”:”14,000″,”goodsName”:”New National Standard Electric Vehicle”,”goodsPic”:”/img/electric_vehicle.png”},
{“id”:4,”count”:”16,000″,”goodsName”:”Official customized projector”,”goodsPic”:”/img/projector.png”},
{“id”:5,”count”:”04,000″,”goodsName”:”Midea 35L Oven”,”goodsPic”:”/img/oven.png”},
{“id”:6,”count”:”33,000″,”goodsName”:”Children’s Learning Table”,”goodsPic”:”/img/learning_table.png”}
]
The corresponding image is also stored in the local img file

4. Use the gson library to parse the product data in JSON format and convert it into a list of java bean product data objects (Goods class);

5. Create a MsgHandler class for asynchronously updating the product list;

6. Load and display network images through the glide control in GoodsAdapter.

1. Deploy network image resources

First, we need to deploy the corresponding files in a simple server (Tomcat). The directory structure of the data stored in the server is as shown below

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

Among them, the ROOT directory is under "apache-tomcat-9.0.65-windows-x64\webapps\ROOT", which represents the root directory of the Tomcat server.

  • The goods folder stores the data used in the product list
  • The goods\img folder stores the picture resources of the products.
  • The goods_list_data.json file stores the data of the product list, as shown below.
[
  {<!-- -->"id":1,"count":"54,000","goodsName":"Fuji Polaroid Camera","goodsPic":"/img/polaroid.png"},
  {<!-- -->"id":2,"count":"53,000","goodsName":"Ganz Microwave Oven","goodsPic":"/img/microwave_oven.png"},
  {<!-- -->"id":3,"count":"14,000","goodsName":"New National Standard Electric Vehicle","goodsPic":"/img/electric_vehicle.png"},
  {<!-- -->"id":4,"count":"16,000","goodsName":"Official customized projector","goodsPic":"/img/projector.png"},
  {<!-- -->"id":5,"count":"04,000","goodsName":"Midea 35L Oven","goodsPic":"/img/oven.png"},
  {<!-- -->"id":6,"count":"33,000","goodsName":"Children's Learning Table","goodsPic":"/img/learning_table.png"}
]

After starting tomcat, you can visit http://localhost:8080/goods/goods_list_data.json to display the information

2. Create project

  1. Open Android Studio and create a new Android project.
  2. Name the project and select the appropriate target API level and device type.
  3. Create a new Empty Activity.

3. Declare network permissions in AndroidManifest.xml

Add the following permission declaration in the AndroidManifest.xml file so that the app can access the network:

<uses-permission android:name="android.permission.INTERNET" />

A problem caused by network security policy that does not allow communication with localhost in clear text (non-encrypted) . This usually involves network security configuration, especially with the introduction of stricter network security policies in Android 9.0 (API level 28) and higher; therefore we also need to Configure network security profiles

One way to solve this problem is to use the HTTPS protocol instead of HTTP, since HTTPS is encrypted.

If you are testing your app locally, you can use Android's Network Security Profile to allow clear text communication.

  1. Create a network security configuration file named network_security_config.xml in the res/xml folder. If the folder does not exist, create it manually.
<?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. In the AndroidManifest.xml file, apply this network security profile to your app. Add the android:networkSecurityConfig attribute inside the element as follows:
<application
    android:networkSecurityConfig="@xml/network_security_config"
    <!-- Other attributes and elements -->
    >
    <!-- Other elements -->
</application>

This will allow your app to communicate in the clear with localhost during local development and testing. Note, however, that in a production environment, HTTPS is highly recommended to ensure secure transmission of data.

If you are using an emulator or a real device, make sure to rebuild and deploy the app for the configuration to take effect. Also, if your server is running locally, make sure the server port and address are correct.

4. Add dependent libraries

Add OkHttp, Glide, and Gson dependency libraries to the app/build.gradle file.

 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")

Sync

Waiting for dependencies to be installed…

5. Create an XML layout file

Create a layout file, such as activity_main.xml, in the res/layout folder to display product data.

<?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"/>


Create an XML layout file to display product items
Create a layout file, such as item_goods.xml, in the res/layout folder to display each product item.

<?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. Create a Java Bean class

Create a Goods class to represent product data.

public class Goods {<!-- -->
    private int id;
    private String count;
    private String goodsName;
    private String goodsPic;

    // Getters and setters
}

7. Create an adapter class

Create a custom adapter class GoodsAdapter to bind product data to RecyclerView.

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; // Returning 0 means there is no data
        }
    }

    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. Implement network loading data

Implement the function of loading product data over the network in MainActivity.java. Please make sure your goods_list_data.json file is located in the app/src/main/assets folder.

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);

                        //Complete image 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);

                        // Switch to the main thread to update the UI
                        runOnUiThread(new Runnable() {<!-- -->
                            @Override
                            public void run() {<!-- -->
                                //Set the adapter of RecyclerView
                                adapter = new GoodsAdapter(MainActivity.this, goodsList);
                                recyclerView.setAdapter(adapter);
                            }
                        });

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


Replace "URL_TO_YOUR_JSON_DATA" with the path to your local JSON file, for example: http://localhost:8080/goods/goods_list_data.json.

Note that if you are deploying tomcat locally and need to access it in the default Android virtualizer, you need to change it to “10.0.2.2

Here are some explanations of the code:

  1. A new thread is created in the fetchGoodsData() method to perform network requests. This is a good practice because it ensures that network requestsdo not block the main thread to avoid responsiveness issues in your application.

  2. After the network request is successful, use the Gson library to parse the JSON data into an array of Goods objects, and complete the URL of the image. This ensures that Glide loads the image correctly.

  3. Use Handler to update the UI because UI updates must be performed in the main thread.

  4. When a network request fails, an error message is printed via Log.e, which helps with debugging and troubleshooting.

Achieve results