RAG using Gemini in Android App
Steps:
- Create JSON for search indexing (embedding) for custom document
- Get API Key for Gemini model using Google AI Studio
- Develop Android App
Sample Prompts used:
- What is Android?
- What is Java?
- What is RAG?
- What is Google Android Studio?
I hope you like this video. For any questions, suggestions or appreciation please contact us at: https://programmerworld.co/contact/ or email at: programmerworld1990@gmail.com
Details:
package com.programmerworld.raginandroidappusinggemini;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.google.ai.client.generativeai.GenerativeModel;
import com.google.ai.client.generativeai.java.GenerativeModelFutures;
import com.google.ai.client.generativeai.type.Content;
import com.google.ai.client.generativeai.type.GenerateContentResponse;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
private EditText queryInput;
private TextView resultText;
private Button submitButton;
private GenerativeModel generativeModel;
private List<Document> documents;
private ExecutorService executor = Executors.newSingleThreadExecutor();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
queryInput = findViewById(R.id.query_input);
resultText = findViewById(R.id.result_text);
submitButton = findViewById(R.id.submit_button);
// Initialize Gemini model
generativeModel = new GenerativeModel(
"gemini-1.5-flash",
"AIzaSyAxxxxx7f_xy5rDwTTP_sEn-CtJuU1gOXQ"
);
// Load documents from assets
documents = loadDocuments(this);
submitButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String query = queryInput.getText().toString();
if (!query.isEmpty()) {
generateWithRAG(query);
}
}
});
}
// Document class to hold text and embedding
private static class Document {
String text;
float[] embedding;
Document(String text, float[] embedding) {
this.text = text;
this.embedding = embedding;
}
}
// Load documents from data.json in assets
private List<Document> loadDocuments(Context context) {
List<Document> docList = new ArrayList<>();
try {
InputStream is = context.getAssets().open("data.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String json = new String(buffer, "UTF-8");
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject obj = jsonArray.getJSONObject(i);
String text = obj.getString("text");
JSONArray embeddingArray = obj.getJSONArray("embedding");
float[] embedding = new float[embeddingArray.length()];
for (int j = 0; j < embeddingArray.length(); j++) {
embedding[j] = (float) embeddingArray.getDouble(j);
}
docList.add(new Document(text, embedding));
}
} catch (Exception e) {
e.printStackTrace();
}
return docList;
}
// Simulate query-specific embeddings for prototyping
private float[] generateEmbedding(String query) {
// Simple heuristic based on query content
String lowerQuery = query.toLowerCase();
if (lowerQuery.contains("android")) {
return new float[]{0.1f, 0.2f, 0.3f, 0.4f, 0.5f}; // Matches Android entry
} else if (lowerQuery.contains("gemini")) {
return new float[]{0.3f, 0.4f, 0.5f, 0.6f, 0.7f}; // Matches Gemini entry
} else if (lowerQuery.contains("rag")) {
return new float[]{0.2f, 0.3f, 0.4f, 0.5f, 0.6f}; // Matches RAG entry
} else if (lowerQuery.contains("java")) {
return new float[]{0.4f, 0.5f, 0.6f, 0.7f, 0.8f}; // Matches Java entry
} else if (lowerQuery.contains("google ai studio")) {
return new float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f}; // Matches Google AI Studio entry
}
// Default fallback
return new float[]{0.2f, 0.3f, 0.4f, 0.5f, 0.6f};
}
// Cosine similarity calculation
private float cosineSimilarity(float[] vec1, float[] vec2) {
float dotProduct = 0.0f;
float norm1 = 0.0f;
float norm2 = 0.0f;
for (int i = 0; i < vec1.length; i++) {
dotProduct += vec1[i] * vec2[i];
norm1 += vec1[i] * vec1[i];
norm2 += vec2[i] * vec2[i];
}
return dotProduct / ((float) Math.sqrt(norm1) * (float) Math.sqrt(norm2));
}
// Retrieve the most relevant document
private String retrieveRelevantDoc(String query) {
float[] queryEmbedding = generateEmbedding(query);
Document bestDoc = null;
float bestScore = -1.0f;
for (Document doc : documents) {
float score = cosineSimilarity(doc.embedding, queryEmbedding);
if (score > bestScore) {
bestScore = score;
bestDoc = doc;
}
}
return bestDoc != null ? bestDoc.text : "No relevant data found";
}
// Generate response with RAG
private void generateWithRAG(String query) {
executor.execute(() -> {
try {
String relevantDoc = retrieveRelevantDoc(query);
String prompt = "Use this context to answer the query: '" + relevantDoc + "'\n\nQuery: " + query;
GenerativeModelFutures modelFutures = GenerativeModelFutures.from(generativeModel);
Content content = new Content.Builder().addText(prompt).build();
ListenableFuture<GenerateContentResponse> future = modelFutures.generateContent(content);
Futures.addCallback(future, new FutureCallback<GenerateContentResponse>() {
@Override
public void onSuccess(GenerateContentResponse response) {
String result = response.getText();
runOnUiThread(() -> resultText.setText(result != null ? result : "No response generated"));
}
@Override
public void onFailure(Throwable t) {
runOnUiThread(() -> resultText.setText("Error: " + t.getMessage()));
}
}, executor);
} catch (Exception e) {
e.printStackTrace();
runOnUiThread(() -> resultText.setText("Error: " + e.getMessage()));
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.RAGInAndroidAppUsingGemini"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
plugins {
alias(libs.plugins.android.application)
}
android {
namespace = "com.programmerworld.raginandroidappusinggemini"
compileSdk = 35
defaultConfig {
applicationId = "com.programmerworld.raginandroidappusinggemini"
minSdk = 33
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
dependencies {
implementation(libs.appcompat)
implementation(libs.material)
implementation(libs.activity)
implementation(libs.constraintlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
implementation("com.google.ai.client.generativeai:generativeai:0.9.0")
implementation("com.google.guava:guava:33.3.1-android")
}
<?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="match_parent"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/query_input"
android:layout_width="match_parent"
android:layout_height="69dp"
android:hint="Enter your query"
android:inputType="text" />
<Button
android:id="@+id/submit_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="16dp"
android:text="Submit" />
<TextView
android:id="@+id/result_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Response will appear here"
android:textSize="16sp"
android:layout_marginTop="16dp" />
</LinearLayout>
Screenshots:





Sample embedding data used (for custom document input):
Save the below json format, say data.json file.
[
{
"text": "Android is an open-source operating system developed by Google for mobile devices.",
"embedding": [0.1, 0.2, 0.3, 0.4, 0.5]
},
{
"text": "Gemini is a family of AI models created by Google, designed for natural language processing.",
"embedding": [0.3, 0.4, 0.5, 0.6, 0.7]
},
{
"text": "RAG stands for Retrieval-Augmented Generation, combining retrieval and generation in AI.",
"embedding": [0.2, 0.3, 0.4, 0.5, 0.6]
},
{
"text": "Java is a popular programming language used for Android app development.",
"embedding": [0.4, 0.5, 0.6, 0.7, 0.8]
},
{
"text": "Google AI Studio provides tools and APIs for building AI-powered applications.",
"embedding": [0.5, 0.6, 0.7, 0.8, 0.9]
}
]