Last active
November 21, 2025 14:47
-
-
Save sunmeat/faf7f97375fc91f8805f7251ece81795 to your computer and use it in GitHub Desktop.
content provider example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| треба додати клас 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