Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Last active November 21, 2025 14:47
Show Gist options
  • Select an option

  • Save sunmeat/faf7f97375fc91f8805f7251ece81795 to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/faf7f97375fc91f8805f7251ece81795 to your computer and use it in GitHub Desktop.
content provider example
треба додати клас ContentProvider в перший додаток (той, що з Room)
StudentContentProvider.java:
package site.sunmeat.helloworld;
import android.content.*;
import android.database.Cursor;
import android.net.Uri;
import androidx.annotation.*;
import androidx.room.Room;
import java.util.Objects;
public class StudentContentProvider extends ContentProvider {
// authority - це унікальне ім'я провайдера (має збігатися в обох додатках!)
public static final String AUTHORITY = "site.sunmeat.helloworld.provider";
// шляхи доступу до ресурсів
private static final String PATH_STUDENTS = "students";
private static final String PATH_STUDENTS_ID = "students/#";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + PATH_STUDENTS);
// якщо прийшов Uri виду content://site.sunmeat.helloworld.provider/students >> повернеться код 100
// якщо прийшов Uri виду content://site.sunmeat.helloworld.provider/students/8 (будь-яке число) >> повернеться код 101
private static final int CODE_STUDENTS = 100;
private static final int CODE_STUDENT_ID = 101;
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
uriMatcher.addURI(AUTHORITY, PATH_STUDENTS, CODE_STUDENTS);
uriMatcher.addURI(AUTHORITY, PATH_STUDENTS + "/#", CODE_STUDENT_ID);
}
private AppDatabase database;
@Override
public boolean onCreate() {
database = Room.databaseBuilder(Objects.requireNonNull(getContext()).getApplicationContext(),
AppDatabase.class, "student_database")
// .allowMainThreadQueries() // тільки для прикладу! в реальному коді — не треба
.build();
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder) {
Cursor cursor = switch (uriMatcher.match(uri)) { // switch expression
case CODE_STUDENTS -> database.studentDao()
.getAllStudentsBlocking(); // синхронний метод в DAO
case CODE_STUDENT_ID -> {
long id = ContentUris.parseId(uri);
yield database.studentDao().getStudentByIdBlocking(id);
}
default -> throw new IllegalArgumentException("Unknown URI: " + uri);
};
if (getContext() != null) {
cursor.setNotificationUri(getContext().getContentResolver(), uri);
}
return cursor;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return switch (uriMatcher.match(uri)) {
case CODE_STUDENTS -> "vnd.android.cursor.dir/vnd." + AUTHORITY + "." + PATH_STUDENTS;
case CODE_STUDENT_ID ->
"vnd.android.cursor.item/vnd." + AUTHORITY + "." + PATH_STUDENTS;
default -> throw new IllegalArgumentException("Unknown URI: " + uri);
};
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
// поки що не реалізуємо запис ззовні (можна додати)
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values,
@Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
=====================================================================================================================
оновлення StudentDao.java:
@Dao // DAO (Data Access Object) - це інтерфейс, який відповідає за всі операції з базою даних
// для таблиці "students". Room автоматично згенерує реалізацію цього інтерфейсу під час компіляції
interface StudentDao {
@Insert void insert(Student student);
@Query("SELECT * FROM students ORDER BY lastName") LiveData<List<Student>> getAllStudents(); // клас з Android Architecture Components,
// який дозволяє спостерігати за даними і автоматично оновлювати UI, коли вони змінюються
@Query("DELETE FROM students") void deleteAll();
@Query("SELECT * FROM students ORDER BY lastName")
List<Student> getAllStudentsBlockingList(); // новий
@Query("SELECT * FROM students ORDER BY lastName")
Cursor getAllStudentsBlocking(); // цей для ContentProvider
@Query("SELECT * FROM students WHERE _id = :id")
Cursor getStudentByIdBlocking(long id);
}
=====================================================================================================================
реєстрація провайдера в маніфесті (над activity):
<provider
android:name=".StudentContentProvider"
android:authorities="site.sunmeat.helloworld.provider"
android:enabled="true"
android:exported="true"
android:grantUriPermissions="true"
/>
=====================================================================================================================
ДРУГИЙ ДОДАТОК!
activity_main.xml:
<?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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Студенти з іншого додатка:"
android:textSize="20sp"
android:textStyle="bold" />
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp" />
</LinearLayout>
=====================================================================================================================
ДРУГИЙ ДОДАТОК!
MainActivity.java:
package site.sunmeat.services;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.widget.*;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private static final Uri STUDENTS_URI = Uri.parse(
"content://site.sunmeat.helloworld.provider/students");
private SimpleCursorAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = findViewById(R.id.listView);
// колонки, які ми хочемо показати
String[] from = {"firstName", "lastName"};
int[] to = {android.R.id.text1, android.R.id.text2};
adapter = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_2,
null,
from,
to,
0);
listView.setAdapter(adapter);
loadStudents();
}
private void loadStudents() {
// запит даних через ContentResolver
Cursor cursor = null;
try {
cursor = getContentResolver().query(
STUDENTS_URI,
null, null, null, null);
if (cursor != null) {
adapter.swapCursor(cursor);
} else {
Toast.makeText(this, "Немає доступу до даних або додаток не встановлений", Toast.LENGTH_LONG).show();
}
} catch (SecurityException e) {
Toast.makeText(this, "Немає дозволу! Перевірте, чи перший додаток встановлений", Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "Помилка: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
=====================================================================================================================
ДРУГИЙ ДОДАТОК!
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<queries>
<package android:name="site.sunmeat.helloworld" />
</queries>
<application...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment