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

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

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

Сообщение Foenix » 27 фев 2015, 12:38

контент-провадер использовался?
нотификейшен в query() контент-провадера верный?
R.id.team

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

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

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

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

ContentProvider полностью из урока. изменения делал только в MainActivity

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

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

Сообщение Foenix » 27 фев 2015, 13:00

код курсор-лоадера и код контент-провайдера
R.id.team

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

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

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

Сообщение Exciter » 27 фев 2015, 13:52

Код контент-провайдера:

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

package ru.startandroid.develop.p1011contentprovider;

import android.content.*;
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 DB_CREATE = "create table " + CONTACT_TABLE + "("
            + CONTACT_ID + " integer primary key autoincrement, "
            + CONTACT_NAME + " text, " + CONTACT_EMAIL + " text" + ");";

    static final String AUTHORITY = "ru.startandroid.providers.AdressBook";
    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");
        dbHelper = new DBHelper(getContext());
        return true;
    }

    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, " + 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;
    }

    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;
    }

    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;
    }

    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, " + 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.update(CONTACT_TABLE, values, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return cnt;
    }

    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;
    }

    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);
                db.insert(CONTACT_TABLE, null, cv);
            }
        }

        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }
}
Код активити с использованием курсор-лоадера:

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

package ru.startandroid.develop.p1012contprovclient;

import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.util.Log;
import android.view.View;
import android.widget.ListView;

public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {

    final String LOG_TAG = "myLogs";

    final Uri CONTACT_URI = Uri.parse("content://ru.startandroid.providers.AdressBook/contacts");

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

    Cursor cursor;

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

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

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

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

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

        getSupportLoaderManager().initLoader(0, null, this);
    }

    public void onClickInsert(View v) {
        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 v) {
        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 v) {
        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 v) {
        Uri uri = Uri.parse("content://ru.startandroid.providers.AdressBook/phones");
        try {
            Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        } catch (Exception ex) {
            Log.d(LOG_TAG, "Error: " + ex.getClass() + ", " + ex.getMessage());
        }

    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(this, CONTACT_URI, null, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    }

}

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

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

Сообщение Foenix » 27 фев 2015, 14:07

среди констант бардак. Убери константы с URIиз кода активити, используй только из контент-провадера.
Вот в этой строчке
return new CursorLoader(this, CONTACT_URI, null, null, null, null);
и вот в этой
getContext().getContentResolver().notifyChange(uri, null);
должна использоваться одна и та же константа. Если будет другая - то нотификация не произойдет.
R.id.team

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

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

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

Сообщение Foenix » 27 фев 2015, 14:46

забыла сказать, и в setNotificationUri тоже самое, та же константа.
R.id.team

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

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

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

Сообщение Exciter » 27 фев 2015, 22:53

Пытался передавать в CursorLoader те же Uri, что и в контент-провайдере таким способом:

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

package ru.startandroid.develop.p1012contprovclient;

import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.util.Log;
import android.view.View;
import android.widget.ListView;

public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {

    final String LOG_TAG = "myLogs";

    static final String AUTHORITY = "ru.startandroid.providers.AdressBook";
    static final String CONTACT_PATH = "contacts";
    public static final Uri CONTACT_CONTENT_URI = Uri.parse("content://"
            + AUTHORITY + "/" + CONTACT_PATH);

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

    Cursor cursor;
    LoaderManager loadermanager;

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

        Uri uri = Uri.parse("content://ru.startandroid.providers.AdressBook/contacts");

        loadermanager = getSupportLoaderManager();

        cursor = getContentResolver().query(CONTACT_CONTENT_URI, null, null, null, null);

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

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

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

        Bundle bundle = new Bundle();
        bundle.putString("URI", CONTACT_CONTENT_URI.toString());
        loadermanager.initLoader(0, bundle, this);
    }

    public void onClickInsert(View v) {
        ContentValues cv = new ContentValues();
        cv.put(CONTACT_NAME, "name 4");
        cv.put(CONTACT_EMAIL, "email 4");
        Uri newUri = getContentResolver().insert(CONTACT_CONTENT_URI, cv);
        Log.d(LOG_TAG, "insert, result Uri : " + newUri.toString());
        Bundle bundle = new Bundle();
        bundle.putString("URI", newUri.toString());
        loadermanager.restartLoader(0, bundle, this);
    }

    public void onClickUpdate(View v) {
        ContentValues cv = new ContentValues();
        cv.put(CONTACT_NAME, "name 5");
        cv.put(CONTACT_EMAIL, "email 5");
        Uri uri = ContentUris.withAppendedId(CONTACT_CONTENT_URI, 2);
        int cnt = getContentResolver().update(uri, cv, null, null);
        Log.d(LOG_TAG, "update, count = " + cnt);
        Bundle bundle = new Bundle();
        bundle.putString("URI", uri.toString());
        loadermanager.restartLoader(0, bundle, this);
    }

    public void onClickDelete(View v) {
        Uri uri = ContentUris.withAppendedId(CONTACT_CONTENT_URI, 3);
        int cnt = getContentResolver().delete(uri, null, null);
        Log.d(LOG_TAG, "delete, count = " + cnt);
        Bundle bundle = new Bundle();
        bundle.putString("URI", uri.toString());
        loadermanager.restartLoader(0, bundle, this);
    }

    public void onClickError(View v) {
        Uri uri = Uri.parse("content://ru.startandroid.providers.AdressBook/phones");
        try {
            Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        } catch (Exception ex) {
            Log.d(LOG_TAG, "Error: " + ex.getClass() + ", " + ex.getMessage());
        }

    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        String data = args.getString("URI");
        Uri loader_uri = Uri.parse(data);
        return new CursorLoader(this, loader_uri, null, null, null, null);
    }


    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    }

}
ничего не вышло. Очевидно что-то недопонял

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

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

Сообщение Foenix » 27 фев 2015, 23:02

ты должен был в контент-провайдере или другом публичном классе создать константы
public static final String URI_CONTACTS=""
и использовать их как обычно return new CursorLoader(this, URI_CONTACTS, null, null, null, null);
А не с этими заворотами, что у тебя в коде, это раз.
Поубирай мусор оттуда
типа этого Uri uri = Uri.parse("content://ru.startandroid.providers.AdressBook/contacts");

и три - приведи в соответствие сказанному выше код контент-провайдера.
R.id.team

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

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

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

Сообщение Exciter » 28 фев 2015, 02:15

Насчет мусора согласен
Foenix писал(а):ты должен был в контент-провайдере или другом публичном классе создать константы
public static final String URI_CONTACTS=""
и использовать их как обычно return new CursorLoader(this, URI_CONTACTS, null, null, null, null);
Но почему константа public static final String URI_CONTACTS=, а не Uri? и как я могу использовать ее в CursorLoader, который в другом проекте? Я же как раз использовал в CursorLoader те Uri, которые поступали в getContext().getContentResolver().notifyChange(uri, null), как было предложено ранее.

Что-то совсем запутался

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

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

Сообщение Foenix » 28 фев 2015, 17:09

Uri - это объект, который ты потом создаешь, подавая ему в конструктор строку.
В каком еще другом проекте?
R.id.team

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

Nikolay
Сообщения: 6
Зарегистрирован: 30 мар 2015, 17:04

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

Сообщение Nikolay » 04 апр 2015, 13:59

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

smu
Сообщения: 1
Зарегистрирован: 12 июл 2015, 13:38

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

Сообщение smu » 12 июл 2015, 13:52

Exciter писал(а):Код контент-провайдера:

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

package ru.startandroid.develop.p1011contentprovider;

import android.content.*;
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 DB_CREATE = "create table " + CONTACT_TABLE + "("
            + CONTACT_ID + " integer primary key autoincrement, "
            + CONTACT_NAME + " text, " + CONTACT_EMAIL + " text" + ");";

    static final String AUTHORITY = "ru.startandroid.providers.AdressBook";
    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");
        dbHelper = new DBHelper(getContext());
        return true;
    }

    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, " + 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;
    }

    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;
    }

    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;
    }

    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, " + 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.update(CONTACT_TABLE, values, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return cnt;
    }

    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;
    }

    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);
                db.insert(CONTACT_TABLE, null, cv);
            }
        }

        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }
}
Код активити с использованием курсор-лоадера:

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

package ru.startandroid.develop.p1012contprovclient;

import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.util.Log;
import android.view.View;
import android.widget.ListView;

public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {

    final String LOG_TAG = "myLogs";

    final Uri CONTACT_URI = Uri.parse("content://ru.startandroid.providers.AdressBook/contacts");

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

    Cursor cursor;

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

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

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

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

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

        getSupportLoaderManager().initLoader(0, null, this);
    }

    public void onClickInsert(View v) {
        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 v) {
        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 v) {
        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 v) {
        Uri uri = Uri.parse("content://ru.startandroid.providers.AdressBook/phones");
        try {
            Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        } catch (Exception ex) {
            Log.d(LOG_TAG, "Error: " + ex.getClass() + ", " + ex.getMessage());
        }

    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(this, CONTACT_URI, null, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    }

}
раз используется CursorLoader, то нет смысла использовать старый адаптер. пометил его красным, его надо убрать.
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cursor, from, to, 0);


новый вызов будет такой
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, null, from, to, 0);

т.е. никаких запросов в UI, курсор отработает только в методе onCreateLoader.

метод onLoadFinished будет выглядеть вот так-

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
//сюда добавляем обработку пришедшего асинхронно курсора (уничтожение старого если надо)
//К тому же по ИД - loader.getId() можно будет выяснить какой из лоадеров обрабатывать. Их может быть больше одного.
mAdapter.swapCursor(cursor);
}
Во всем остальном не вижу отличий, у меня все работает и обновляется.



Upd. Кстати из предыдущего кода, из-за использования Loader-а, можно (как вариант №2), убрать все оповещения об изменениях(cursor.setNotificationUri), и сделать вместо этого оповещения через UI поток, используя метод get(Support)LoaderManager().restartLoader(LOADER_ID, null, this);

Этот вызов добавить в каждый из методов CRUD-a(onClickInsert, update и тп), после чего он будет обновлять данные.


Вот ссылка на источник: http://www.androiddesignpatterns.com/20 ... nager.html

Juki
Сообщения: 7
Зарегистрирован: 13 авг 2015, 12:22
Откуда: Kharkiv

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

Сообщение Juki » 13 авг 2015, 12:27

Подскажите пожалуйста, если я в приложении хочу в одном Activity добавлять данные в базу, а в другом эти данные выводить на экран, то целесообразно будет пользоваться ContentProviderом или можно это как-то сделать через SQLiteOpenHelper?

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

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

Сообщение Foenix » 13 авг 2015, 15:10

целесообразно
R.id.team

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

K_Vladimir
Сообщения: 36
Зарегистрирован: 28 июн 2015, 03:13

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

Сообщение K_Vladimir » 05 сен 2015, 20:43

Спасибо за урок.

К сожалению по уроку не всё понятно. Остаются вопросы:
1. Не понятен жизненный цикл контент провайдера. Есть какая-то схожесть с сервисом.
Когда его (провайдера) процесс/поток завершается? При выключении телефона что ли?

2. Соединение с БД у нас тоже никогда не разрывается. На сколько это правильно и безопасно никогда не закрывать подключение к БД?

3. Выходит что с помощью контент провайдера можно практически полностью заменить сервис? При этом без лишних заморочек с передачей данных клиентам и потокам.

4. Зачем всё-таки нужны эти MIME-типы
// Типы данных
// набор строк
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;
5. Не очень понятен механизм обновления курсора
// просим ContentResolver уведомлять этот курсор
// об изменениях данных в CONTACT_CONTENT_URI
cursor.setNotificationUri(getContext().getContentResolver(), CONTACT_CONTENT_URI);

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

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

Сообщение Foenix » 06 сен 2015, 03:27

Ты лучше уйди от абстракций типа "соединение", "механизм", "подключение", "жизненный цикл" - и думай о классах, методах и переменных класса. Тогда какая-то ясность придет. Потому что это никакой не живой организм, обладающий жизненным циклом, и никакой не механизм, который существует сам по себе.
А с мимами не заморачивайся, особого смысла они не несут на начальном этапе. Представляют информацию об получаемых данных - курсор, строчка.
R.id.team

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

danek130995
Сообщения: 42
Зарегистрирован: 25 янв 2015, 18:57

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

Сообщение danek130995 » 07 фев 2016, 14:18

Для новых версий Андроид чтобы избежать ошибки Security необходимо изменить манифесты провайдера и клиента:
1)Манифест провайдера:

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

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="p1011contentprovider.develop.startandroid.ru.p1011_contentprovider" >

    <permission android:name="ru.startandroid.providers.AdressBook.READ_DATABASE" android:protectionLevel="normal" />
    <permission android:name="ru.startandroid.providers.AdressBook.WRITE_DATABASE" android:protectionLevel="normal" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
      <provider
          android:authorities="ru.startandroid.providers.AdressBook"
          android:name=".MyContactsProvider"
          android:exported="true"
          android:readPermission="ru.startandroid.providers.AdressBook.READ_DATABASE"
          android:writePermission="ru.startandroid.providers.AdressBook.WRITE_DATABASE">
      </provider>
    </application>

</manifest>
Манифест клиента:

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

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="p1012contprovclient.develop.startandroid.ru.p1012_contprovclient" >


    <uses-permission android:name="ru.startandroid.providers.AdressBook.READ_DATABASE" />
    <uses-permission android:name="ru.startandroid.providers.AdressBook.WRITE_DATABASE" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

shirakz
Сообщения: 9
Зарегистрирован: 23 сен 2015, 20:33

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

Сообщение shirakz » 02 мар 2016, 13:12

Добавил разрешения в манифесты. Но выходит новая ошибка.
Основная ошибка такая

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference

Ошибка на строке кода 32:
startManagingCursor(cursor);

Вот полный лог ошибки (не знаю как добавить в сжатом виде, сори) :(

03-02 16:02:53.908 21212-21212/com.example.kz.p1012_contprovclient E/ActivityThread: Failed to find provider info for com.example.kz.providers.AdressBook
03-02 16:02:53.910 21212-21212/com.example.kz.p1012_contprovclient E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.kz.p1012_contprovclient, PID: 21212
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.kz.p1012_contprovclient/com.example.kz.p1012_contprovclient.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2462)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2524)
at android.app.ActivityThread.access$800(ActivityThread.java:167)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1419)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5546)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference
at android.app.Activity.startManagingCursor(Activity.java:2041)
at com.example.kz.p1012_contprovclient.MainActivity.onCreate(MainActivity.java:32)
at android.app.Activity.performCreate(Activity.java:5977)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1111)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2415)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2524) 
at android.app.ActivityThread.access$800(ActivityThread.java:167) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1419) 
at android.os.Handler.dispatchMessage(Handler.java:111) 
at android.os.Looper.loop(Looper.java:194) 
at android.app.ActivityThread.main(ActivityThread.java:5546) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759) 

shirakz
Сообщения: 9
Зарегистрирован: 23 сен 2015, 20:33

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

Сообщение shirakz » 02 мар 2016, 13:14

Android 5.0.2
MIUI 7
Xiaomi Redmi Note 2

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

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

Сообщение Foenix » 03 мар 2016, 00:09

Код программы надо приводить.
R.id.team

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

Ответить