我试图为数据库提取历史记录....但它从不拉扯任何东西......任何人都能看到我做错了什么
以下是内容提供商:
package com.projectcaruso.naturalfamilyplaning;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;
public class StatusProvider extends ContentProvider {
private static final String TAG = StatusProvider.class.getSimpleName();
public static final Uri CONTENT_URI = Uri.parse("content://com.projectcaruso.naturalfamilyplaning.statusprovider");
public static final String SINGLE_RECORD_MIME_TYPE = "vnd.android.cursor.item/vnd.projectcaruso.naturalfamilyplaning.status";
public static final String MULTIPLE_RECORDS_MIME_TYPE = "vnd.android.cursor.dir/vnd.projectcaruso.naturalfamilyplaning.status";
StatusData statusData;
@Override
public String getType(Uri uri) {
return this.getId(uri) < 0 ? MULTIPLE_RECORDS_MIME_TYPE
: SINGLE_RECORD_MIME_TYPE;
}
@Override
public boolean onCreate() {
statusData = new StatusData(getContext());
return true;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = statusData.dbHelper.getWritableDatabase();
try {
long id = db.insertOrThrow(StatusData.DATABASE_TABLE, null, values);
if (id == -1) {
throw new RuntimeException(String.format(
"%s: Failed to insert [%s] to [%s] for unknown reasons.", TAG,
values, uri));
} else {
Uri newUri = ContentUris.withAppendedId(uri, id);
// Notify the Context's ContentResolver of the change
getContext().getContentResolver().notifyChange(newUri, null);
return newUri;
}
} finally {
db.close();
}
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
long id = this.getId(uri);
int count;
SQLiteDatabase db = statusData.dbHelper.getWritableDatabase();
try {
if (id < 0) {
count = db.update(StatusData.DATABASE_TABLE, values, selection, selectionArgs);
} else {
count = db.update(StatusData.DATABASE_TABLE, values, StatusData.KEY_ROWID + "=" + id,
null);
}
} finally {
db.close();
}
// Notify the Context's ContentResolver of the change
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
long id = this.getId(uri);
int count;
SQLiteDatabase db = statusData.dbHelper.getWritableDatabase();
try {
if (id < 0) {
count = db.delete(StatusData.DATABASE_TABLE, selection, selectionArgs);
} else {
count = db.delete(StatusData.DATABASE_TABLE, StatusData.KEY_ROWID + "=" + id, null);
}
} finally {
db.close();
}
// Notify the Context's ContentResolver of the change
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
long id = this.getId(uri);
SQLiteDatabase db = statusData.dbHelper.getReadableDatabase();
Log.d(TAG, "querying");
Cursor c;
if (id < 0) {
c = db.query(StatusData.DATABASE_TABLE, projection, selection, selectionArgs,
null, null, sortOrder);
} else {
c = db.query(StatusData.DATABASE_TABLE, projection, StatusData.KEY_ROWID + "=" + id,
null, null, null, null);
}
// Notify the context's ContentResolver if the cursor result set changes
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
// Helper method to extract ID from Uri
private long getId(Uri uri) {
String lastPathSegment = uri.getLastPathSegment();
if (lastPathSegment != null) {
try {
return Long.parseLong(lastPathSegment);
} catch (NumberFormatException e) {
// at least we tried
}
}
return -1;
}
}
历史片段:
package com.projectcaruso.naturalfamilyplaning;
import com.projectcaruso.naturalfamilyplanning.R;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.SimpleCursorAdapter.ViewBinder;
public class HistoryFragment extends Fragment {
static final String SEND_TIMELINE_NOTIFICATIONS = "com.marakana.yamba.SEND_TIMELINE_NOTIFICATIONS";
Cursor cursor;
ListView listTimeline;
SimpleCursorAdapter adapter;
static final String[] FROM = { StatusData.KEY_CHARTING_DATE, StatusData.KEY_NAME, StatusData.KEY_CHARTING_NOTES };
static final int[] TO = { R.id.textCreatedAt, R.id.textUser, R.id.textText };
TimelineReceiver receiver;
IntentFilter filter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_history, container, false);
listTimeline = (ListView) view.findViewById(R.id.listTimeline);
// Create the receiver
//receiver = new TimelineReceiver();
//filter = new IntentFilter( UpdaterService.NEW_STATUS_INTENT );
return view;
}
@Override
public void onResume() {
super.onResume();
this.setupList();
// Register the receiver
//super.registerReceiver(receiver, filter,
// SEND_TIMELINE_NOTIFICATIONS, null);
}
@Override
public void onPause() {
super.onPause();
// UNregister the receiver
//unregisterReceiver(receiver);
}
// Responsible for fetching data and setting up the list and the adapter
private void setupList() { // <5>
// Get the data
Cursor c = getActivity().getContentResolver().query(StatusProvider.CONTENT_URI, null, null, null, StatusData.KEY_CHARTING_DATE + " DESC"); // <3>
getActivity().startManagingCursor(cursor);
// Setup Adapter
adapter = new SimpleCursorAdapter(getActivity(), R.layout.row, cursor, FROM, TO);
adapter.setViewBinder(VIEW_BINDER); // <6>
listTimeline.setAdapter(adapter);
}
// View binder constant to inject business logic for timestamp to relative
// time conversion
static final ViewBinder VIEW_BINDER = new ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if(view.getId() != R.id.textCreatedAt) return false;
// Update the created at text to relative time
long timestamp = cursor.getLong(columnIndex);
CharSequence relTime = DateUtils.getRelativeTimeSpanString(view.getContext(), timestamp);
((TextView)view).setText(relTime);
return true;
}
};
// Receiver to wake up when UpdaterService gets a new status
// It refreshes the timeline list by requerying the cursor
class TimelineReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
setupList();
Log.d("TimelineReceiver", "onReceived");
}
}
}
片段历史记录:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation ="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<!-- Title -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_margin="10dp"
android:text="@string/title_history"
android:textColor="#fff"
android:textSize="30sp" />
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/listTimeline" />
</LinearLayout>
历史排:
<?xml version="1.0" encoding="utf-8"?>
<!-- <1> -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content" android:orientation="vertical"
android:layout_width="fill_parent">
<!-- <2> -->
<LinearLayout android:layout_height="wrap_content"
android:layout_width="fill_parent">
<!-- <3> -->
<TextView android:layout_height="wrap_content"
android:layout_width="fill_parent" android:layout_weight="1"
android:id="@+id/textUser" android:text="Slashdot"
android:textStyle="bold" />
<!-- <4> -->
<TextView android:layout_height="wrap_content"
android:layout_width="fill_parent" android:layout_weight="1"
android:gravity="right" android:id="@+id/textCreatedAt"
android:text="10 minutes ago" />
</LinearLayout>
<!-- <5> -->
<TextView android:layout_height="wrap_content"
android:layout_width="fill_parent" android:id="@+id/textText"
android:text="Firefox comes to Android" />
</LinearLayout>
数据库:
public class StatusData {
//Database information
private static final String DATABASE_NAME = "NFP";
private static final int DATABASE_VERSION = 1;
//Table Information
static final String DATABASE_TABLE = "charting";
public static final String KEY_ROWID = "_id";
public static final String KEY_NAME = "username";
public static final String KEY_CHARTING_DATE = "Date";
public static final String KEY_CHARTING_TEMPERATURE = "temperature";
public static final String KEY_CHARTING_STAMPS = "Stamps";
public static final String KEY_CHARTING_FERTILE = "Fertile";
public static final String KEY_CHARTING_NOTES = "Notes";
public static final String KEY_CHARTING_PROC = "Proc";
private static final String GET_ALL_ORDER_BY = KEY_CHARTING_DATE + " DESC";
private static final String[] MAX_CREATED_AT_COLUMNS = { "max(" + StatusData.KEY_CHARTING_DATE + ")" };
private static final String[] DB_TEXT_COLUMNS = { KEY_CHARTING_NOTES };
//called once
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL( "CREATE table " + DATABASE_TABLE + " (" +
KEY_ROWID + " INTEGER primary key AUTOINCREMENT, " +
KEY_CHARTING_DATE + " TEXT NOT NULL, " +
KEY_NAME + " TEXT, " +
KEY_CHARTING_TEMPERATURE + " INTEGER, " +
KEY_CHARTING_STAMPS + " INTEGER, " +
KEY_CHARTING_FERTILE + " TEXT, " +
KEY_CHARTING_NOTES + " TEXT, " +
KEY_CHARTING_PROC + " ); "
);
}
final DbHelper dbHelper;
public StatusData(Context context) {
this.dbHelper = new DbHelper(context);
}
public void close() {
this.dbHelper.close();
}
public void insertOrIgnore(ContentValues values) {
SQLiteDatabase db = this.dbHelper.getWritableDatabase();
try {
db.insertWithOnConflict(DATABASE_TABLE, null, values,
SQLiteDatabase.CONFLICT_IGNORE);
} finally {
db.close();
}
}
/**
*
* @return Cursor where the columns are going to be id, created_at, user, txt
*/
public Cursor getStatusUpdates() {
SQLiteDatabase db = this.dbHelper.getReadableDatabase();
return db.query(DATABASE_TABLE, null, null, null, null, null, GET_ALL_ORDER_BY);
}
public long getLatestStatusCreatedAtTime() {
SQLiteDatabase db = this.dbHelper.getReadableDatabase();
try {
Cursor cursor = db.query(DATABASE_TABLE, MAX_CREATED_AT_COLUMNS, null, null, null,
null, null);
try {
return cursor.moveToNext() ? cursor.getLong(0) : Long.MIN_VALUE;
} finally {
cursor.close();
}
} finally {
db.close();
}
}
public String getStatusTextById(long id) {
SQLiteDatabase db = this.dbHelper.getReadableDatabase();
try {
Cursor cursor = db.query(DATABASE_TABLE, DB_TEXT_COLUMNS, KEY_ROWID + "=" + id, null,
null, null, null);
try {
return cursor.moveToNext() ? cursor.getString(0) : null;
} finally {
cursor.close();
}
} finally {
db.close();
}
}
/**
* Deletes ALL the data
*/
public void delete() {
// Open Database
SQLiteDatabase db = dbHelper.getWritableDatabase();
// Delete the data
db.delete(DATABASE_TABLE, null, null);
// Close Database
db.close();
}
}
添加到清单:
<application>
...
<provider android:name=".StatusProvider" android:authorities="com.projectcaruso.naturalfamilyplaning"/>
</application>
编辑:
05-16 21:41:20.514: E/ActivityThread(7147): Failed to find provider info for com.projectcaruso.naturalfamilyplaning.statusprovider
05-16 21:41:20.514: V/SlidingMenu(7147): changing layerType. hardware? true
05-16 21:41:20.584: D/dalvikvm(7147): GC_FOR_ALLOC freed 2595K, 8% free 3305K/3564K, paused 33ms, total 42ms
05-16 21:41:20.594: I/dalvikvm-heap(7147): Grow heap (frag case) to 4.476MB for 1188736-byte allocation
05-16 21:41:20.694: D/dalvikvm(7147): GC_CONCURRENT freed 1K, 6% free 4464K/4728K, paused 73ms+5ms, total 105ms
05-16 21:41:20.694: D/dalvikvm(7147): WAIT_FOR_CONCURRENT_GC blocked 19ms
05-16 21:41:20.744: D/dalvikvm(7147): GC_FOR_ALLOC freed <1K, 6% free 4464K/4728K, paused 30ms, total 30ms
05-16 21:41:20.754: I/dalvikvm-heap(7147): Grow heap (frag case) to 5.870MB for 1463056-byte allocation
05-16 21:41:20.864: D/dalvikvm(7147): GC_CONCURRENT freed 0K, 5% free 5893K/6160K, paused 76ms+5ms, total 107ms
05-16 21:41:20.864: D/dalvikvm(7147): WAIT_FOR_CONCURRENT_GC blocked 18ms
05-16 21:41:20.894: I/Choreographer(7147): Skipped 47 frames! The application may be doing too much work on its main thread.
05-16 21:41:20.937: V/CustomViewBehind(7147): behind INVISIBLE
05-16 21:41:21.025: V/SlidingMenu(7147): changing layerType. hardware? false
编辑2:
05-17 13:20:41.013: D/dalvikvm(21373): GC_CONCURRENT freed 0K, 12% free 6199K/7004K, paused 73ms+6ms, total 111ms
05-17 13:20:41.013: D/dalvikvm(21373): WAIT_FOR_CONCURRENT_GC blocked 24ms
05-17 13:20:41.054: V/SlidingMenu(21373): changing layerType. hardware? true
05-17 13:20:41.054: V/SlidingMenu(21373): changing layerType. hardware? false
05-17 13:20:41.073: I/Choreographer(21373): Skipped 54 frames! The application may be doing too much work on its main thread.
05-17 13:20:41.844: D/StatusProvider(21373): querying
05-17 13:20:41.855: I/Choreographer(21373): Skipped 39 frames! The application may be doing too much work on its main thread.
05-17 13:20:41.924: V/SlidingMenu(21373): changing layerType. hardware? true
05-17 13:20:41.984: W/CursorWrapperInner(21373): Cursor finalized without prior close()
05-17 13:20:41.984: D/dalvikvm(21373): GC_FOR_ALLOC freed 2601K, 49% free 3627K/7004K, paused 35ms, total 43ms
05-17 13:20:41.994: I/dalvikvm-heap(21373): Grow heap (frag case) to 4.791MB for 1188736-byte allocation
05-17 13:20:42.104: D/dalvikvm(21373): GC_CONCURRENT freed 23K, 32% free 4765K/7004K, paused 73ms+5ms, total 113ms
05-17 13:20:42.104: D/dalvikvm(21373): WAIT_FOR_CONCURRENT_GC blocked 35ms
05-17 13:20:42.154: D/dalvikvm(21373): GC_FOR_ALLOC freed 1K, 32% free 4764K/7004K, paused 36ms, total 36ms
05-17 13:20:42.154: I/dalvikvm-heap(21373): Grow heap (frag case) to 6.163MB for 1463056-byte allocation
05-17 13:20:42.265: D/dalvikvm(21373): GC_CONCURRENT freed 0K, 12% free 6193K/7004K, paused 74ms+5ms, total 110ms
05-17 13:20:42.265: D/dalvikvm(21373): WAIT_FOR_CONCURRENT_GC blocked 29ms
05-17 13:20:42.294: V/SlidingMenu(21373): changing layerType. hardware? true
05-17 13:20:42.294: I/Choreographer(21373): Skipped 45 frames! The application may be doing too much work on its main thread.
05-17 13:20:42.335: V/CustomViewBehind(21373): behind INVISIBLE
05-17 13:20:42.424: V/SlidingMenu(21373): changing layerType. hardware? false
答案 0 :(得分:1)
中有错误
public static final Uri CONTENT_URI = Uri
.parse("content://com.projectcaruso.naturalfamilyplaning.statusprovider");
应该是
public static final Uri CONTENT_URI = Uri
.parse("content://com.projectcaruso.naturalfamilyplaning/statusprovider");
uri解析器通过“/”解析元素而不是点解析。因此,无法找到提供者,因为您的清单中没有声明“com.projectcaruso.naturalfamilyplaning.statusprovider”权限。