Connectra Insights

In this blog, I’ll share key insights and implementation details from the development of an Android application. This app was designed with robust Firebase integration and a seamless user experience in mind. Along the way, I'll explain specific challenges and solutions, with an emphasis on professional practices.
Note: All the code snippets shared in this blog are kept concise for clarity and to explain the functionality. You can always refer to my complete code to explore the detailed implementation.
1. LoginActivity.java
The LoginActivity is the gateway to the app. Here's a breakdown of its functionality and design choices:
Dark Mode Check
- Since the app is optimized for light mode only, we perform a check at the beginning in
onCreate()
. If the system is in dark mode, a popup informs the user that the app is not designed for this mode. This ensures clarity in the user experience.
int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES) {
new AlertDialog.Builder(this)
.setTitle("Suggestion")
.setMessage("Please use this app without Dark mode for the best experience.")
.setCancelable(true) // User can dismiss the dialog by tapping outside
.setPositiveButton("OK", (dialog, which) -> dialog.dismiss())
.show();
}
Internet Connectivity Check
- Another critical check is for internet availability. If no connection is detected, the app displays a popup stating: “We need internet to proceed,” ensuring the user understands the requirement.
if (!isInternetAvailable()) {
showNoInternetDialog();
}
private boolean isInternetAvailable() {
ConnectivityManager connectivityManager =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
NetworkCapabilities capabilities =
connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
if (capabilities != null) {
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
}
}
return false;
}
Navigation Handling
- Users can navigate to the Forgot Password and Register screens by clicking the respective text views. Intents make this transition smooth and intuitive.
forgotPass.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(LoginActivity.this, ForgotPassword.class));
}
});
register.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(LoginActivity.this , RegisterActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP));
finish();
}
});
Login Flow
When the Login button is clicked, we extract user credentials from input fields, validate them, and authenticate against Firebase Authentication.
“Edge cases” are handled to ensure no invalid inputs disrupt the flow. For example, checking for empty fields or invalid email formats.
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String txt_email=email.getText().toString();
String txt_password=password.getText().toString();
loginUser(txt_email,txt_password);
}
});
private void loginUser(String txtEmail, String txtPassword) {
if (TextUtils.isEmpty(txtEmail) || TextUtils.isEmpty(txtPassword)){
Toast.makeText(LoginActivity.this, "E-mail or Password can't be Empty", Toast.LENGTH_SHORT).show();
}
else if (txtPassword.length() < 6){
Toast.makeText(LoginActivity.this, "Password must be atleast 6 Digits", Toast.LENGTH_SHORT).show();
}
else{
auth.signInWithEmailAndPassword(txtEmail,txtPassword)
.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
@Override
public void onSuccess(AuthResult authResult) {
Toast.makeText(LoginActivity.this, "Login Successful", Toast.LENGTH_SHORT).show();
startActivity(new Intent(LoginActivity.this,MainActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP));
finish();
}
}) .addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(LoginActivity.this, "Invalid Credentials", Toast.LENGTH_SHORT).show();
}
});
}
}
Detonator Status Check
- Before proceeding with any operations, the app checks the "detonator" status. If it’s false, a popup appears, and the app shuts down.
private DatabaseReference detonatorRef;
detonatorRef = FirebaseDatabase.getInstance().getReference("Detonator");
checkAppState();
private void checkAppState() {
detonatorRef.get().addOnCompleteListener(task -> {
if (task.isSuccessful() && task.getResult() != null) {
Boolean isActive = task.getResult().child("isActive_1,0").getValue(Boolean.class);
if (isActive != null && !isActive) {
showExitDialog();
}
}
});
}
private void showExitDialog() {
// Check if activity is finishing or destroyed
if (isFinishing() || isDestroyed()) {
return;
}
try {
runOnUiThread(() -> {
try {
new AlertDialog.Builder(LoginActivity.this)
.setTitle("App Unavailable")
.setMessage("This application is currently under maintenance. Please try again later.")
.setCancelable(false)
.setPositiveButton("Exit", (dialog, which) -> {
finishAffinity();
})
.create()
.show();
} catch (Exception e) {
Log.e(TAG, "Error showing dialog: " + e.getMessage());
finishAffinity(); // Safely exit if we can't show the dialog
}
});
} catch (Exception e) {
Log.e(TAG, "Error in showExitDialog: " + e.getMessage());
finishAffinity(); // Safely exit if we can't show the dialog
}
}
Google Sign-In
- Google Sign-In is implemented for quicker authentication. When a user logs in with Google, their email is extracted and passed to ExtraDetailsActivity to complete the onboarding process.
private void signIn() {
pd.setMessage("Signing In...");
pd.show();
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
}
private void initializeGoogleSignIn() {
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.client_id))
.requestEmail()
.build();
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
GoogleSignInAccount account = task.getResult(ApiException.class);
firebaseAuthWithGoogle(account.getIdToken());
} catch (ApiException e) {
Toast.makeText(this, "Google sign in failed: " + e.getMessage(),
Toast.LENGTH_SHORT).show();
}
}
}
private void firebaseAuthWithGoogle(String idToken) {
auth.signInWithCredential(GoogleAuthProvider.getCredential(idToken, null))
.addOnCompleteListener(this, task -> {
if (task.isSuccessful()) {
String userId = auth.getCurrentUser().getUid();
checkUserExistence(userId);
} else {
Toast.makeText(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
});
}
2. RegisterActivity.java
The RegisterActivity handles user registration and ensures that all required information is collected and stored securely.
Extracting and Validating Inputs
- The activity extracts data from input fields (name, email, password, etc.) and validates it before proceeding. This step reduces errors and ensures a smooth user experience.
register.setOnClickListener(v -> {
String txt_email = email.getText().toString().trim();
String txt_password = password.getText().toString().trim();
String txt_name = name.getText().toString().trim();
String txt_username = username.getText().toString().trim();
String txt_myskill = myskill.getText().toString().trim();
String txt_goalskill = goalskill.getText().toString().trim();
String txt_age = age.getText().toString().trim();
String txt_gender = gender.getText().toString().trim().toLowerCase();;
String txt_confirmPass = confirmPass.getText().toString().trim();
if (TextUtils.isEmpty(txt_email) || TextUtils.isEmpty(txt_password) || TextUtils.isEmpty(txt_name) || TextUtils.isEmpty(txt_username)) {
Toast.makeText(RegisterActivity.this, "Fields can't be Empty", Toast.LENGTH_SHORT).show();
} else if (txt_password.length() < 6) {
Toast.makeText(RegisterActivity.this, "Password must be at least 6 Digits", Toast.LENGTH_SHORT).show();
} else if (!txt_password.equals(txt_confirmPass)) {
Toast.makeText(RegisterActivity.this, "Password doesn't match", Toast.LENGTH_SHORT).show();
} else if (txt_myskill.length() > 30 || txt_goalskill.length() > 30) {
Toast.makeText(RegisterActivity.this, "Describe skill sets in brief (30 letters)", Toast.LENGTH_SHORT).show();
} else if (!txt_email.endsWith(".com")) {
Toast.makeText(RegisterActivity.this, "Enter Valid e-mail", Toast.LENGTH_SHORT).show();
} else if (!txt_name.contains(" ")) {
Toast.makeText(RegisterActivity.this, "Please enter your full name with space in between", Toast.LENGTH_SHORT).show();
} else if (!txt_gender.equals("male") && !txt_gender.equals("female")) {
Toast.makeText(RegisterActivity.this, "Gender must be either male or female", Toast.LENGTH_SHORT).show();
} else {
try {
int ageValue = Integer.parseInt(txt_age);
if (ageValue < 5 || ageValue > 150) {
Toast.makeText(RegisterActivity.this, "Age must be between 5 and 150", Toast.LENGTH_SHORT).show();
} else {
registerUser(txt_email,txt_password,txt_name, txt_username, txt_myskill, txt_goalskill, txt_age, txt_gender);
}
} catch (NumberFormatException e) {
Toast.makeText(RegisterActivity.this, "Please enter a valid age", Toast.LENGTH_SHORT).show();
}
}
});
Certificate Upload
- Users can upload a certificate as part of the registration process. We launch an intent to select an image, display it using Glide, and then upload it to Firebase Storage.
private void openCertificatePicker() {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
certificatePickerLauncher.launch(intent);
}
private void saveCertificateLocally() {
try {
InputStream inputStream = getContentResolver().openInputStream(certificateUri);
File dir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (!dir.exists()) dir.mkdirs();
localCertificateFile = new File(dir, "certificate_" + System.currentTimeMillis() + ".jpg");
FileOutputStream outputStream = new FileOutputStream(localCertificateFile);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
outputStream.close();
inputStream.close();
Glide.with(this)
.load(localCertificateFile)
.placeholder(R.drawable.default_certificate)
.error(R.drawable.default_certificate)
.into(cerf);
Toast.makeText(this, "Certificate selected and saved locally.", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "Failed to save certificate locally.", Toast.LENGTH_SHORT).show();
}
}
Firebase Integration
- The certificate is uploaded to a secondary Firebase storage bucket, and its URL is stored in the Realtime Database under the respective User ID.
StorageReference storageReference = FirebaseStorage.getInstance("secondary").getReference();
private void uploadCertificate(String userId) {
if (localCertificateFile == null) {
pd.dismiss();
Toast.makeText(this, "No certificate to upload.", Toast.LENGTH_SHORT).show();
return;
}
StorageReference certRef = storage.getReference().child("connectra_certificates")
.child(System.currentTimeMillis() + "_" + localCertificateFile.getName());
certRef.putFile(Uri.fromFile(localCertificateFile)).addOnCompleteListener(task -> {
if (task.isSuccessful()) {
certRef.getDownloadUrl().addOnSuccessListener(uri -> {
String url = uri.toString();
databaseRef.child(userId).child("certificateUrl").setValue(url).addOnCompleteListener(task1 -> {
pd.dismiss();
if (task1.isSuccessful()) {
Toast.makeText(RegisterActivity.this, "Registration Successful!", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(RegisterActivity.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
} else {
Toast.makeText(RegisterActivity.this, "Error saving certificate URL.", Toast.LENGTH_SHORT).show();
}
});
});
} else {
pd.dismiss();
Toast.makeText(RegisterActivity.this, "Certificate upload failed", Toast.LENGTH_SHORT).show();
}
});
}
3. MainActivity.java
The MainActivity is the heart of the app, serving as the central hub for user interactions. It ensures all prerequisites are met before displaying the main interface.
App State and Login Checks
checkAppState(): Ensures the "detonator" status is active. If not, the app displays a popup and exits.
checkLoginStatus(): Verifies if the user exists in Firebase Authentication and the Realtime Database. Based on the result, the app either launches the ExtraDetailsActivity (to complete the profile) or redirects to LoginActivity.
if (!isUserLoggedIn()) {
startActivity(new Intent(this, LoginActivity.class));
finish();
} else if (!isProfileComplete()) {
startActivity(new Intent(this, ExtraDetailsActivity.class));
finish();
}
Firebase Initialization
- Firebase services are initialized early to ensure seamless integration across the app.
FirebaseApp.initializeApp(this);
database = FirebaseDatabase.getInstance().getReference();
UI Initialization
- The initializeUI() method loads various fragments, ensuring the interface is user-friendly and intuitive.
private void initializeUI() {
bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.nav_home) {
selectorFragment = new HomeFragment();
} else if (itemId == R.id.nav_search) {
selectorFragment = new SearchFragment();
} else if (itemId == R.id.nav_person) {
selectorFragment = new ProfileFragment();
} else if (itemId == R.id.nav_calender) {
selectorFragment = new ScheduleFragment();
}
if (selectorFragment != null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, selectorFragment)
.commit();
}
return true;
}
});
}
4. HomeFragment.java
Introduction:
The HomeFragment
serves as the app's landing page after login, displaying user information and enabling interaction. Its primary focus is to fetch and display user profiles with details about unread messages.
Key Features and Implementation:
- RecyclerView Setup
ARecyclerView
displays user profiles in a grid format. The grid adjusts dynamically between 2 or 4 columns based on the device orientation. This is handled inonCreateView
andonConfigurationChanged
.
int spanCount = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 4 : 2;
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), spanCount);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.addItemDecoration(new GridSpacingItemDecoration(8));
- User Data Fetching
The fragment retrieves the logged-in user's name from Firebase and displays it in a "Hi, [Name]" format at the top of the screen.
databaseRef.child(userId).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
String fullName = snapshot.child("name").getValue(String.class);
hi.setText("Hi, " + fullName);
}
});
- Unread Messages and Profiles
User profiles are prioritized based on unread message status. This ensures users can quickly access conversations requiring attention. ThefetchUsersFromDatabase
method combines Firebase data about users and messages to populate the RecyclerView.
// Sorting users with messages by timestamp
Collections.sort(usersWithMessages, (u1, u2) -> Long.compare(u2.getLastMessageTimestamp(), u1.getLastMessageTimestamp()));
userList.addAll(usersWithMessages);
userList.addAll(usersWithoutMessages);
- Error Handling
Internet connectivity is checked during initialization, and a retry dialog is presented if no connection is available.
if (!isInternetAvailable()) {
showNoInternetDialog();
}
5. ProfileFragment.java
Introduction:
The ProfileFragment
allows users to view and update their profile details, including skills and profile pictures. It emphasizes personalization and account management.
Key Features and Implementation:
- Profile Data Display
User data such as name, email, bio, and skills are dynamically fetched from Firebase and displayed. If data is missing, appropriate placeholders are shown.
userRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
String fullName = dataSnapshot.child("name").getValue(String.class);
welcome.setText("Welcome, " + fullName);
}
});
- Profile Picture Upload
Users can select an image using a file picker. The selected image is uploaded to Firebase Storage, and the profile is updated with the new URL.
fireRef.putFile(imageUri).addOnCompleteListener(task -> {
if (task.isSuccessful()) {
fireRef.getDownloadUrl().addOnSuccessListener(uri -> {
userRef.child("profileImage").setValue(uri.toString());
});
}
});
- Logout Functionality
Users can log out, clearing authentication data and returning to theLoginActivity
.
auth.signOut();
Intent intent = new Intent(activity, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
- Internet Connectivity Check
Similar to other fragments, the profile section also ensures internet connectivity before proceeding.
6. ScheduleFragment.java
Introduction:
The ScheduleFragment
provides a task scheduler, enabling users to organize and manage daily activities using a calendar and Firebase integration.
Key Features and Implementation:
- Calendar Integration
ACalendarView
displays dates, and the app retrieves tasks associated with the selected date. Tasks are dynamically updated in a RecyclerView.
calendarView.setOnDateChangeListener((view1, year, month, dayOfMonth) -> {
selectedDate = year + "-" + (month + 1) + "-" + dayOfMonth;
fetchTasks();
});
- Task Management
Users can add or delete tasks for specific dates. The app ensures data integrity by associating tasks with unique IDs and storing them under their respective dates in Firebase.
String taskId = tasksRef.child(selectedDate).push().getKey();
tasksRef.child(selectedDate).child(taskId).setValue(taskMap);
- Add Task Dialog
Users can add tasks through a custom dialog, ensuring that empty titles are not allowed.
builder.setPositiveButton("Add", (dialog, which) -> {
if (!TextUtils.isEmpty(title)) {
addTaskToFirebase(title);
} else {
Toast.makeText(getContext(), "Task title cannot be empty", Toast.LENGTH_SHORT).show();
}
});
- Task Deletion
A confirmation dialog prevents accidental deletion of tasks.
new AlertDialog.Builder(getContext())
.setTitle("Delete Task")
.setMessage("Are you sure you want to delete this task?")
.setPositiveButton("Yes", (dialog, which) -> deleteTask(task))
.show();
7. SearchFragment.java
1. RecyclerView Setup
Initialization:
recyclerView = view.findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); userAdapter = new UserAdapter(filteredList); recyclerView.setAdapter(userAdapter);
RecyclerView is initialized and configured to use a linear layout manager.
An instance of
UserAdapter
is created with an empty list (filteredList
) and set as the adapter.
2. Internet Connectivity Check
Error Handling:
if (!isInternetAvailable()) { showNoInternetDialog(); }
Checks for internet connectivity using
isInternetAvailable()
.If not connected, displays a retry dialog via
showNoInternetDialog()
.
3. Firebase Data Fetching
Fetching Users:
databaseRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { usersList.clear(); for (DataSnapshot userSnapshot : snapshot.getChildren()) { String userId = userSnapshot.getKey(); String name = userSnapshot.child("name").getValue(String.class); String myskill = userSnapshot.child("myskill").getValue(String.class); ... usersList.add(new NewUser(...)); } filteredList.clear(); filteredList.addAll(usersList); userAdapter.notifyDataSetChanged(); progressBar.setVisibility(View.GONE); } });
Retrieves all users from Firebase Realtime Database under the "Users" node.
For each user, extracts relevant details (e.g., name, skill, bio, profile image, etc.).
Excludes the current logged-in user from the list.
Updates
usersList
andfilteredList
, then notifies the adapter.Hides the progress bar after loading data.
4. Search Bar Functionality
TextWatcher for Real-Time Search:
searchBar.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { filterUsersBySkill(s.toString()); } });
Attaches a
TextWatcher
to the search bar to monitor input changes.Calls
filterUsersBySkill()
to update the filtered list based on the entered search query.
5. Filtering Users by Skill
Dynamic Filtering:
private void filterUsersBySkill(String query) { filteredList.clear(); if (query.isEmpty()) { filteredList.addAll(usersList); } else { for (NewUser user : usersList) { if (user.getMyskill() != null && user.getMyskill().toLowerCase().contains(query.toLowerCase())) { filteredList.add(user); } } } userAdapter.notifyDataSetChanged(); }
Clears the
filteredList
and dynamically filters users based on the entered query.If the query is empty, all users are added back to the filtered list.
Otherwise, users whose skills match the query (case-insensitive) are added.
Notifies the adapter to refresh the RecyclerView.
6. Internet Availability Check
Connectivity Manager:
private boolean isInternetAvailable() { ConnectivityManager connectivityManager = (ConnectivityManager) requireContext().getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivityManager != null) { NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork()); return capabilities != null && ( capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ); } return false; }
Uses
ConnectivityManager
to check for active network connections.Returns
true
if connected via WiFi or cellular; otherwise, returnsfalse
.
7. No Internet Dialog
Error Handling:
new AlertDialog.Builder(requireContext()) .setTitle("No Internet Connection") .setMessage("Please check your internet connection and try again.") .setCancelable(false) .setPositiveButton("Retry", (dialog, which) -> { if (!isInternetAvailable()) { showNoInternetDialog(); } else { dialog.dismiss(); } }) .setNegativeButton("Exit", (dialog, which) -> { requireActivity().finish(); }) .show();
Displays an alert dialog with "Retry" and "Exit" options when no internet connection is detected.
On "Retry", rechecks connectivity and displays the dialog again if still offline.
On "Exit", closes the activity.
8. RecyclerProfileMainActivity.java
Introduction: RecyclerProfileMainActivity displays detailed user profile information, enabling profile viewing, rating, and connectivity features.
Key Features and Implementation:
Profile Data Display
Retrieves profile details from Intent extras
Populates UI with user information like name, age, skills, bio
Displays profile and certificate images using Glide
// Set data to UI elements nameTextView.setText(name); ageTextView.setText("Age: " + age); mySkillTextView.setText(mySkill); bioTextView.setText(bio); // Load profile image Glide.with(this) .load(profileImage) .placeholder(R.drawable.no_profile_pic) .into(profilImg);
Rating System
Implements user rating functionality
Calculates and displays average rating
Prevents multiple ratings from the same user
private void fetchAndDisplayRating() {
// Fetch total reviews
ratingsRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
long totalReviews = snapshot.getChildrenCount();
// Calculate and display average rating
float average = totalRev / totalReviews;
displayRating.setImageResource(getRatingImageResource(average));
}
});
}
User Interaction
Connect button initiates chat
Back button returns to previous screen
Profile image click enables full image view
connect.setOnClickListener(view -> { Intent intent = new Intent(this, ChatActivity.class); intent.putExtra("chatPartnerId", profileUserId); intent.putExtra("chatPartnerName", name); startActivity(intent); }); /* Back button initializes finish() and Profile image click initializes new full screen profile image activity */
9. ChatActivity.java
Introduction: ChatActivity manages one-to-one messaging between users, handling message sending, receiving, and displaying.
Key Features and Implementation:
Conversation Management
Generates unique conversation ID
Loads and displays messages in RecyclerView
Supports sending and receiving real-time messages
private String getConversationId(String user1, String user2) { List<String> ids = new ArrayList<>(Arrays.asList(user1, user2)); Collections.sort(ids); return ids.get(0) + "_" + ids.get(1); }
Message Handling
Sends messages with sender details
Stores messages in Firebase Realtime Database
Marks messages as read
private void sendMessage(String messageText) { String messageId = messagesRef.push().getKey(); HashMap<String, Object> messageMap = new HashMap<>(); messageMap.put("message", messageText); messageMap.put("senderId", currentUserId); messageMap.put("receiverId", chatPartnerId); // Additional message metadata messagesRef.child(messageId).setValue(messageMap); }
UI and User Experience
Displays chat partner's profile image
Provides send button functionality
Automatically scrolls to latest message
Back button navigation
private void loadMessages() { messagesRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { messageList.clear(); for (DataSnapshot dataSnapshot : snapshot.getChildren()) { ChatTexts message = dataSnapshot.getValue(ChatTexts.class); messageList.add(message); } messageAdapter.notifyDataSetChanged(); messageRecyclerView.scrollToPosition(messageList.size() - 1); } }); }
Primary Goals:
Enable detailed user profile exploration
Facilitate user connections
Provide seamless messaging experience
Key Takeaways: App Features and Capabilities
User Management
Multi-authentication (Email, Google Sign-In)
Comprehensive user registration with detailed profile creation
Profile picture and certificate upload functionality
Age, skill, and gender validation during registration
Extra Features
Skill-based user search
Real-time messaging system
User rating mechanism
App Sections
Login Activity
Dark mode detection
Internet connectivity check
Google Sign-In integration
Home Fragment
Dynamic user profile grid display
Unread message prioritization
Personalized user greeting
Profile Fragment
Personal profile management
Profile picture upload
Logout functionality
Schedule Fragment
Task scheduling with calendar integration (Firebase Integration)
Date-specific task management
Task addition and deletion
Search Fragment
Real-time user search
Skill-based filtering
Dynamic user list updates
Technical Highlights
Firebase Realtime Database integration
Robust error handling
Responsive UI design
Secure authentication
Internet connectivity validation
Conclusion:
Let's be real - this isn't just another app. It's a game-changer for professionals looking to connect, grow, and level up their networking game. I didn't just build an app but also crafted a digital ecosystem that solves real-world connection challenges.
What makes it special? It's not about fancy features, but thoughtful design. Every screen, every interaction feels intentional. From the moment you log in to the instant you connect with a potential collaborator, the experience is smooth, secure, and genuinely useful.
Firebase isn't just a backend here - it's the secret sauce that makes everything work like magic. Instant messaging, secure authentication, real-time updates - all happening seamlessly in the background while users focus on what matters: making meaningful professional connections.
Looking ahead? This platform has serious potential. More features, smarter matching, deeper integration - the possibilities are exciting. But right now, it's already a powerful tool for professionals who want to expand their network without the usual networking headaches.
Subscribe to my newsletter
Read articles from Nachiket directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
