0

我已經嘗試了所有我可以在過去五天如何獲得AsyncTask Loader使用內容提供商獲取數據更改的通知,但沒有運氣和所有在stackoverflow中提供的答案都沒有讓我無論如何。 我真的需要你的幫助。通知異步任務加載器的數據變化

我正在使用AsyncTaskLoader和內容提供程序從數據庫中檢索數據,將它添加到我的數組列表並使用recyclerview適配器更新我的片段。新數據由同步適配器異步下載並存儲在數據庫中。通常情況下,我希望AsyncTask Loader在新數據插入到數據庫時應該立即得到通知,但是我嘗試了所有可能的方式,但仍然不會調用負責此操作的ContentChanged()方法,並且無法更新新數據。

看我下面的實現:

public class NewsListLoader extends AsyncTaskLoader<List<News>> { 
private static final String LOG_TAG = NewsListLoader.class.getSimpleName(); 
private List<News> mNews; 
private ContentResolver mContentResolver; 
private Cursor mCursor; 
private Uri mUri; 
private String mSortOrder; 

public NewsListLoader(Context context, Uri uri, String sortOrder, ContentResolver contentResolver) { 
    super(context); 
    mContentResolver = contentResolver; 
    mUri = uri; 
    mSortOrder = sortOrder; 

} 

@Override 
public List<News> loadInBackground() { 
    String[] projection = {NewsContract.NewsEntry.NEWS_TABLE_NAME 
      + "." + NewsContract.NewsEntry._ID, 
      NewsContract.NewsEntry.NEWS_TITLE_COLUMN, 
      NewsContract.NewsEntry.NEWS_CATEGORY_COLUMN, 
      NewsContract.NewsEntry.NEWS_IMAGEURL_COLUMN, 
      NewsContract.NewsEntry.NEWS_URL_COLUMN, 
      NewsContract.NewsEntry.NEWS_DATE_COLUMN, 
      NewsContract.NewsEntry.NEWS_AUTHOR_COLUMN}; 
      // NewsContract.SourceEntry.SOURCE_COLUMN}; 

    List<News> entries = new ArrayList<News>(); 




    mCursor = mContentResolver.query(NewsContract.NewsEntry.NEWS_TABLE_CONTENT_URI, 
      projection, null, null, mSortOrder); 

    if (mCursor != null){ 
     if (mCursor.moveToFirst()){ 
      do{ 
       //int _id = mCursor.getInt(mCursor.getColumnIndex(NewsContract.NewsEntry._ID)); 
       /*String source = mCursor.getString(
         mCursor.getColumnIndex(NewsContract.SourceEntry.SOURCE_COLUMN));*/ 
       String source = "mySource"; 
       String title = mCursor.getString(
         mCursor.getColumnIndex(NewsContract.NewsEntry.NEWS_TITLE_COLUMN)); 
       String category = mCursor.getString(
         mCursor.getColumnIndex(NewsContract.NewsEntry.NEWS_CATEGORY_COLUMN)); 
       String imageUrl = mCursor.getString(
         mCursor.getColumnIndex(NewsContract.NewsEntry.NEWS_IMAGEURL_COLUMN)); 
       String url = mCursor.getString(
         mCursor.getColumnIndex(NewsContract.NewsEntry.NEWS_URL_COLUMN)); 
       String date = mCursor.getString(
         mCursor.getColumnIndex(NewsContract.NewsEntry.NEWS_DATE_COLUMN)); 
       String author = mCursor.getString(
         mCursor.getColumnIndex(NewsContract.NewsEntry.NEWS_AUTHOR_COLUMN)); 


       News news = new News(source,title, category, imageUrl, url, date, author); 
       entries.add(news); 
      }while (mCursor.moveToNext()); 
     } 
    } else {Log.d(LOG_TAG, "Cursor is null"); 

     //mCursor.setNotificationUri(mContentResolver, mUri); 
    } 

    return entries; 

} 

@Override 
public void deliverResult(List<News> news) { 
    if (isReset()){ 
     if (news != null){ 
      mCursor.close(); 
     } 
    } 

    List<News> oldNews = mNews; 
    if (mNews == null || mNews.size() == 0){ 
     Log.d(LOG_TAG, "+++++++ No data returned"); 

    } 

    mNews = news; 
    if (isStarted()){ 
     super.deliverResult(news); 
    } 

    if (oldNews != null && oldNews != news){ 
     mCursor.close(); 
    } 
} 

@Override 
protected void onStartLoading() { 
    if (mNews != null){ 
     deliverResult(mNews); 
    } 

    if (takeContentChanged() || mNews == null){ 
     // here this forceLoad() is called only when mNews is null and never 
     // takeContentChanged. 
     // the ui gets refresh only when i restart the app 
     forceLoad(); 

    } 
} 

@Override 
protected void onStopLoading() { 
    cancelLoad(); 
} 

@Override 
protected void onReset() { 
    onStopLoading(); 
    if (mCursor != null){ 
     mCursor.close(); 
    } 

    mNews = null; 
} 

@Override 
public void onCanceled(List<News> news) { 
    super.onCanceled(news); 
    if (mCursor != null){ 
     mCursor.close(); 
    } 
} 

@Override 
public void forceLoad() { 
    super.forceLoad(); 
} 


public void deleteOldItems (int num){ 

    String where = NewsContract.NewsEntry._ID + 
      " IN (SELECT " + NewsContract.NewsEntry._ID + " FROM " + 
      NewsContract.NewsEntry.NEWS_TABLE_NAME + 
      " ORDER BY " + NewsContract.NewsEntry._ID + " DESC " + " LIMIT ?)"; 
    String limit = "2, 10"; 
    String[] selectionArgs = new String[]{limit}; 

    mContentResolver.delete(
      NewsContract.NewsEntry.NEWS_TABLE_CONTENT_URI, where, selectionArgs); 



} 

}

內容提供商的代碼snipplet

@Override 
public int bulkInsert(Uri uri, ContentValues[] values) { 
    final SQLiteDatabase db = mHelper.getWritableDatabase(); 
    final int match = sUriMatcher.match(uri); 
    Log.d(LOG_TAG, "Insert Uri " + uri); 
    switch (match) { 
     case NEWS: 

      /** 
      * Begins a transaction in "exclusive" mode. No other mutations can occur on the 
       * db until this transaction finishes.*/ 

      db.beginTransaction(); 
      int returnCount = 0; 
      try { 
       for (ContentValues value : values) { 
        long _id = db.insert(NewsContract.NewsEntry.NEWS_TABLE_NAME, null, value); 
        if (_id != -1) { 
         returnCount++; 
        } 
       } 
       db.setTransactionSuccessful(); 
      } finally { 
       db.endTransaction(); 
      } 

      getContext().getContentResolver().notifyChange(uri, null); 

      //Log.d(LOG_TAG, "Insert Count is " + returnCount); 
      return returnCount; 
     default: 
      return super.bulkInsert(uri, values); 
    } 
} 

@Override 
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 
        String sortOrder) { 
    // Here's the switch statement that, given a URI, will determine what kind of request it is, 
    // and query the database accordingly. 
    Cursor retCursor; 
    Log.d(LOG_TAG, "Match Uri is " + uri); 
    Log.d(LOG_TAG, "Matcher is " + sUriMatcher.match(uri)); 


    switch (sUriMatcher.match(uri)) { 

     case NEWS: { 

      //retCursor = getNewsWithAuthor(uri,projection, sortOrder); 
      //String author = NewsContract.NewsEntry.getAuthorFromUri(uri); 
      //Log.d(LOG_TAG, "URI for News is "+ uri); 
      //selection = sAuthorSlection; 
      retCursor = mHelper.getReadableDatabase().query(
        NewsContract.NewsEntry.NEWS_TABLE_NAME, 
        projection, 
        selection, 
        selectionArgs, 
        null, 
        null, 
        sortOrder 
      ); 
      break; 

     } 


     case NEWS_WITH_SOURCE: { 

      retCursor = getNewsSourceAndCategory(uri, projection, sortOrder); 
      break; 
     } 

     case NEWS_WITH_CATEGORY: { 

      retCursor = getNewsWithCategory(uri, projection, sortOrder); 
      break; 
     } 


     case NEWS_WITH_SOURCE_AND_CATEGORY:{ 
      Log.d(LOG_TAG, "Provider Uri is "+ uri); 
      retCursor = getNewsSourceAndCategory(uri, projection, sortOrder); 
      break; 
     } 



     // "news/*/*/* 
     case NEWS_WITH_SOURCE_DATE_AND_CATEGORY: { 
      // Log.d(LOG_TAG, "Provider Uri is "+ uri); 
      retCursor = getNewsWithSourceDateAndCategory(uri, projection, sortOrder); 

      break; 
     } 



     case SOURCE: { 
      retCursor = mHelper.getReadableDatabase().query(
        NewsContract.SourceEntry.NEWS_SOURCE_TABLE_NAME, 
        projection, 
        selection, 
        selectionArgs, 
        null, 
        null, 
        null, 
        sortOrder 
      ); 
      break; 
     } 
     // "source/*" 
     case SOURCE_ID: { 

      retCursor = mHelper.getReadableDatabase().query(
        NewsContract.SourceEntry.NEWS_SOURCE_TABLE_NAME, 
        projection, 
        NewsContract.SourceEntry._ID + " = '" + ContentUris.parseId(uri) + "'", 
        null, 
        null, 
        null, 
        sortOrder 
      ); 
      break; 
     } 
     // "source" 


     default: 
      throw new UnsupportedOperationException("Unknown uri: " + uri); 
    } 
    retCursor.setNotificationUri(getContext().getContentResolver(), uri); 

    return retCursor; 
} 

片段實現LoaderCallback

public class RecyclerViewFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<News>> { 
private static final String LOG_TAG = RecyclerViewFragment.class.getSimpleName(); 

private RecyclerView mRecyclerView; 
private NewsRecyclerViewAdapter mAdapter; 
private List<News> mNews; 
private static final int LOADER_ID = 0; 
private ContentResolver mContentResolver; 
private Object mSyncObserverHandle; 
Menu mOptionsMenu; 



private String[] mUris; 



public static RecyclerViewFragment newInstance() { 
    return new RecyclerViewFragment(); 
} 






@Override 
public void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 

    return inflater.inflate(R.layout.fragment_recyclerview, container, false); 



} 



@Override 
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 
    super.onViewCreated(view, savedInstanceState); 

    mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView); 
    RecyclerView.LayoutManager layoutManager; 

    mRecyclerView.setLayoutManager(layoutManager); 
    mRecyclerView.setHasFixedSize(false); 

    mRecyclerView.addItemDecoration(new MaterialViewPagerHeaderDecorator()); 




    mAdapter = new NewsRecyclerViewAdapter(getActivity(),new ArrayList<News>()); 
    mRecyclerView.setAdapter(mAdapter); 


       ... 


@Override 
public void onActivityCreated(Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 


    mContentResolver = getActivity().getContentResolver(); 
    getLoaderManager().initLoader(LOADER_ID, null,this); 






} 

@Override 
public void onAttach(Context context) { 
    super.onAttach(context); 
    .... 



} 

@Override 
public void onResume() { 
    super.onResume(); 
    ... 
} 

@Override 
public void onPause() { 
    super.onPause(); 
    if (mSyncObserverHandle != null) { 
     ContentResolver.removeStatusChangeListener(mSyncObserverHandle); 
     mSyncObserverHandle = null; 
    } 
} 

@Override 
public Loader<List<News>> onCreateLoader(int id, Bundle args) { 
    mContentResolver = getActivity().getContentResolver(); 
    String source = "techcrunch"; 
     String category = null; 
    String author = "Anna Escher"; 
    String sortOrder = NewsContract.NewsEntry.NEWS_DATE_COLUMN + " DESC"; 
    return new NewsListLoader(getActivity(), NewsContract.NewsEntry 
      .buildNewsSource(source), sortOrder, mContentResolver); 
} 

@Override 
public void onLoadFinished(Loader<List<News>> loader, List<News> news) { 

    mAdapter.loadData(news); 
    mNews = news; 

    mAdapter.notifyDataSetChanged(); 
    //mNews = news; 

} 


@Override 
public void onLoaderReset(Loader<List<News>> loader) { 
    mAdapter.loadData(null); 
} 

回覆cyclerview適配器代碼

@Override 
public View_Holder onCreateViewHolder(ViewGroup parent, int viewType) { 

    View view = LayoutInflater.from(parent.getContext()) 
        .inflate(R.layout.list_item_card_big, parent, false); 
      return new View_Holder(view); 



} 

@Override 
public void onBindViewHolder(View_Holder holder, int position) { 

    List<News> newsItem = mNewsItems; 
    Log.d(LOG_TAG, "Processing "+ newsItem.get(position).getTitle() + " -->" + Integer.toString(position)); 

      String title = newsItem.get(position).getTitle(); 
      holder.title.setText(title); 
      String author = newsItem.get(position).getAuthor(); 
      holder.author.setText(author); 
      String source = (newsItem.get(position).getSource()); 
      holder.source.setText(source); 
      String date = Utility.getDayName(mContext,newsItem.get(position).getPublishedAt()); 
      holder.publisedAt.setText(date); 

      Picasso.with(mContext).load(newsItem.get(position).getImageToUrl()) 
        .fit() 
        .error(R.drawable.placeholder) 
        .placeholder(R.drawable.placeholder) 
        .into(holder.imageView); 


} 
@Override 
public int getItemCount() { 

    return (null != mNewsItems ? mNewsItems.size(): 0); 
} 

public void loadData(List<News> newNews){ 
    mNewsItems.clear(); 
    if (newNews != null){ 
     mNewsItems.addAll(newNews); 

     notifyDataSetChanged(); 
    } 



} 
+0

爲什麼定製'AsyncTaskLoader',爲什麼不' CursorLoader'? – pskink

+0

爲什麼我使用AsyncTaskLoader是因爲我會在其他地方使用arraylist – Hopes

回答

0

您需要註冊的Cursor一個ContentObserver,並覆蓋在onChange調用onContentChangedAsyncTaskLoader

如果使用CursorLoader你在已經烤了這種能力。

+0

感謝您的回覆,儘管我在閱讀您的答案之前已經想清楚了。我使用與遊標加載器類相同的實現註冊了一個內容觀察器 – Hopes

0

也許你必須使用自己的回收商視圖。我只是給你一個想法。你必須實現checkIfempty方法。

@Override 
public void setAdapter(Adapter adapter) { 
} 



final private AdapterDataObserver observer = new AdapterDataObserver() { 

    @Override 
    public void onChanged() { 
     checkIfEmpty(); 
    } 

    @Override 
    public void onItemRangeInserted(int positionStart, int itemCount) { 
     checkIfEmpty(); 
    } 

    @Override 
    public void onItemRangeRemoved(int positionStart, int itemCount) { 
     checkIfEmpty(); 
    } 

    }; 


@Override 
public void setAdapter(Adapter adapter) { 
    final Adapter oldAdapter = getAdapter(); 
    if (oldAdapter != null) { 
     oldAdapter.unregisterAdapterDataObserver(observer); 
    } 
    super.setAdapter(adapter); 
    if (adapter != null) { 
     adapter.registerAdapterDataObserver(observer); 
    } 

    checkIfEmpty(); 
} 
0

得到它在我的AsyncTask裝載機實現內容觀測工作延長class.`

public class NewsListLoader extends AsyncTaskLoader<List<News>> { 
..... 
final ForceLoadContentObserver mObserver; 

public NewsListLoader(Context context, Uri uri, String sortOrder, ContentResolver contentResolver) { 
    super(context); 
    mContentResolver = contentResolver; 
    mUri = uri; 
    mSortOrder = sortOrder; 
    mObserver = new ForceLoadContentObserver(); 

} 

public NewsListLoader(Context context){ 
    super(context); 
    mObserver = new ForceLoadContentObserver(); 
} 

@Override 
public List<News> loadInBackground() { 
    ...... 
    mCursor = mContentResolver.query(mUri, 
      projection, null, null, mSortOrder); 

    if (mCursor != null){ 

      try { 
       // Ensure the cursor window is filled. 
       mCursor.getCount(); 
       mCursor.registerContentObserver(mObserver); 
      } catch (RuntimeException ex) { 
       mCursor.close(); 
       throw ex; 
      }