Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ dependencies {
implementation libs.androidx.room.runtime
annotationProcessor libs.androidx.room.compiler
annotationProcessor libs.glide.compiler
implementation libs.retrofit2
implementation libs.retrofit2.converter.gson

// Testing
testImplementation libs.junit
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,18 @@
android:label="@string/room_database"
android:parentActivityName=".ui.screens.android.lessons.data.room.RoomActivity" />

<activity
android:name=".ui.screens.android.lessons.networking.retrofit.RetrofitActivity"
android:exported="false"
android:label="@string/retrofit"
android:parentActivityName=".ui.screens.main.MainActivity" />

<activity
android:name=".ui.screens.android.lessons.networking.retrofit.RetrofitCodeActivity"
android:exported="false"
android:label="@string/retrofit"
android:parentActivityName=".ui.screens.android.lessons.networking.retrofit.RetrofitActivity" />

<activity
android:name=".ui.screens.settings.SettingsActivity"
android:exported="false"
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/assets/quiz_questions.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,10 @@
"question": "What component shows a scrollable list of items?",
"options": ["RecyclerView", "TextView", "ImageView", "Button"],
"answer": 0
},
{
"question": "Which library simplifies HTTP requests by turning APIs into interfaces?",
"options": ["Volley", "Retrofit", "Glide", "Room"],
"answer": 1
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.networking.retrofit;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;

import androidx.annotation.Nullable;

import com.d4rk.androidtutorials.java.databinding.ActivityRetrofitBinding;
import com.d4rk.androidtutorials.java.ui.components.navigation.UpNavigationActivity;
import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate;

import com.d4rk.androidtutorials.java.R;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;

/**
* Demonstrates a simple HTTP request using Retrofit.
*/
public class RetrofitActivity extends UpNavigationActivity {
private ActivityRetrofitBinding binding;
private final Handler handler = new Handler(Looper.getMainLooper());
private JsonPlaceholderApi api;

interface JsonPlaceholderApi {
@GET("todos/1")
Call<Todo> getTodo();
}

static class Todo {
public String title;
}

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityRetrofitBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

EdgeToEdgeDelegate edgeToEdgeDelegate = new EdgeToEdgeDelegate(this);
edgeToEdgeDelegate.applyEdgeToEdge(binding.constraintLayout);

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
api = retrofit.create(JsonPlaceholderApi.class);

binding.buttonFetch.setOnClickListener(v -> {
binding.buttonFetch.setEnabled(false);
api.getTodo().enqueue(new Callback<Todo>() {
@Override
public void onResponse(Call<Todo> call, Response<Todo> response) {
if (response.isSuccessful() && response.body() != null) {
binding.textViewResult.setText(response.body().title);
} else {
binding.textViewResult.setText(R.string.snack_general_error);
}
binding.buttonFetch.setEnabled(true);
}

@Override
public void onFailure(Call<Todo> call, Throwable t) {
binding.textViewResult.setText(R.string.snack_general_error);
binding.buttonFetch.setEnabled(true);
}
});
});

binding.floatingButtonShowSyntax.setOnClickListener(v ->
startActivity(new Intent(RetrofitActivity.this, RetrofitCodeActivity.class)));
handler.postDelayed(() -> binding.floatingButtonShowSyntax.shrink(), 5000);
}

@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.networking.retrofit;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import com.d4rk.androidtutorials.java.R;
import com.d4rk.androidtutorials.java.databinding.ActivityTabLayoutBinding;
import com.d4rk.androidtutorials.java.ui.components.navigation.UpNavigationActivity;
import com.d4rk.androidtutorials.java.ui.screens.android.lessons.networking.retrofit.tabs.RetrofitTabCodeFragment;
import com.d4rk.androidtutorials.java.ui.screens.android.lessons.networking.retrofit.tabs.RetrofitTabLayoutFragment;
import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate;
import com.google.android.material.tabs.TabLayoutMediator;

import java.util.ArrayList;

/**
* Displays Java and XML snippets for the Retrofit example.
*/
public class RetrofitCodeActivity extends UpNavigationActivity {
private ActivityTabLayoutBinding binding;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityTabLayoutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

EdgeToEdgeDelegate edgeToEdgeDelegate = new EdgeToEdgeDelegate(this);
edgeToEdgeDelegate.applyEdgeToEdge(binding.appBarLayout);

setupViewPager();

new TabLayoutMediator(binding.tabs, binding.viewpager, (tab, position) -> {
ViewPagerAdapter adapter = (ViewPagerAdapter) binding.viewpager.getAdapter();
if (adapter != null) {
tab.setText(adapter.getPageTitle(position));
}
}).attach();
}

private void setupViewPager() {
ViewPagerAdapter adapter = new ViewPagerAdapter(this);
adapter.addFragment(new RetrofitTabCodeFragment(), getString(R.string.code_java));
adapter.addFragment(new RetrofitTabLayoutFragment(), getString(R.string.layout_xml));
binding.viewpager.setAdapter(adapter);
}

private static class ViewPagerAdapter extends FragmentStateAdapter {
private final ArrayList<Fragment> fragmentList = new ArrayList<>();
private final ArrayList<String> fragmentTitleList = new ArrayList<>();

ViewPagerAdapter(@NonNull UpNavigationActivity activity) {
super(activity);
}

void addFragment(@NonNull Fragment fragment, @NonNull String title) {
fragmentList.add(fragment);
fragmentTitleList.add(title);
}

@NonNull
@Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}

@Override
public int getItemCount() {
return fragmentList.size();
}

CharSequence getPageTitle(int position) {
return fragmentTitleList.get(position);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.networking.retrofit.tabs;

import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.preference.PreferenceManager;

import com.d4rk.androidtutorials.java.R;
import com.d4rk.androidtutorials.java.databinding.FragmentCodeBinding;
import com.d4rk.androidtutorials.java.utils.CodeHighlighter;
import com.d4rk.androidtutorials.java.utils.CodeViewUtils;
import com.d4rk.androidtutorials.java.utils.FontManager;
import com.google.android.gms.ads.AdRequest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import me.zhanghai.android.fastscroll.FastScrollerBuilder;

/**
* Shows the Java implementation for the Retrofit example.
*/
public class RetrofitTabCodeFragment extends Fragment {

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
FragmentCodeBinding binding = FragmentCodeBinding.inflate(inflater, container, false);
new FastScrollerBuilder(binding.scrollView).useMd2Style().build();
binding.adView.loadAd(new AdRequest.Builder().build());

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
Typeface monospaceFont = FontManager.getMonospaceFont(requireContext(), prefs);
CodeViewUtils.applyDefaults(monospaceFont, binding.codeView);

StringBuilder builder = new StringBuilder();
InputStream inputStream = getResources().openRawResource(R.raw.text_retrofit_java);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append('\n');
}
binding.codeView.setText(builder.toString());
CodeHighlighter.applyJavaTheme(binding.codeView);
} catch (IOException e) {
Log.e("RetrofitTabCode", "Error reading code", e);
}
return binding.getRoot();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.networking.retrofit.tabs;

import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.preference.PreferenceManager;

import com.d4rk.androidtutorials.java.R;
import com.d4rk.androidtutorials.java.databinding.FragmentLayoutBinding;
import com.d4rk.androidtutorials.java.utils.CodeHighlighter;
import com.d4rk.androidtutorials.java.utils.CodeViewUtils;
import com.d4rk.androidtutorials.java.utils.FontManager;
import com.google.android.gms.ads.AdRequest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import me.zhanghai.android.fastscroll.FastScrollerBuilder;

/**
* Shows the XML layout for the Retrofit example.
*/
public class RetrofitTabLayoutFragment extends Fragment {

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
FragmentLayoutBinding binding = FragmentLayoutBinding.inflate(inflater, container, false);
new FastScrollerBuilder(binding.scrollView).useMd2Style().build();
binding.adView.loadAd(new AdRequest.Builder().build());

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
Typeface monospaceFont = FontManager.getMonospaceFont(requireContext(), prefs);
CodeViewUtils.applyDefaults(monospaceFont, binding.codeView);

StringBuilder builder = new StringBuilder();
InputStream inputStream = getResources().openRawResource(R.raw.text_retrofit_xml);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append('\n');
}
binding.codeView.setText(builder.toString());
CodeHighlighter.applyXmlTheme(binding.codeView);
} catch (IOException e) {
Log.e("RetrofitTabLayout", "Error reading layout", e);
}
return binding.getRoot();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public com.d4rk.androidtutorials.java.data.repository.LessonRepository.Lesson ge
new com.d4rk.androidtutorials.java.data.repository.LessonRepository.Lesson(R.string.grid_view, R.raw.text_grid_view_java, R.raw.text_grid_view_xml);
case "WebView" ->
new com.d4rk.androidtutorials.java.data.repository.LessonRepository.Lesson(R.string.web_view, R.raw.text_webview_java, R.raw.text_webview_xml);
case "Retrofit" ->
new com.d4rk.androidtutorials.java.data.repository.LessonRepository.Lesson(R.string.retrofit, R.raw.text_retrofit_java, R.raw.text_retrofit_xml);
case "BottomNavigation" ->
new com.d4rk.androidtutorials.java.data.repository.LessonRepository.Lesson(R.string.bottom_navigation, R.raw.text_bottom_navigation_java, R.raw.text_bottom_navigation_xml);
case "NavigationDrawer" ->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorSecondary"
android:pathData="M6.5,20Q5.88,20 5.44,19.56Q5,19.12 5,18.5L5,15.5Q5,14.88 5.44,14.44Q5.88,14 6.5,14Q7.12,14 7.56,14.44Q8,14.88 8,15.5L8,18.5Q8,19.12 7.56,19.56Q7.12,20 6.5,20ZM12.5,20Q11.88,20 11.44,19.56Q11,19.12 11,18.5L11,10.5Q11,9.88 11.44,9.44Q11.88,9 12.5,9Q13.12,9 13.56,9.44Q14,9.88 14,10.5L14,18.5Q14,19.12 13.56,19.56Q13.12,20 12.5,20ZM18.5,20Q17.88,20 17.44,19.56Q17,19.12 17,18.5L17,5.5Q17,4.88 17.44,4.44Q17.88,4 18.5,4Q19.12,4 19.56,4.44Q20,4.88 20,5.5L20,18.5Q20,19.12 19.56,19.56Q19.12,20 18.5,20Z"/>
</vector>
53 changes: 53 additions & 0 deletions app/src/main/res/layout/activity_retrofit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.google.android.material.textview.MaterialTextView
android:id="@+id/textViewSummary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/summary_retrofit"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.button.MaterialButton
android:id="@+id/buttonFetch"
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/fetch_data"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textViewSummary" />

<com.google.android.material.textview.MaterialTextView
android:id="@+id/textViewResult"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:padding="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/buttonFetch" />

<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/floating_button_show_syntax"
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:contentDescription="@string/tooltip_show_java_code_snippet"
android:text="@string/show_code"
android:textSize="14sp"
android:tooltipText="@string/tooltip_show_java_code_snippet"
app:icon="@drawable/ic_code"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
Loading
Loading