CODE

Android E-Commerce App - Joomla VirtueMart Integration

Android E-Commerce App with Joomla VirtueMart Integration

This tutorial demonstrates how to build a fully functional Android shopping app that connects directly to a Joomla VirtueMart store. Products are displayed using a RecyclerView layout and enhanced with features like image loading (Glide), network requests (Volley), and real-time search.

The backend fetches data from a MySQL database, converts it into JSON using a custom PHP script, and delivers it to the Android app. The app showcases a modern UI, smooth animations, and product detail pages using CollapsingToolBarLayout.

Ideal for developers looking to bridge Joomla CMS with native Android applications in a clean, efficient way.

This Android tutorial connects a Joomla VirtueMart store to an Android front end by:

  • Using a PHP API (JoomlaApi.php) to query VirtueMart's MySQL structure and return formatted product data as JSON.
  • Accessing joined tables like virtuemart_products, virtuemart_product_prices, and virtuemart_medias to output product name, image, stock, price, and category.
  • Enhancing Android UI with:
    • RecyclerView for dynamic product lists
    • Volley for network communication
    • Glide for image loading
    • HtmlTextView to render HTML-based product descriptions
    • A built-in SearchView to filter results locally
    • CollapsingToolbarLayout for rich product detail views
  • Using custom model classes (e.g., Anime.java) to map JSON data to objects
  • Including activities like:
    • Shop (Main product list)
    • AnimeActivity (Product detail screen)
    • SplashActivity (animated intro)

The project uses an activity_shop.xml layout with RecyclerView and fully supports filtering/searching products based on name, studio, description, or category.

Volley Library: Volley is an HTTP library that makes networking for Android applications easier and, more importantly, faster.

Glide: Glide is a fast and efficient open-source image loading and media management framework for Android that wraps media decoding, memory and disk caching, and resource pooling into a simple and easy-to-use interface.

Android E-Commerce App with Joomla VirtueMart Integration
Android E-Commerce App with Joomla VirtueMart Integration
Android E-Commerce App with Joomla VirtueMart Integration

 

Demo Site:
https://demo.virtuemart.net/
Template used in this demo:
https://www.smartaddons.com/free-joomla-templates

Access the MySql database and convert to Json:
To load Virtuemart products in the Android RecyclerView, you need to access the MySql database and load the data via Json.
To do this, use the following method:
Create a db.php file with access to your database.
Replace JOOMLA_db_prefix with the prefix of your installation.

date_default_timezone_set('Europe/Lisbon');
include('db.php');

JommlaApi.php

$sqlProdutos = "SELECT JOOMLA_db_prefix_virtuemart_products_en_gb.product_name AS name, JOOMLA_db_prefix_virtuemart_products_en_gb.product_desc AS description, JOOMLA_db_prefix_virtuemart_medias.file_url AS img, JOOMLA_db_prefix_virtuemart_categories_en_gb.category_name AS categorie, JOOMLA_db_prefix_virtuemart_products.product_in_stock AS Rating, JOOMLA_db_prefix_virtuemart_product_prices.product_override_price AS studio,JOOMLA_db_prefix_virtuemart_products.product_in_stock AS episode FROM JOOMLA_db_prefix_virtuemart_products 

JOIN JOOMLA_db_prefix_virtuemart_products_en_gb ON JOOMLA_db_prefix_virtuemart_products_en_gb.virtuemart_product_id = JOOMLA_db_prefix_virtuemart_products.virtuemart_product_id 
JOIN JOOMLA_db_prefix_virtuemart_product_medias ON JOOMLA_db_prefix_virtuemart_product_medias.virtuemart_product_id = JOOMLA_db_prefix_virtuemart_products.virtuemart_product_id 
JOIN JOOMLA_db_prefix_virtuemart_medias ON JOOMLA_db_prefix_virtuemart_medias.virtuemart_media_id = JOOMLA_db_prefix_virtuemart_product_medias.virtuemart_media_id
JOIN JOOMLA_db_prefix_virtuemart_product_categories ON JOOMLA_db_prefix_virtuemart_product_categories.virtuemart_product_id = JOOMLA_db_prefix_virtuemart_products.virtuemart_product_id 
JOIN JOOMLA_db_prefix_virtuemart_categories_en_gb ON JOOMLA_db_prefix_virtuemart_product_categories.virtuemart_category_id = JOOMLA_db_prefix_virtuemart_categories_en_gb.virtuemart_category_id 
JOIN JOOMLA_db_prefix_virtuemart_product_prices ON JOOMLA_db_prefix_virtuemart_product_prices.virtuemart_product_id = JOOMLA_db_prefix_virtuemart_products.virtuemart_product_id"; 

$resultProdutos = $conn->query($sqlProdutos); 
$num_rowsProdutos = mysqli_num_rows($resultProdutos); 
$string = ""; 
foreach ($resultProdutos as $value) { 
$value["img"] = 'https://'.$_SERVER['SERVER_NAME'].'/'.$value["img"]; 
$value["studio"] = number_format((float)$value["studio"], 2, ',', ''). " €"; 
$value["description"] = '<b>Categoria: '. $value["categorie"].'</b><br><br><label class="price label"><b>Em stock:</b> '. $value["Rating"].'</label><br><br><b><label class="price label">Preço c/ Desconto: '.$value["studio"].'</label></b><div class="col-sm-12"><img style="margin:0 auto;" width="100%" src="'. $value["img"] .'"/></div><p style="text-align:justify;">'. $value["description"].'</p><hr style="border: 1px solid #333;">';
$resultado = (json_encode($value, JSON_FORCE_OBJECT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); $string .= $resultado . ",\n";
}
header("Content-Type: application/json; charset=UTF-8");
$finalResult = "[\n". substr($string, 0, strlen($string) - 2) ."\n]";
echo $finalResult ;
mysqli_close($conn);

In Android Studio, create a new activity (empty_activity)
1. Importing Required Libraries:

Inside build.gradle (Project: yourappname) add the mavenCentral() repository:

repositories {
mavenCentral()
google()
jcenter()
}

 e em build.gradle (Módulo: app) adicione as seguintes implementações:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    // Glide library 
    implementation 'com.github.bumptech.glide:glide:4.6.1'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'
    // Volley library
    implementation 'com.android.volley:volley:1.0.0'
    // Recyclerview Library
    implementation 'com.android.support:recyclerview-v7:27.0.2'
// Apresenta HTML na descrição do Produto implementation 'org.sufficientlysecure:html-textview:4.0' }

 2. Create a model Class

public class Anime {

    private String name ;
    private String Description;
    private String rating;
    private String nb_episode;
    private String categorie;
    private String studio ;
    private String image_url;

    public Anime() {
    }

    public Anime(String name, String description, String rating, String nb_episode, String categorie, String studio, String image_url) {
        this.name = name;
        Description = description;
        this.rating = rating;
        this.nb_episode = nb_episode;
        this.categorie = categorie;
        this.studio = studio;
        this.image_url = image_url;
    }

    public String getName() {
        return name;
    }
    public String getDescription() {
        return Description;
    }
    public String getRating() {
        return rating;
    }
    public String getNb_episode() {
        return nb_episode;
    }
    public String getCategorie() {
        return categorie;
    }
    public String getStudio() {
        return studio;
    }
    public String getImage_url() {
        return image_url;
    }

    public void setName(String name) {
        this.name = name;
    }
    public void setDescription(String description) {
        Description = description;
    }
    public void setRating(String rating) {
        this.rating = rating;
    }
    public void setNb_episode(String nb_episode) {
        this.nb_episode = nb_episode;
    }
    public void setCategorie(String categorie) {
        this.categorie = categorie;
    }
    public void setStudio(String studio) {
        this.studio = studio;
    }
    public void setImage_url(String image_url) {
        this.image_url = image_url;
    }
}

2.3. Product Listing

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:layout_marginTop="0dp"
    android:background="@color/white"
    android:orientation="horizontal"
    android:padding="0dp">

    <ImageView
        android:id="@+id/thumbnail"
        android:layout_width="150dp"
        android:layout_height="120dp"
        android:background="#fff"
        android:layout_margin="1sp"
        android:contentDescription="@string/todo" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="119dp"
        android:layout_marginBottom="1dp"
        android:background="@color/colorPrimaryDark"
        android:orientation="vertical"
        android:padding="4dp">

        <TextView
            android:id="@+id/anime_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/anime_title"
            android:textColor="@color/white"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/categorie"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:text="@string/category"
            android:textColor="@color/white" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:textSize="16sp"
                android:fontFamily="@font/ubuntu"
                android:textColor="@color/white"
                android:text="@string/ref"/>
        <TextView
            android:id="@+id/rating"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:text="@string/_0_0"
            android:textColor="@color/white"
            android:textSize="15sp"
            android:textStyle="bold" />
        </LinearLayout>
        <TextView
            android:id="@+id/studio"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:text="@string/studio"
            android:textStyle="bold"
            android:textSize="16sp"
            android:textColor="@color/white" />


    </LinearLayout>

</LinearLayout>

activity anime row

2.4. Product Details

The details activity will contain a collapsigntoolbarlayout and to implement this view we need to add the design library to our project
open build.gradle(module:app) and add the following line:

// Design Library
implementation 'com.android.support:design:27.0.2'
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:layout_marginTop="0dp"
    android:background="@color/white"
    android:orientation="horizontal"
    android:padding="0dp">

    <ImageView
        android:id="@+id/thumbnail"
        android:layout_width="150dp"
        android:layout_height="120dp"
        android:background="#fff"
        android:layout_margin="1sp"
        android:contentDescription="@string/todo" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="119dp"
        android:layout_marginBottom="1dp"
        android:background="@color/colorPrimaryDark"
        android:orientation="vertical"
        android:padding="4dp">

        <TextView
            android:id="@+id/anime_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/anime_title"
            android:textColor="@color/white"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/categorie"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:text="@string/category"
            android:textColor="@color/white" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:textSize="16sp"
                android:fontFamily="@font/ubuntu"
                android:textColor="@color/white"
                android:text="@string/ref"/>
        <TextView
            android:id="@+id/rating"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:text="@string/_0_0"
            android:textColor="@color/white"
            android:textSize="15sp"
            android:textStyle="bold" />
        </LinearLayout>
        <TextView
            android:id="@+id/studio"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:text="@string/studio"
            android:textStyle="bold"
            android:textSize="16sp"
            android:textColor="@color/white" />


    </LinearLayout>

</LinearLayout>

2.1 AnimeActivity

public class AnimeActivity extends AppCompatActivity {

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

      ActionBar actionBar = getSupportActionBar();

        actionBar.setDisplayShowHomeEnabled(true);
        getSupportActionBar().setTitle("Shop Demo");

        String name  = Objects.requireNonNull(getIntent().getExtras()).getString("anime_name");
        String description = getIntent().getExtras().getString("anime_description");
        String studio = getIntent().getExtras().getString("anime_studio") ;
        String category = getIntent().getExtras().getString("anime_category");
        String nb_episode = getIntent().getExtras().getString("anime_nb_episode") ;
        String rating = getIntent().getExtras().getString("anime_rating") ;
        String image_url = getIntent().getExtras().getString("anime_img") ;

        // ini views

        CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsingtoolbar_id);
        collapsingToolbarLayout.setTitleEnabled(true);

        TextView tv_name = findViewById(R.id.aa_anime_name);
        TextView tv_studio = findViewById(R.id.aa_studio);
        TextView tv_categorie = findViewById(R.id.aa_categorie) ;
        TextView tv_rating  = findViewById(R.id.aa_rating) ;
        ImageView image = findViewById(R.id.aa_thumbnail);

        // setting values to each view
        tv_name.setText(name);
        tv_categorie.setText(category);
        tv_rating.setText(rating);
        tv_studio.setText(studio);

        HtmlTextView tv_description = findViewById(R.id.aa_description);
        tv_description.setHtml(Objects.requireNonNull(description), new HtmlHttpImageGetter(tv_description));

        collapsingToolbarLayout.setTitle(name);
        RequestOptions requestOptions = new RequestOptions().centerCrop().placeholder(R.drawable.i9_logo_dark).error(R.drawable.i9_logo_dark);
        // set image using Glide
        Glide.with(this).load(image_url).apply(requestOptions).into(image);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_menu, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        int id = item.getItemId();
        if (id==R.id.BTHome) {
            Intent int1 = new Intent(AnimeActivity.this, SplashActivity.class);
            startActivity(int1);
            overridePendingTransition(R.anim.left_in, R.anim.left_out);
        }

        return super.onOptionsItemSelected(item);
    }

}

2.1.1 Itens - (activity_anime.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".AnimeActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:background="@color/colorPrimaryDark"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsingtoolbar_id"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMargin="10dp"
            app:expandedTitleMarginEnd="10dp"
            app:expandedTitleMarginStart="8dp"
            app:expandedTitleTextAppearance="@style/CollapsedAppBar"
            app:layout_scrollFlags="exitUntilCollapsed|scroll"
            android:textStyle="bold"
            app:title="@string/anime_title">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:paddingLeft="4dp"
                android:paddingTop="4dp"
                android:paddingRight="4dp"
                android:paddingBottom="4dp">

                <ImageView
                    android:id="@+id/aa_thumbnail"
                    android:layout_width="180dp"
                    android:layout_height="match_parent"
                    android:background="#fff"
                    android:layout_margin="4sp"
                    android:contentDescription="@string/app_name" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="140dp"
                    android:layout_margin="0dp"
                    android:padding="4dp"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/aa_anime_name"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/anime_title"
                        android:textColor="@color/white"
                        android:textSize="18sp"
                        android:fontFamily="@font/ubuntu"
                        android:textAllCaps="true" />

                    <TextView
                        android:id="@+id/aa_categorie"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="0dp"
                        android:text="@string/category"
                        android:textSize="14dp"
                        android:fontFamily="@font/ubuntu"
                        android:textColor="@color/white" />
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal">
                        <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="4dp"
                        android:textSize="16sp"
                        android:fontFamily="@font/ubuntu"
                        android:textColor="@color/white"
                        android:text="@string/ref"/>
                        <TextView
                        android:id="@+id/aa_rating"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="6dp"
                        android:paddingEnd="4dp"
                        android:paddingStart="0dp"
                        android:text="0.0"
                        android:textColor="@color/white"
                        android:textSize="18sp"
                        android:fontFamily="@font/ubuntu"
                        android:textStyle="bold" />

                    </LinearLayout>
                        <TextView
                            android:id="@+id/aa_studio"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="5dp"
                            android:text="@string/studio"
                            android:paddingStart="0dp"
                            android:textSize="20dp"
                            android:fontFamily="@font/ubuntu"
                            android:textStyle="bold"
                            android:textColor="@color/white" />

                </LinearLayout>
            </LinearLayout>
            <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:theme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_collapseMode="pin">
            </androidx.appcompat.widget.Toolbar>
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>
    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="6dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
        <org.sufficientlysecure.htmltextview.HtmlTextView
            android:gravity="center"
            android:layout_gravity="center_vertical|top"
            android:text="Anime Description"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/aa_description"
            android:fontFamily="@font/ubuntu"
            android:textSize="16sp"
            />
    </androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

activity anime

2.2 RecyclerView Adapter class

public class RecyclerViewAdapter extends RecyclerView.Adapter implements Filterable {

    private final Context mContext ;
    private final List mData ;
    private List mDataFull ;
    RequestOptions option;

    public RecyclerViewAdapter(Context mContext, List mData) {
        this.mContext = mContext;
        this.mData = mData;
        this.mDataFull = mData;
        // Request option for Glide
        option = new RequestOptions().centerCrop().placeholder(R.drawable.loading_shape).error(R.drawable.loading_shape);
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view ;
        LayoutInflater inflater = LayoutInflater.from(mContext);
        view = inflater.inflate(R.layout.anime_row_item,parent,false) ;
        final MyViewHolder viewHolder = new MyViewHolder(view) ;
        viewHolder.view_container.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Intent i = new Intent(mContext, AnimeActivity.class);
                i.putExtra("anime_name",mDataFull.get(viewHolder.getAdapterPosition()).getName());
                i.putExtra("anime_description",mDataFull.get(viewHolder.getAdapterPosition()).getDescription());
                i.putExtra("anime_studio",mDataFull.get(viewHolder.getAdapterPosition()).getStudio());
                i.putExtra("anime_category",mDataFull.get(viewHolder.getAdapterPosition()).getCategorie());
                i.putExtra("anime_nb_episode",mDataFull.get(viewHolder.getAdapterPosition()).getNb_episode());
                i.putExtra("anime_rating",mDataFull.get(viewHolder.getAdapterPosition()).getRating());
                i.putExtra("anime_img",mDataFull.get(viewHolder.getAdapterPosition()).getImage_url());
                mContext.startActivity(i);
            }
        });

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {

        holder.tv_name.setText(mDataFull.get(position).getName());
        holder.tv_rating.setText(mDataFull.get(position).getRating());
        holder.tv_studio.setText(mDataFull.get(position).getStudio());
        holder.tv_category.setText(mDataFull.get(position).getCategorie());
        // Load Image from the internet and set it into Imageview using Glide
        Glide.with(mContext).load(mDataFull.get(position).getImage_url()).apply(option).into(holder.img_thumbnail);

    }

    @Override
    public int getItemCount() {

        return mDataFull.size();
    }

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {
                String charString = charSequence.toString();
                if (charString.isEmpty()) {
                    mDataFull = mData ;
                } else {
                    List filteredList = new ArrayList<>();
                    for (Anime name : mData) {
                        if (name.getName().toLowerCase().contains(charString.toLowerCase()) || name.getStudio().toLowerCase().contains(charString.toLowerCase()) || name.getDescription().toLowerCase().contains(charSequence) || name.getCategorie().toLowerCase().contains(charString.toLowerCase())) {
                            filteredList.add(name);
                        }
                    }
                    mDataFull = filteredList ;
                }
                FilterResults filterResults = new FilterResults();
                filterResults.values = mDataFull;
                return filterResults ;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                mDataFull = (List) results.values;
                notifyDataSetChanged();
            }
        };
    }

    public static class MyViewHolder extends RecyclerView.ViewHolder {

        TextView tv_name ;
        TextView tv_rating ;
        TextView tv_studio ;
        TextView tv_category;
        ImageView img_thumbnail;
        LinearLayout view_container;

        public MyViewHolder(View itemView) {
            super(itemView);

            view_container = itemView.findViewById(R.id.container);
            tv_name = itemView.findViewById(R.id.anime_name);
            tv_category = itemView.findViewById(R.id.categorie);
            tv_rating = itemView.findViewById(R.id.rating);
            tv_studio = itemView.findViewById(R.id.studio);
            img_thumbnail = itemView.findViewById(R.id.thumbnail);

        }
    }

}

 2.3. (Activity Shop)

public class Shop extends AppCompatActivity {

    private final String JSON_URL = "LINK PARA O SEU FICHEIRO PHP/JSON (Descrito Acima)" ;
    private JsonArrayRequest request ;
    private RequestQueue requestQueue ;
    private List<Anime> lstAnime ;
    private RecyclerView recyclerView ;
    private RecyclerViewAdapter adapter;

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

        ActionBar actionBar = getSupportActionBar();
        actionBar.setDisplayShowHomeEnabled(true);
        getSupportActionBar().setTitle("Shop Demo");

        lstAnime = new ArrayList<>() ;
        recyclerView = findViewById(R.id.recyclerviewid);
        jsonrequest();
    }

    private void jsonrequest() {

        request = new JsonArrayRequest(JSON_URL, new Response.Listener<JSONArray>() {
            @Override
            public void onResponse(JSONArray response) {

                JSONObject jsonObject  = null ;

                for (int i = 0 ; i < response.length(); i++ ) {

                    try {
                        jsonObject = response.getJSONObject(i) ;
                        Anime anime = new Anime() ;
                        anime.setName(jsonObject.getString("name"));
                        anime.setDescription(jsonObject.getString("description"));
                        anime.setRating(jsonObject.getString("Rating"));
                        anime.setCategorie(jsonObject.getString("categorie"));
                        anime.setNb_episode(jsonObject.getString("episode"));
                        anime.setStudio(jsonObject.getString("studio"));
                        anime.setImage_url(jsonObject.getString("img"));
                        lstAnime.add(anime);

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

                setuprecyclerview(lstAnime);

            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
            }
        });

        requestQueue = Volley.newRequestQueue(Shop.this);
        requestQueue.add(request) ;
    }

    private void setuprecyclerview(List<Anime> lstAnime) {

        adapter = new RecyclerViewAdapter(this,lstAnime) ;
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_menu, menu);
        inflater.inflate(R.menu.search_menu, menu);

        MenuItem searchItem = menu.findItem(R.id.action_search);
        SearchView searchView = (SearchView) searchItem.getActionView();
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                if (adapter != null) {
                    adapter.getFilter().filter(newText);
                }
                return false;
            }
        });

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        int id = item.getItemId();

        if (id==R.id.BTHome) {
            Intent int1 = new Intent(Shop.this, SplashActivity.class);
            startActivity(int1);
            overridePendingTransition(R.anim.left_in, R.anim.left_out);
        }

        return super.onOptionsItemSelected(item);
    }

}

activity_shop.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.i9web.VMDemo.Shop">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerviewid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="0dp"
        android:layout_marginRight="0dp">
    </androidx.recyclerview.widget.RecyclerView>

</LinearLayout>

2.4: SplashActivity

Actividade de abertura da App, redireciona para a página de produtos.

public class SplashActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mostrarMainActivity();
            }
        }, 5000);

        ImageView img = findViewById(R.id.img_top);
        Animation aniSlide = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fade_in);
        img.startAnimation(aniSlide);

    }

    private void mostrarMainActivity() {
        Intent intent = new Intent(
                SplashActivity.this, Shop.class
        );
        startActivity(intent);
        finish();
    }
}

activity_splash.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.i9web.VMDemo.SplashActivity"
    android:orientation="vertical"
    android:gravity="center_horizontal|center_vertical"
    android:background="@color/black_overlay">

    <ImageView android:layout_width="wrap_content"
        android:id="@+id/img_top"
        android:src="@drawable/i9_logo_dark"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:scaleType="centerInside" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name"/>
</LinearLayout>

 splash