Урок 101. Создаем свой ContentProvider
Урок 101. Создаем свой ContentProvider
В этом уроке:
- создаем свой ContentProvider
Click here to read this article!
- создаем свой ContentProvider
Click here to read this article!
Последний раз редактировалось damager82 23 май 2017, 22:04, всего редактировалось 13 раз.
Re: Урок 101. Создаем свой ContentProvider
Спасибо, выцедил пару улучшений для своего ContentProvider'а, который был недавно мной написан.
У меня возник вопрос, в своем проекте я не могу использовать CursorAdapter, так как мне необходимо наполнять адаптер из нескольких курсоров. Возможно ли отловить событие обновления курсора и назначить свой обработчик? (к примеру как мы отлавливаем событие нажатия кнопки, но только для курсора).
У меня возник вопрос, в своем проекте я не могу использовать CursorAdapter, так как мне необходимо наполнять адаптер из нескольких курсоров. Возможно ли отловить событие обновления курсора и назначить свой обработчик? (к примеру как мы отлавливаем событие нажатия кнопки, но только для курсора).
Re: Урок 101. Создаем свой ContentProvider
Что то не въехал малёха. Не вижу большой разницы между ContentProvider'ом и SQLiteOpenHelper'ом. Всё что мы реализовываем (методы insert update delete и т.д.) можно реализовать и в SQLiteOpenHelper. Единственно что я понял так это что мы можем обратится из своего приложения к любой бд, я ж правильно понял?
R.id.team
Политика на форуме запрещена
Политика на форуме запрещена
Re: Урок 101. Создаем свой ContentProvider
rezak90
ContentProvider является посредником между данными (в нашем случае это БД) и приложениями. Так же он создается в единственном экземпляре, что дает следующие преимущества:
1) Открывается только одна копия источника данных (у нас это БД sqlite);
2) Позволяет сделать механизм синхронизации отображаемой информации и информации содержащийся в источнике.
Ну это только 2 пункта, что меня заставили писать в приложении собственную реализацию контент провайдера для данных.
ContentProvider является посредником между данными (в нашем случае это БД) и приложениями. Так же он создается в единственном экземпляре, что дает следующие преимущества:
1) Открывается только одна копия источника данных (у нас это БД sqlite);
2) Позволяет сделать механизм синхронизации отображаемой информации и информации содержащийся в источнике.
Ну это только 2 пункта, что меня заставили писать в приложении собственную реализацию контент провайдера для данных.
Re: Урок 101. Создаем свой ContentProvider
короче я так понял провайдер даёт возможность подключаться к бд более чем одному приложению? Но не понял можно ли получить данные из бд которую не знаешь (например указать имя бд и вытянуть от тудого все таблицы с полями, заведомо не зная названия таблиц и столбцов)? И ещё, можно ли присабачить провайдер и программу в одно приложение, а не как создавать в уроке.
ап, ещё вычитал что с помощу провайдеров могут общаться между собой приложения, было бы интересно на это посмотреть.
ап, ещё вычитал что с помощу провайдеров могут общаться между собой приложения, было бы интересно на это посмотреть.
R.id.team
Политика на форуме запрещена
Политика на форуме запрещена
Re: Урок 101. Создаем свой ContentProvider
Принципиально прав, но я бы сказал, что он дает подключиться к БД более чем одному процессу.rezak90 писал(а):короче я так понял провайдер даёт возможность подключаться к бд более чем одному приложению?
Тут скорей всего вопрос в правильном построении SQL запроса.rezak90 писал(а):Но не понял можно ли получить данные из бд которую не знаешь (например указать имя бд и вытянуть от тудого все таблицы с полями, заведомо не зная названия таблиц и столбцов)?
Лично у меня оно так и сделано в моем приложении, а ещё у меня запрещено другим приложениям, кроме моего, обращаться к моему контент провайдеру.rezak90 писал(а): И ещё, можно ли присабачить провайдер и программу в одно приложение, а не как создавать в уроке.
Когда с ними разберешься, то такое можно организовать.rezak90 писал(а): ап, ещё вычитал что с помощу провайдеров могут общаться между собой приложения, было бы интересно на это посмотреть.
Re: Урок 101. Создаем свой ContentProvider
я так понял что getContentResolver() возвращает все провайдеры которые есть в Android'e. В общем как например вытащить все названия провайдеров которые функционируют на данный момент в системе, не зная их названия.
R.id.team
Политика на форуме запрещена
Политика на форуме запрещена
Re: Урок 101. Создаем свой ContentProvider
getContentResolver() - это интерфейс, что ищет нужного контент провайдера по Uri.rezak90 писал(а):я так понял что getContentResolver() возвращает все провайдеры которые есть в Android'e. В общем как например вытащить все названия провайдеров которые функционируют на данный момент в системе, не зная их названия.
Re: Урок 101. Создаем свой ContentProvider
Уже хотел накатать сюда огромный пост по одной проблеме, как вдруг осенило))) Как то после каждого обращения к бд я всё время закрывал подключения с ней, а потом курсор получался с возвратом null и не мог понять почему так. Такой себе вопрос для рассуждения: почему каждый раз открывается новое соединение с бд и не закрывается? Не влияет ли это на производительность? И вообще правильно ли это с точки зрения архитектуры? Или я может чего то не уловил...
R.id.team
Политика на форуме запрещена
Политика на форуме запрещена
Re: Урок 101. Создаем свой ContentProvider
всё время выходит путанница с айди. Вот у меня такой адрес "ua.my.providers.Supershop/sneakers/" где sneakers - название таблицы. Если обращаюсь по адресу "ua.my.providers.Supershop/sneakers/33" то uMatcher.match(uri) возвращает мне цифру 2 всегда, мне почему то казалось что метод match возвращает то что стоит в конце или же после названия таблицы, он берёт от куда то двойку. Сам UriMatcher такой:
Код: Выделить всё
uMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uMatcher.addURI(AUTHORITY, TABLE_NAME, 1);
uMatcher.addURI(AUTHORITY, TABLE_NAME + "/#", 2);
R.id.team
Политика на форуме запрещена
Политика на форуме запрещена
Re: Урок 101. Создаем свой ContentProvider
Он тебе правильно возвращает 2.rezak90 писал(а):всё время выходит путанница с айди. Вот у меня такой адрес "ua.my.providers.Supershop/sneakers/" где sneakers - название таблицы. Если обращаюсь по адресу "ua.my.providers.Supershop/sneakers/33" то uMatcher.match(uri) возвращает мне цифру 2 всегда, мне почему то казалось что метод match возвращает то что стоит в конце или же после названия таблицы, он берёт от куда то двойку. Сам UriMatcher такой:Код: Выделить всё
uMatcher = new UriMatcher(UriMatcher.NO_MATCH); uMatcher.addURI(AUTHORITY, TABLE_NAME, 1); uMatcher.addURI(AUTHORITY, TABLE_NAME + "/#", 2);
В методе ты делаешь:
Код: Выделить всё
// Вычисляем какая таблица нужна.
switch (uriMatcher.match(uri)){
case 1:
uTable = TABLE_NAME;
break;
case 2:
uTable = TABLE_NAME;
// Получаем id необходимой строки
uID = uri.getLastPathSegment();
break;
}
Re: Урок 101. Создаем свой ContentProvider
а понял, ошибка была в самом запросе, нужно было не "ua.my.providers.Supershop/sneakers/33" а просто "ua.my.providers.Supershop/sneakers", то есть не ставить палку после названия таблицы, а так UriMatcher определял как айди столбца, а не всю таблицу.
R.id.team
Политика на форуме запрещена
Политика на форуме запрещена
Re: Урок 101. Создаем свой ContentProvider
У меня возник вопрос, на который я никак не могу найти ответ, у меня довольно большая структура БД, и порядка 15 таблиц, мне необходимо писать для каждой своего провайдера, либо лепить все в один, и использовать кейсы?
Re: Урок 101. Создаем свой ContentProvider
и ещё один вопрос: если кто-то сможет разобраться с запросами к моему провайдеру, то без проблем сможет курочить мою БД своим приложением? как от этого защищаться?
Re: Урок 101. Создаем свой ContentProvider
Я не знаю, заметили или нет те кто смотрел этот урок, в отличие от SQLiteOpenHelper'а, обращение к базе при помощи своего ContentProvider'а позволяет
делать оповещения о сделанных изменениях. Эти оповещения в дальнейшем можно обрабатывать. Код где оповещения:
getContext().getContentResolver().notifyChange(uri, null);
делать оповещения о сделанных изменениях. Эти оповещения в дальнейшем можно обрабатывать. Код где оповещения:
getContext().getContentResolver().notifyChange(uri, null);
Re: Урок 101. Создаем свой ContentProvider
"У нас тут получилось, что имя таблицы в БД совпало с path в Uri. Это вовсе необязательно, они могут быть разными."
Если не ошибаюсь, если они будут разными, то в вашем примере будет IllegalArgumentException("Wrong URI: " + uri);
Потому что uri придет вида "content://ru.startandroid.providers.AdressBook/contacts" исходя из этой строчки
public static final Uri CONTACT_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + CONTACT_PATH);
а UriMatcher будет сравнивать её с чем нибудь вроде "content://ru.startandroid.providers.AdressBook/contacts_db" изходя из этого:
uriMatcher.addURI(AUTHORITY, CONTACT_TABLE, URI_CONTACTS);
Или я не правильно что то понял, но у меня не работает.
Если не ошибаюсь, если они будут разными, то в вашем примере будет IllegalArgumentException("Wrong URI: " + uri);
Потому что uri придет вида "content://ru.startandroid.providers.AdressBook/contacts" исходя из этой строчки
public static final Uri CONTACT_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + CONTACT_PATH);
а UriMatcher будет сравнивать её с чем нибудь вроде "content://ru.startandroid.providers.AdressBook/contacts_db" изходя из этого:
uriMatcher.addURI(AUTHORITY, CONTACT_TABLE, URI_CONTACTS);
Или я не правильно что то понял, но у меня не работает.
Re: Урок 101. Создаем свой ContentProvider
Верно, у меня ошибка в уроке. Вместоgh-gh писал(а):"У нас тут получилось, что имя таблицы в БД совпало с path в Uri. Это вовсе необязательно, они могут быть разными."
Если не ошибаюсь, если они будут разными, то в вашем примере будет IllegalArgumentException("Wrong URI: " + uri);
[syntax=java] uriMatcher.addURI(AUTHORITY, CONTACT_TABLE, URI_CONTACTS);
uriMatcher.addURI(AUTHORITY, CONTACT_TABLE + "/#", URI_CONTACTS_ID);[/syntax]
Надо
[syntax=java] uriMatcher.addURI(AUTHORITY, CONTACT_PATH, URI_CONTACTS);
uriMatcher.addURI(AUTHORITY, CONTACT_PATH+ "/#", URI_CONTACTS_ID);[/syntax]
Спасибо, что написали об этом!
Re: Урок 101. Создаем свой ContentProvider
Здравствуйте =)
вроде бы все делаю по уроку, однако программа при запуске сразу выдает ошибку =(
вроде бы все делаю по уроку, однако программа при запуске сразу выдает ошибку =(
Код: Выделить всё
04-30 14:53:15.150: D/dalvikvm(2455): GC_CONCURRENT freed 56K, 7% free 2803K/3004K, paused 18ms+5ms, total 72ms
04-30 14:53:15.150: D/AndroidRuntime(2455): Shutting down VM
04-30 14:53:15.150: W/dalvikvm(2455): threadid=1: thread exiting with uncaught exception (group=0x40a71930)
04-30 14:53:15.170: E/AndroidRuntime(2455): FATAL EXCEPTION: main
04-30 14:53:15.170: E/AndroidRuntime(2455): java.lang.RuntimeException: Unable to start activity ComponentInfo{ru.startandroid.develop.contprovclient/ru.startandroid.develop.contprovclient.MainActivity}: java.lang.SecurityException: Permission Denial: opening provider ru.startandroid.develop.contentprovider.MyContactProvider from ProcessRecord{41718cd8 2455:ru.startandroid.develop.contprovclient/u0a10047} (pid=2455, uid=10047) that is not exported from uid 10046
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.access$600(ActivityThread.java:141)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.os.Handler.dispatchMessage(Handler.java:99)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.os.Looper.loop(Looper.java:137)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.main(ActivityThread.java:5041)
04-30 14:53:15.170: E/AndroidRuntime(2455): at java.lang.reflect.Method.invokeNative(Native Method)
04-30 14:53:15.170: E/AndroidRuntime(2455): at java.lang.reflect.Method.invoke(Method.java:511)
04-30 14:53:15.170: E/AndroidRuntime(2455): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
04-30 14:53:15.170: E/AndroidRuntime(2455): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
04-30 14:53:15.170: E/AndroidRuntime(2455): at dalvik.system.NativeStart.main(Native Method)
04-30 14:53:15.170: E/AndroidRuntime(2455): Caused by: java.lang.SecurityException: Permission Denial: opening provider ru.startandroid.develop.contentprovider.MyContactProvider from ProcessRecord{41718cd8 2455:ru.startandroid.develop.contprovclient/u0a10047} (pid=2455, uid=10047) that is not exported from uid 10046
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.os.Parcel.readException(Parcel.java:1425)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.os.Parcel.readException(Parcel.java:1379)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:2545)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.acquireProvider(ActivityThread.java:4462)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2002)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1101)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.content.ContentResolver.query(ContentResolver.java:356)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.content.ContentResolver.query(ContentResolver.java:315)
04-30 14:53:15.170: E/AndroidRuntime(2455): at ru.startandroid.develop.contprovclient.MainActivity.onCreate(MainActivity.java:29)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.Activity.performCreate(Activity.java:5104)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
04-30 14:53:15.170: E/AndroidRuntime(2455): ... 11 more
Re: Урок 101. Создаем свой ContentProvider
У меня была похожая ошибка.Mill666 писал(а):Здравствуйте =)
вроде бы все делаю по уроку, однако программа при запуске сразу выдает ошибку =(Код: Выделить всё
04-30 14:53:15.150: D/dalvikvm(2455): GC_CONCURRENT freed 56K, 7% free 2803K/3004K, paused 18ms+5ms, total 72ms 04-30 14:53:15.150: D/AndroidRuntime(2455): Shutting down VM 04-30 14:53:15.150: W/dalvikvm(2455): threadid=1: thread exiting with uncaught exception (group=0x40a71930) 04-30 14:53:15.170: E/AndroidRuntime(2455): FATAL EXCEPTION: main 04-30 14:53:15.170: E/AndroidRuntime(2455): java.lang.RuntimeException: Unable to start activity ComponentInfo{ru.startandroid.develop.contprovclient/ru.startandroid.develop.contprovclient.MainActivity}: java.lang.SecurityException: Permission Denial: opening provider ru.startandroid.develop.contentprovider.MyContactProvider from ProcessRecord{41718cd8 2455:ru.startandroid.develop.contprovclient/u0a10047} (pid=2455, uid=10047) that is not exported from uid 10046 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.access$600(ActivityThread.java:141) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.os.Handler.dispatchMessage(Handler.java:99) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.os.Looper.loop(Looper.java:137) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.main(ActivityThread.java:5041) 04-30 14:53:15.170: E/AndroidRuntime(2455): at java.lang.reflect.Method.invokeNative(Native Method) 04-30 14:53:15.170: E/AndroidRuntime(2455): at java.lang.reflect.Method.invoke(Method.java:511) 04-30 14:53:15.170: E/AndroidRuntime(2455): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 04-30 14:53:15.170: E/AndroidRuntime(2455): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 04-30 14:53:15.170: E/AndroidRuntime(2455): at dalvik.system.NativeStart.main(Native Method) 04-30 14:53:15.170: E/AndroidRuntime(2455): Caused by: java.lang.SecurityException: Permission Denial: opening provider ru.startandroid.develop.contentprovider.MyContactProvider from ProcessRecord{41718cd8 2455:ru.startandroid.develop.contprovclient/u0a10047} (pid=2455, uid=10047) that is not exported from uid 10046 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.os.Parcel.readException(Parcel.java:1425) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.os.Parcel.readException(Parcel.java:1379) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:2545) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.acquireProvider(ActivityThread.java:4462) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2002) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1101) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.content.ContentResolver.query(ContentResolver.java:356) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.content.ContentResolver.query(ContentResolver.java:315) 04-30 14:53:15.170: E/AndroidRuntime(2455): at ru.startandroid.develop.contprovclient.MainActivity.onCreate(MainActivity.java:29) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.Activity.performCreate(Activity.java:5104) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080) 04-30 14:53:15.170: E/AndroidRuntime(2455): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144) 04-30 14:53:15.170: E/AndroidRuntime(2455): ... 11 more
Помогло добавить в тег <provider> манифеста строку:
android:exported="true"
Мой тег <provider> теперь выглядит так:
<provider
android:name="MyContactsProvider"
android:authorities="ru.startandroid.providers.AdressBook"
android:exported="true" >
</provider>
Re: Урок 101. Создаем свой ContentProvider
В AndroidManifest.xml указываем exported = false. При этом провайдер должен быть объявлен в самом приложении, а не как в уроке отдельно.Ant писал(а):и ещё один вопрос: если кто-то сможет разобраться с запросами к моему провайдеру, то без проблем сможет курочить мою БД своим приложением? как от этого защищаться?
Код: Выделить всё
<provider
android:name="[i]provider_name[/i]"
android:authorities="[i]provider_authorities[/i]"
android:exported="false">
</provider>
Значение свойства exported определяет, доступен ли provider из других приложений.android:exported
Whether the content provider is available for other applications to use:
true: The provider is available to other applications. Any application can use the provider's content URI to access it, subject to the permissions specified for the provider.
false: The provider is not available to other applications. Set android:exported="false" to limit access to the provider to your applications. Only applications that have the same user ID (UID) as the provider will have access to it.
The default value is "true" for applications that set either android:minSdkVersion or android:targetSdkVersion to "16" or lower. For applications that set either of these attributes to "17" or higher, the default is "false".
You can set android:exported="false" and still limit access to your provider by setting permissions with the permission attribute.
true: provider доступен из других приложений через URI.
false: provider не доступен из других приложений. При это доступ из приложений с одинаковым user ID (подпись автора???) сохраняется.
Самое интересное: для приложений с API <= 16 значение по умолчанию "true", для API > 16 -- "false".
Источник: http://developer.android.com/guide/topi ... ement.html.