Урок 101. Создаем свой ContentProvider

Обсуждение уроков
allexan
Сообщения: 23
Зарегистрирован: 03 июл 2014, 16:32

Re: Урок 101. Создаем свой ContentProvider

Сообщение allexan » 08 авг 2014, 09:56

Разобрался с проблемой, но одно мне непонятно: судя по логам метод onCreate() провайдера выполняется при каждом запуске приложения

Код: Выделить всё

public boolean onCreate() {
		// TODO Auto-generated method stub
		Log.d(LOG_TAG, "--- onCreate ---");
		DBHelper dbH = new DBHelper(getContext());
		db = dbH.getWritableDatabase(); 
		return false;
	}
Я был уверен, что соединение с базой установлено и каждый метод провайдера может этой базой пользоваться,
однако оказалось, что соединение с базой должно быть в каждом методе, например

Код: Выделить всё

public Uri insert(Uri arg0, ContentValues arg1) {
		// TODO Auto-generated method stub
		Log.d(LOG_TAG,"--- insert ---");
		DBHelper dbH = new DBHelper(getContext());
		db = dbH.getWritableDatabase();
		db.insert("my_table", null, arg1);
		return null;
	}
После этого все заработало

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Урок 101. Создаем свой ContentProvider

Сообщение Foenix » 08 авг 2014, 11:27

ссылки в подписи
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

dimitrius
Сообщения: 17
Зарегистрирован: 21 авг 2014, 12:47

Re: Урок 101. Создаем свой ContentProvider

Сообщение dimitrius » 30 окт 2014, 17:28

Уважаемые коллеги, подскажите как правильно добавлять поля в данную таблицу

Ибо если просто дописываешь по одноименной константе в провайдер и клиент,дописываешь в скрипт создания таблицы дополнительное поле, дополняешь массивы from to соответствующим полем, прописываем по cv паре в методы onClickInsert, onClickUpdate, то выдает ошибку -

java.lang.illegalargumentexception column "login" does not exist

Вот код класса MyContactsProvider.java:

Код: Выделить всё

package ru.startandroid.develop.p1011contentprovider;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log; 

public class MyContactsProvider extends ContentProvider {
  final String LOG_TAG = "myLogs";

  // // Константы для БД
  // БД
  static final String DB_NAME = "mydb";
  static final int DB_VERSION = 1;

  // Таблица
  static final String CONTACT_TABLE = "contacts";

  // Поля
  static final String CONTACT_ID = "_id";
  static final String CONTACT_NAME = "name";
  static final String CONTACT_EMAIL = "email";
  static final String CONTACT_LOGIN = "login";
  

  // Скрипт создания таблицы
  static final String DB_CREATE = "create table " + CONTACT_TABLE + "("
      + CONTACT_ID + " integer primary key autoincrement, "
      + CONTACT_NAME + " text, " + CONTACT_EMAIL + " text" 
      + CONTACT_LOGIN + " text, " + ");";


.....



private class DBHelper extends SQLiteOpenHelper {

    public DBHelper(Context context) {
      super(context, DB_NAME, null, DB_VERSION);
    }

    public void onCreate(SQLiteDatabase db) {
      db.execSQL(DB_CREATE);
      ContentValues cv = new ContentValues();
      for (int i = 1; i <= 3; i++) {
        cv.put(CONTACT_NAME, "name " + i);
        cv.put(CONTACT_EMAIL, "email " + i);
        cv.put(CONTACT_LOGIN, "login " + i);
        db.insert(CONTACT_TABLE, null, cv);
      }
    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
  }
}


Вот код класса ContentProviderClient.java:

Код: Выделить всё


package ru.startandroid.develop.p1012contprovclient;

import android.app.Activity;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

public class MainActivity extends Activity {
  
  final String LOG_TAG = "myLogs";

  final Uri CONTACT_URI = Uri
      .parse("content://ru.startandroid.providers.AdressBooks/contacts");
  
  final String CONTACT_NAME = "name";
  final String CONTACT_EMAIL = "email";
  final String CONTACT_LOGIN = "login";

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Cursor cursor = getContentResolver().query(CONTACT_URI, null, null,
        null, null);
    startManagingCursor(cursor);

    String from[] = { "name", "email", "login" };
    int to[] = { R.id.text1, R.id.text2, R.id.text3 };
    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
        R.layout.item, cursor, from, to);

    ListView lvContact = (ListView) findViewById(R.id.lvContact);
    lvContact.setAdapter(adapter);
  }
  
  public void onClickInsert(View v) {
        ContentValues cv = new ContentValues();
        cv.put(CONTACT_NAME, "name 4");
        cv.put(CONTACT_EMAIL, "email 4"); 
        cv.put(CONTACT_LOGIN, "login 4");
        Uri newUri = getContentResolver().insert(CONTACT_URI, cv);
        Log.d(LOG_TAG, "insert, result Uri : " + newUri.toString());
  }

  public void onClickUpdate(View v) {
        ContentValues cv = new ContentValues();
        cv.put(CONTACT_NAME, "name 5");
        cv.put(CONTACT_EMAIL, "email 5");
        cv.put(CONTACT_LOGIN, "login 5");
        Uri uri = ContentUris.withAppendedId(CONTACT_URI, 2);
        int cnt = getContentResolver().update(uri, cv, null, null);
        Log.d(LOG_TAG, "update, count = " + cnt);
  }

  public void onClickDelete(View v) {
    Uri uri = ContentUris.withAppendedId(CONTACT_URI, 3);
        int cnt = getContentResolver().delete(uri, null, null);
        Log.d(LOG_TAG, "delete, count = " + cnt);
  }
}


Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Урок 101. Создаем свой ContentProvider

Сообщение Foenix » 30 окт 2014, 17:52

в helper-e прибавь версию базы данных
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

dimitrius
Сообщения: 17
Зарегистрирован: 21 авг 2014, 12:47

Re: Урок 101. Создаем свой ContentProvider

Сообщение dimitrius » 30 окт 2014, 21:23

То есть создать новую константу вместо static final int DB_VERSION = 1 соответствующую версии базы данных 2?

Аватара пользователя
doter.ua
Сообщения: 1106
Зарегистрирован: 23 ноя 2013, 16:08
Откуда: Ukraine

Re: Урок 101. Создаем свой ContentProvider

Сообщение doter.ua » 31 окт 2014, 01:44

dimitrius писал(а):То есть создать новую константу вместо static final int DB_VERSION = 1 соответствующую версии базы данных 2?
public DBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
Последний параметр - версия БД, ты передаешь туда свою константу ее и меняй. т.е. да - DB_VERSION = 2
Семь раз отмерь - поставь студию.
Эклипс не студия, ошибка вылетит - не исправишь.
Скажи мне кто твой друг, и оба поставили студию.
Студия - свет, а эклипс - тьма.

dimitrius
Сообщения: 17
Зарегистрирован: 21 авг 2014, 12:47

Re: Урок 101. Создаем свой ContentProvider

Сообщение dimitrius » 31 окт 2014, 10:57

Сделал как Вы говорите, но видимо это еще не все. При запуске ContProvClient выдает "Unfortunately, ContProvClient has stopped"
Как нам проверить что еще может быть не так,я просто понимаю что где то какая то мелкая ошибка, не могу найти...

dimitrius
Сообщения: 17
Зарегистрирован: 21 авг 2014, 12:47

Re: Урок 101. Создаем свой ContentProvider

Сообщение dimitrius » 31 окт 2014, 11:03

Подскажите а если обойтись без констант, так будет проще?

Аватара пользователя
doter.ua
Сообщения: 1106
Зарегистрирован: 23 ноя 2013, 16:08
Откуда: Ukraine

Re: Урок 101. Создаем свой ContentProvider

Сообщение doter.ua » 31 окт 2014, 14:15

dimitrius писал(а):Подскажите а если обойтись без констант, так будет проще?
Константы не причем, они упрощают редактирование в будущем,Если бы у тебя в коде 100 раз использовалось значение версии, то вместо сотни изменений вручную, лучше изначально во всех местах указать константу, и в случае необходимости поменять ее. и она поменяется во всем коде.
По поводу ошибок: Лог в студию. (log cat)
Семь раз отмерь - поставь студию.
Эклипс не студия, ошибка вылетит - не исправишь.
Скажи мне кто твой друг, и оба поставили студию.
Студия - свет, а эклипс - тьма.

MikeInsaine
Сообщения: 1
Зарегистрирован: 21 янв 2015, 18:36

Re: Урок 101. Создаем свой ContentProvider

Сообщение MikeInsaine » 21 янв 2015, 18:42

Забил код урока. ListView не реагирует на insert\update и т.д. клики. Походу я с notifyChange() где-то напортачил, но не могу найти где я не прав :( Не подскажете?

Вот код MyContentProvider:

Код: Выделить всё


public class MyContactsProvider extends ContentProvider
{

    final String LOG_TAG = "myLogs";

    static final String DB_NAME = "mydb";
    static final int DB_VERSION = 1;

    static final String CONTACT_TABLE = "contacts";

    static final String CONTACT_ID = "_id";
    static final String CONTACT_NAME = "name";
    static final String CONTACT_EMAIL = "email";

    static final String DB_CREATE = "CREATE TABLE " + CONTACT_TABLE + "("
                                     + CONTACT_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
                                     + CONTACT_NAME + " TEXT, "
                                     + CONTACT_EMAIL + " TEXT" + ");";

    static final String AUTHORITY = "zulfigarov.com.trainingprj.MyContactsProvider";

    static final String CONTACT_PATH = "contacts";

    public static final Uri CONTACT_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + CONTACT_PATH);

    static final String CONTACT_CONTENT_TYPE = "vnd.android.cursor.dir/vnd." + AUTHORITY + "." + CONTACT_PATH;

    static final String CONTACT_CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd." + AUTHORITY + "." + CONTACT_PATH;


    static final int URI_CONTACTS = 1;

    static final int URI_CONTACTS_ID = 2;

    private static final UriMatcher uriMatcher;
    static
    {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, CONTACT_PATH, URI_CONTACTS);
        uriMatcher.addURI(AUTHORITY, CONTACT_PATH + "/#", URI_CONTACTS_ID);
    }

    DBHelper dbHelper;
    SQLiteDatabase db;

    @Override
    public boolean onCreate()
    {
        Log.d(LOG_TAG, "onCreate provider");
        dbHelper = new DBHelper(getContext());
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
    {
        Log.d(LOG_TAG,"query, " + uri.toString());

        switch (uriMatcher.match(uri))
        {
            case URI_CONTACTS:
                Log.d(LOG_TAG, "URI_CONTACTS");
                if(TextUtils.isEmpty(sortOrder))
                {
                    sortOrder = CONTACT_NAME + " ASC";
                }
                break;

            case URI_CONTACTS_ID:
                String id = uri.getLastPathSegment();
                Log.d(LOG_TAG, "URI_CONTACTS_ID");

                if (TextUtils.isEmpty(selection))
                    selection = CONTACT_ID + " = " + id;
                else
                    selection = selection + " AND " + CONTACT_ID + " = " + id;
                break;

            default:
                throw new IllegalArgumentException("Wrong URI: " + uri);
        }

        db = dbHelper.getWritableDatabase();
        Cursor cursor = db.query(CONTACT_TABLE, projection, selection,
                selectionArgs, null, null, sortOrder);

        cursor.setNotificationUri(getContext().getContentResolver(),CONTACT_CONTENT_URI);

        return cursor;
    }

    @Override
    public String getType(Uri uri)
    {
        Log.d(LOG_TAG, "getTYpe, " + uri.toString());
        switch (uriMatcher.match(uri))
        {
            case URI_CONTACTS:
                return CONTACT_CONTENT_TYPE;
            case URI_CONTACTS_ID:
                return CONTACT_CONTENT_ITEM_TYPE;
        }
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values)
    {
        Log.d(LOG_TAG,"insert, " + uri.toString());

        if(uriMatcher.match(uri) != URI_CONTACTS)
            throw new IllegalArgumentException("Wrong URI: " + uri);

        db = dbHelper.getWritableDatabase();
        long rowID = db.insert(CONTACT_TABLE, null, values);
        Uri resultUri = ContentUris.withAppendedId(CONTACT_CONTENT_URI, rowID);
        getContext().getContentResolver().notifyChange(resultUri, null);

        return resultUri;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs)
    {

        Log.d(LOG_TAG,"delete, " + uri.toString());
        switch (uriMatcher.match(uri))
        {
            case URI_CONTACTS:
                Log.d(LOG_TAG,"URI_CONTACTS");
                break;

            case URI_CONTACTS_ID:
                String id = uri.getLastPathSegment();
                Log.d(LOG_TAG,"URI_CONTACTS_ID, " + id);
                if(TextUtils.isEmpty(selection))
                {
                    selection = CONTACT_ID + " = " + id;
                }
                else
                {
                    selection = selection + " AND " + CONTACT_ID + " = " + id;
                }
                break;

            default:
                throw new IllegalArgumentException("Wrong URI: " + uri);
        }

        db = dbHelper.getWritableDatabase();
        int cnt = db.delete(CONTACT_TABLE, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);

        return cnt;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
    {
        Log.d(LOG_TAG,"update, " + uri.toString());

        switch (uriMatcher.match(uri))
        {
            case URI_CONTACTS:
                Log.d(LOG_TAG,"URI_CONTACTS");
                break;
            case URI_CONTACTS_ID:
                String id = uri.getLastPathSegment();
                Log.d(LOG_TAG, "URI_CONTACTS_ID");
                if(TextUtils.isEmpty(selection))
                {
                    selection = CONTACT_ID;
                }
                else
                {
                    selection = selection + " AND " + CONTACT_ID + " = " + id;
                }
                break;
            default:
                throw new IllegalArgumentException("Wrong URI: " + uri);
        }
        db = dbHelper.getWritableDatabase();
        int cnt = db.update(CONTACT_TABLE, values, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri,null);
        return cnt;
    }

    private class DBHelper extends SQLiteOpenHelper
    {

        public DBHelper(Context context)
        {
            super(context, DB_NAME, null, DB_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db)
        {
            db.execSQL(DB_CREATE);
            ContentValues cv = new ContentValues();

            for (int i = 1; i <= 3; i++)
            {
                cv.put(CONTACT_NAME, "name " + i);
                cv.put(CONTACT_EMAIL, "email " + i);
                db.insert(CONTACT_TABLE, null, cv);
            }
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
        {

        }
    }
}

А вот MainActivity:

Код: Выделить всё

public class MainActivity extends ActionBarActivity
{

    final String LOG_TAG = "myLogs";

    final Uri CONTACT_URI = Uri.parse("content://zulfigarov.com.trainingprj.MyContactsProvider/contacts");

    final String CONTACT_NAME = "name";
    final String CONTACT_EMAIL = "email";

    SimpleCursorAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Cursor cursor = getContentResolver().query(CONTACT_URI, null, null, null, null);

        startManagingCursor(cursor);

        String[] from = {"name", "email"};
        int[] to = {android.R.id.text1, android.R.id.text2};

        adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cursor, from, to, 0);

        ListView lvContact = (ListView)findViewById(R.id.lvContacts);
        lvContact.setAdapter(adapter);
    }

    public void onClickInsert(View view)
    {
        ContentValues cv = new ContentValues();
        cv.put(CONTACT_NAME, "name 4");
        cv.put(CONTACT_EMAIL, "email 4");
        Uri newUri = getContentResolver().insert(CONTACT_URI, cv);

        Log.d(LOG_TAG, "insert, result Uri: " + newUri.toString());
    }

    public void onClickUpdate(View view)
    {
        ContentValues cv = new ContentValues();
        cv.put(CONTACT_NAME, "name 5");
        cv.put(CONTACT_EMAIL, "email 5");
        Uri uri = ContentUris.withAppendedId(CONTACT_URI, 2);
        int cnt = getContentResolver().update(uri, cv, null, null);

        Log.d(LOG_TAG, "update, count = " + cnt);
    }

    public void onClickDelete(View view)
    {
        Uri uri = ContentUris.withAppendedId(CONTACT_URI, 3);
        int cnt = getContentResolver().delete(uri, null, null);

        Log.d(LOG_TAG, "delete, count = " + cnt);
    }

    public void onClickError(View view)
    {
        Uri uri = Uri.parse("content://zulfigarov.com.trainingprj.MyContentProvider/phones");

        try
        {
            Cursor cursor = getContentResolver().query(uri, null, null, null, null);

        }
        catch (Exception ex)
        {
            Log.d(LOG_TAG, "Error: " + ex.getClass() + ", " + ex.getMessage());
        }

    }
}

Аватара пользователя
Fry
Сообщения: 183
Зарегистрирован: 07 дек 2013, 22:07

Re: Урок 101. Создаем свой ContentProvider

Сообщение Fry » 03 фев 2015, 09:35

Возникает ощущение, что код провайдеров будет не сильно отличаться от одной базы к другой.

Поэтому вопрос к профи. )

Вы в каждом очередном проекте провайдеры по-новой пишите, или копипастите некий шаблон, а его уже модифицируете?

Или вообще используете каким-либо из автогенераторов контент-провайдера на основе модели данных?
Arbeit macht Fry

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Урок 101. Создаем свой ContentProvider

Сообщение altwin » 03 фев 2015, 09:56

Fry писал(а):Возникает ощущение, что код провайдеров будет не сильно отличаться от одной базы к другой.

Поэтому вопрос к профи. )

Вы в каждом очередном проекте провайдеры по-новой пишите, или копипастите некий шаблон, а его уже модифицируете?

Или вообще используете каким-либо из автогенераторов контент-провайдера на основе модели данных?
Дело в том, что в простых проектах хватает дефолтного поведения, а более или менее сложные редко создаются часто. Они пишутся несколько лет. И да, всегда по новой с учетом требований. Проблемы копипастов решает IDEA, хотя копипастить там особо нечего.
Изображение

Аватара пользователя
Fry
Сообщения: 183
Зарегистрирован: 07 дек 2013, 22:07

Re: Урок 101. Создаем свой ContentProvider

Сообщение Fry » 03 фев 2015, 10:15

Я это к тому, что методы, которые нужно переопределить в CP, фактически, просто передают данные в соответствующие CRUD функции БД.
А раз зависимость от конкретной структуры БД минимально, вот и возникли вопросы об оптимизации работы )
Arbeit macht Fry

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Урок 101. Создаем свой ContentProvider

Сообщение Foenix » 03 фев 2015, 12:09

есть генераторы кода провайдеров, ну если очень надо
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

GRAF_COLLIOSTRO
Сообщения: 115
Зарегистрирован: 08 янв 2015, 14:32

Re: Урок 101. Создаем свой ContentProvider

Сообщение GRAF_COLLIOSTRO » 11 фев 2015, 08:50

очень не хватает в уроках подробного разбора манифеста что там и зачем и почему... в гуглохелпе навалено кучей - очень тяжело для понимания, там можно на сутки зарыться в поисках нужного...

в этом уроке в манифест провайдера нужно добавить android:exported="true" иначе не работает(

кстати, мучает вопрос, а как быть с внешней MySQL на сервере??? - есть ли какой-то вариант прямого коннекта provider+query??? меньше всего хочется писать обработчик на PHP, а поиск выдаёт именно такие решения(((

GRAF_COLLIOSTRO
Сообщения: 115
Зарегистрирован: 08 янв 2015, 14:32

Re: Урок 101. Создаем свой ContentProvider

Сообщение GRAF_COLLIOSTRO » 11 фев 2015, 09:04

эмм... и ещё: убил провайдер через процессы - клиент тоже сдох(((
какбы вот нехорошо( как этот момент отследить??? ну прервалось соединение и фиг с ним... сообщили об ошибке и дальше работаем... чу так критично то? полное катапультирование никак не устраивает

Аватара пользователя
Fry
Сообщения: 183
Зарегистрирован: 07 дек 2013, 22:07

Re: Урок 101. Создаем свой ContentProvider

Сообщение Fry » 15 фев 2015, 13:45

GRAF_COLLIOSTRO писал(а):очень не хватает в уроках подробного разбора манифеста что там и зачем и почему... в гуглохелпе навалено кучей - очень тяжело для понимания, там можно на сутки зарыться в поисках нужного...
Если ты про манифест вообще, то лично у меня понимание его устройство пришло со временем. Сталкиваешься с определенными компонентами приложений (их всего 4), интентами и технологиями, требующих permission, прописываешь их в манифесте (т. к. это требует их использованием) и понимаешь, как они работают. Заморачиваться с манифестом отдельно имхо нет смысла.
GRAF_COLLIOSTRO писал(а): в этом уроке в манифест провайдера нужно добавить android:exported="true" иначе не работает(
Если у тебя CP должен быть доступен из других приложений, ставишь android:exported="true", если нет, то false.
GRAF_COLLIOSTRO писал(а): кстати, мучает вопрос, а как быть с внешней MySQL на сервере??? - есть ли какой-то вариант прямого коннекта provider+query??? меньше всего хочется писать обработчик на PHP, а поиск выдаёт именно такие решения(((
Я бы здесь реализовывал REST-client. Прямое соединение с удаленной базой данной этот какое-то извращение.
GRAF_COLLIOSTRO писал(а): эмм... и ещё: убил провайдер через процессы - клиент тоже сдох(((
А не надо ничего убивать через процессы. Это не эмулирует работу гарбич коллектора в андройде. Если произвольно убивать процессы (например, на рутовом устройстве) можно и всю систему грохнуть.
Arbeit macht Fry

oligazar
Сообщения: 1
Зарегистрирован: 14 фев 2015, 10:32

Re: Урок 101. Создаем свой ContentProvider

Сообщение oligazar » 15 фев 2015, 14:29

Попробовал выполнить урок на Android Studio. Упорно получаю следущее:
java.lang.RuntimeException: Unable to start activity ComponentInfo{...}: java.lang.SecurityException: Permission Denial: opening provider com... from ProcessRecord{...} that is not exported from uid 10062
Думаю, что проблема в конфигурации запуска. Стандартная "app" не доступна, я отредактировал ее выбрав радиокнопку "Do not launch Activity". Запускаю проект - в console пусто. В чем может быть проблема?
В authority прописал имя своего пакета, но его же указал в манифесте и в CONTACT_URI программы-клиента, в остальном все соответствует материалам с сайта.

GRAF_COLLIOSTRO
Сообщения: 115
Зарегистрирован: 08 янв 2015, 14:32

Re: Урок 101. Создаем свой ContentProvider

Сообщение GRAF_COLLIOSTRO » 15 фев 2015, 14:45

без android:exported у меня вываливается с ошибками(((

Exciter
Сообщения: 6
Зарегистрирован: 24 ноя 2014, 14:12

Re: Урок 101. Создаем свой ContentProvider

Сообщение Exciter » 27 фев 2015, 12:37

Здравствуйте.
Попытался реализовать MainActivity c использованием CursorLoader, поскольку startManagingCursor deprecated. Все вроде работает, судя по логам, но список не обновляется. Обновление содержимого списка происходит лишь при перезапуске приложения. Кто-нибудь знает в чем может быть проблема?

Ответить