找不到<自定义提供程序>的提供程序信息。

7

我已经阅读了所有关于这个问题的内容,但还是无法解决。

我的应用程序从MainActivity开始,我的Content ProviderAndroidManifest.xml中被正确定义,ContentProvider类似乎没什么问题...这已经在运行 Android 4.3 的 Nexus i9250、运行 Android 4.2.1 的 Asus Memo Pad 以及运行 Jelly Bean 的 VDevices 上进行了测试。在每种情况下都可以运行应用程序而不崩溃,但唯一的问题是LogCat在我的某个片段尝试查询Content Provider并获取光标时给出的错误消息:"Failed to find provider info for de.somename.provider"。以下是代码:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="de.somename.hvk3"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="14"
              android:targetSdkVersion="18" />

    <application android:allowBackup="true"
                 android:icon="@drawable/ic_launcher"
                 android:label="@string/app_name"
                 android:theme="@style/AppTheme" >
        <activity android:name="de.somename.hvk3.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>
        <activity android:name="de.somename.hvk3.UserSettingActivity"
                  android:label="@string/settings" ></activity>
        <provider android:authorities="de.somename.provider"
                  android:enabled="true"
                  android:multiprocess="true"
                  android:name=".hvkContentProvider"
                  android:exported="true" ></provider>
    </application>
</manifest>

hvkContentProvider.java

public class hvkContentProvider extends ContentProvider {

    private static final String DATABASE_NAME = "hvkDB";
    private static final int DATABASE_VERSION = 1;
    public static final String Authority = "de.somename.provider";
    public static final String ElementPath = "/hv_kontakte";
    public static final Uri CONTENT_URI = Uri.parse("content://" + Authority + ElementPath);
    private static final int ALLROWS = 1;
    private static final int SINGLE_ROW = 2;
    
    private static final UriMatcher suriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static{
        suriMatcher.addURI("de.somename.provider", ElementPath, ALLROWS);
        suriMatcher.addURI("de.somename.provider", ElementPath + "/#", SINGLE_ROW);
    }
    
    public static final String KEY_ID = "_id";
    public static final String KEY_TYPE = "type";
    public static final String KEY_CLTYP = "cltyp";
    public static final String KEY_MDT = "mdt";
    public static final String KEY_OBJ = "obj";
    public static final String KEY_VTR = "vtr";
    public static final String KEY_FKZ = "fkz";
    public static final String KEY_NAME = "name";
    public static final String KEY_VNAME = "vname";
    public static final String KEY_TEL = "tel";
    public static final String KEY_FAX = "fax";
    public static final String KEY_MOBIL = "mobil";
    public static final String KEY_EMAIL = "email";
    
    private MySQLiteOpenHelper myOpenHelper;
    
    @Override
    public boolean onCreate() {
        
        myOpenHelper = new MySQLiteOpenHelper(getContext(), DATABASE_NAME, null, DATABASE_VERSION);
        return true;
    }
    
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        
        SQLiteDatabase db = myOpenHelper.getReadableDatabase();
        
        String groupBy = null;
        String having = null;
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        queryBuilder.setTables(MySQLiteOpenHelper.DATABASE_TABLE);
        
        switch(suriMatcher.match(uri)){
        case SINGLE_ROW:
            String rowID = uri.getPathSegments().get(1);
            queryBuilder.appendWhere(KEY_ID + "=" + rowID);
        default: break;
        }
        
        Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, groupBy, having, sortOrder);
        
        return cursor;
    }
    
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = myOpenHelper.getWritableDatabase();
        switch(suriMatcher.match(uri)){
        case SINGLE_ROW:
            String rowID = uri.getPathSegments().get(1);
            selection = KEY_ID + "=" + rowID
                    + (!TextUtils.isEmpty(selection) ?
                    " AND (" + selection + ')' : "");
        default: break;
        }
        //To return the number of deleted items you must specify a where clause. To delete all rows and return a value pass in "1"
        if (selection == null)
            selection = "1";
        
        return db.delete(MySQLiteOpenHelper.DATABASE_TABLE, selection, selectionArgs);
    }
    
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        
        SQLiteDatabase db = myOpenHelper.getWritableDatabase();
        String nullColumnHack = null;
        long id = db.insert(MySQLiteOpenHelper.DATABASE_TABLE, nullColumnHack, values);
        
        if(id > -1){
            Uri insertedId = ContentUris.withAppendedId(CONTENT_URI, id);
            getContext().getContentResolver().notifyChange(insertedId, null);
            return insertedId;
        }
        else
            return null;
    }
    
    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        
        SQLiteDatabase db = myOpenHelper.getWritableDatabase();
        
        switch(suriMatcher.match(uri)){
        case SINGLE_ROW:
            String rowID = uri.getPathSegments().get(1);
            selection = KEY_ID + "=" + rowID
                + (!TextUtils.isEmpty(selection) ?
                " AND (" + selection + ')' : "");
        default: break;
        }
        
        return db.update(MySQLiteOpenHelper.DATABASE_TABLE, values, selection, selectionArgs);
    }

    @Override
    public String getType(Uri uri) {
        switch(suriMatcher.match(uri)){
        case ALLROWS:
            return "vnd.android.cursor.dir/vnd.somename.contacts";
        case SINGLE_ROW:
            return "vnd.android.cursor.item/vnd.somename.contacts";
        default:
            throw new IllegalArgumentException("Unsupported URI: " + uri);
        }
    }
    
    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
        
        //Find the row ID and use it as a filename
        String rowID = uri.getPathSegments().get(1);
        
        //Create a file object in the applications external files directory
        String picsDir = Environment.DIRECTORY_PICTURES;
        File file = new File(getContext().getExternalFilesDir(picsDir), rowID);
        
        if(!file.exists()) {
            try{
                file.createNewFile();
            } catch (IOException e) {
                //Log.d(TAG, "File creation failed: " + e.getMessage());
            }
        }
        
        //Translate the mode parameter to the corresponding Parcel File Descriptor open mode
        int fileMode = 0;
        if(mode.contains("w"))
            fileMode |= ParcelFileDescriptor.MODE_WRITE_ONLY;
        if(mode.contains("r"))
            fileMode |= ParcelFileDescriptor.MODE_READ_ONLY;
        if(mode.contains("+"))
            fileMode |= ParcelFileDescriptor.MODE_APPEND;
        
        return ParcelFileDescriptor.open(file, fileMode);
    }
    
    private class MySQLiteOpenHelper extends SQLiteOpenHelper {     //used to be static
        
        public static final String DATABASE_TABLE = "hv_kontakte";
        private static final String DATABASE_CREATE = 
                "CREATE TABLE " + DATABASE_TABLE + "(" + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                        KEY_TYPE + " TEXT, " + KEY_CLTYP + " TEXT, " + KEY_MDT + " INTEGER, " + KEY_OBJ + " INTEGER, "
                        + KEY_VTR + " INTEGER, " + KEY_FKZ + " INTEGER, " + KEY_NAME + " TEXT, " + KEY_VNAME + " TEXT, "
                        + KEY_TEL + " TEXT, " + KEY_FAX + " TEXT, " + KEY_MOBIL + " TEXT, " + KEY_EMAIL + " TEXT)";
        
        public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version){
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
        
        @Override
        public void onCreate(SQLiteDatabase database) {
            database.execSQL(DATABASE_CREATE);
            hvkContentProvider.this.insertSomeContacts();
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
            database.execSQL("DROP TABLE IF EXISTS" + DATABASE_TABLE);
            onCreate(database);
        }
    }
}

HdwFragment.java

public class HdwFragment extends Fragment{

    private SimpleCursorAdapter hdwDataAdapter;
    private ListView listview;
    public static final String ARG_SECTION_NUMBER = "section_number";
    private static final String TAG = "HdwFragment";
    public HdwFragment(){}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState){
        
        Context context = getActivity();
        View rootView = inflater.inflate(R.layout.fragment_all,container, false);
        TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
        dummyTextView.setText("Dienstleister");
        //android.support.v4.app.LoaderManager loaderManager = getLoaderManager();
        
        Log.i(TAG, "Before getContentResolver");
        ContentResolver cr = context.getContentResolver();
        Log.i(TAG, "Before result_columns");
        String[] result_columns = new String[] {
                hvkContentProvider.KEY_ID,
                hvkContentProvider.KEY_TYPE,
                hvkContentProvider.KEY_CLTYP,
                hvkContentProvider.KEY_NAME,
                hvkContentProvider.KEY_VNAME
        };
        Log.i(TAG, "Before where,whereArgs and order");
        String where = null;
        String whereArgs[] = null;
        String order = null;
        Log.i(TAG, "Before resultCursor action");
        Log.i(TAG, "hvkContentProvider URI: " + hvkContentProvider.CONTENT_URI);
        Cursor resultCursor = cr.query(hvkContentProvider.CONTENT_URI, result_columns, where, whereArgs, order);
        Log.i(TAG, "resultCursor = " + resultCursor);
        Log.i(TAG, "Before fromColumns");
        String[] fromColumns = new String[]{
                hvkContentProvider.KEY_TYPE,
                hvkContentProvider.KEY_CLTYP,
                hvkContentProvider.KEY_NAME,
                hvkContentProvider.KEY_VNAME    
        };
        Log.i(TAG, "Before toViews");
        int[] toViews = new int[]{
            R.id.contactType,
            R.id.contactCltype,
            R.id.contactName,
            R.id.contactVname
        };
        Log.i(TAG, "Before Adapter");
        hdwDataAdapter = new SimpleCursorAdapter(getActivity(), R.layout.object_list_item, resultCursor, fromColumns, toViews, 0);
        listview = (ListView) rootView.findViewById(R.id.list_all);
        listview.setAdapter(hdwDataAdapter);
        Log.i(TAG, "Before return Layout");
        return (LinearLayout) rootView;
    }
    
    @Override
    public void onActivityCreated(Bundle savedInstanceState){
        super.onActivityCreated(savedInstanceState);
        
        //Bundle args = null;
        //loaderManager.initLoader(LOADER_ID, args, loaderCallback);
    }
}

方法:insertSomeFunctions() 我已经省略了,因为它在这里没有影响。我会尽快悬赏此事。真的需要完成这个任务。
3个回答

18
<provider android:authorities="de.somename.provider"
    android:enabled="true"
    android:multiprocess="true"
    android:name=".hvkContentProvider"
    android:exported="true" ></provider>

<provider>的参考页面上得知:链接

android:authorities:...... 为避免冲突,权限名称应使用Java样式命名规则(例如com.example.provider.cartoonprovider)。通常,它是实现该提供程序的ContentProvider子类的名称。

在您的情况下,android:authorities应具有值:de.somename.provider.hvkContentProvider


android:name:...... 实现内容提供程序的类的名称,即ContentProvider的子类。这应该是一个完全合格的类名(例如,“com.example.project.TransportationProvider”)。但是,作为一种简写,如果名称的第一个字符是点,则将其附加到元素中指定的包名称中。

因此,如果您正在AndroidManifest.xmlmanifest标记中定义package,请确保hvkContentProvider在该包中。否则,请将android:name =“。hvkContentProvider”更改为android:name=“de.somename.hvk3.hvkContentProvider”your.package.name.hvkContentProvider


4
你引导我朝着正确的方向前进......谢谢。你的建议开始带来其他错误,最终帮我解决了内容提供者的问题。虽然如此,你确实让我重新开始行动了。 - M.Bennett
说,为什么IDE会警告使用 android:exported="true" ?当我将其设置为false时,选择共享多个文件时会有一些应用程序出现问题... - android developer

4
尝试在android:authorities中使用完全限定路径,将de.somename.provider替换为de.somename.provider.hvkContentProvider,使其变为以下形式。
<provider android:authorities="de.somename.provider.hvkContentProvider"
              android:enabled="true"
              android:multiprocess="true"
              android:name=".hvkContentProvider"
              android:exported="true" ></provider>

您可以引用此处


1
我遇到了类似的问题,但是没有一个解决方案对我有用。最终偶然发现下面的链接(在API 30中找不到内容提供程序),这个解决方案就像魔法一样奏效了。 对于API大于29的应用程序,请在您的AppB清单文件中声明以下块。
    <manifest>
...
    <queries>
        <provider android:authorities="com.example.appcontainprovider" />
    </queries>
...
</manifest>

当局价值是提供者权限。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接