标签: android-cursor

为什么我不应该使用消息总线而不是加载器和服务?

在典型的Android项目中,我们需要以干净的方式将数据从某个地方(REST,SQL,缓存等)提取到UI中,我们通常使用Loader,Service或(可能是yuk)AsyncTask,但我发现所有这些方法由于以下几个原因不满意:

  • 它们很难看,尤其是具有令人震惊的API结构的Loaders
  • 它很容易被包裹在线程中,并踩在UI线程上
  • 我们的表示层代码被Android代码和样板文件污染了.我们经常将Android对象(例如Cursors)传递到UI层,这使得一个干净的架构几乎无法实现.这迫使我们将业务领域特定代码(理想情况下是普通的Java对象)与Android平台代码混合在一起 - 对于未来开发的可读性,维护,测试或灵活性来说并不是很好.在实践中,我们经常会遇到庞大,混乱的Activity/Fragment类.

我被这些文章中概述的想法所吸引:http : //fernandocejas.com/2014/09/03/architecting-android-the-clean-way/ http://antonioleiva.com/mvp-android/ http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

成功开始使用MVP将活动/碎片/视图分解为更小/更清洁的部分,我现在认为上述问题的解决方案可能是依赖于消息总线(Otto,EventBus等)而不是服务或加载器或任何与域数据交互的内容.

所以在实践中这意味着不是使用(例如)CursorLoader从数据库加载Cursor,而是使用消息总线发送消息来请求数据,数据被加载到后台线程以响应该消息,然后通过UI线程上的消息到达时处理响应数据.对我来说至关重要的是,我希望将数据结构从业务领域推出,而不是Android域,所以我更喜欢业务对象数组,而不是Cursor.

这是工程设计,总是需要权衡,虽然这似乎提供了更清晰的关注点分离,但是装载机/服务模板的减少,缺点是什么?

  • 理解代码可能更难(特别是对于新开发人员而言)
  • 有必要确保在正确的线程上发送和接收消息(Otto似乎在这里可能有限制)
  • 有必要避免将一切事物作为一种信息实施的诱惑,这最终会适得其反
  • 传递业务对象集合可能不如使用像Cursors这样的对象.虽然在许多情况下它在实践中是一个问题吗?
  • 我不知道Otto/EventBus是否只是为了传递非常小的消息,或者是否适合传递更大的对象(例如业务对象数组).

我的问题是,是否有任何基本原因不采用这种基于消息的Android应用程序方法?

android android-service android-cursor android-testing android-cursorloader

19
推荐指数
1
解决办法
1782
查看次数

带有搜索实现的CursorTreeAdapter

我申请了 我正在使用CursorTreeAdapter作为ExpandableListView.现在我想使用搜索框来显示已过滤的ExpandableListView项.像这样:http://i.imgur.com/8ua7Mkl.png

这是我到目前为止的代码:

MainActivity.java:

package com.example.cursortreeadaptersearch;

import java.util.HashMap;

import android.app.SearchManager;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.ContactsContract;
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.util.Log;
import android.widget.ExpandableListView;
import android.widget.SearchView;
import android.widget.SearchView.OnCloseListener;
import android.widget.SearchView.OnQueryTextListener;

import com.actionbarsherlock.app.SherlockFragmentActivity;

public class MainActivity extends SherlockFragmentActivity {

    private SearchView search;
    private MyListAdapter listAdapter;
    private ExpandableListView myList;

    private final String DEBUG_TAG = getClass().getSimpleName().toString();

    /**
     * The columns we are interested in from the database
     */
    static …
Run Code Online (Sandbox Code Playgroud)

java search android android-cursor simplecursortreeadapter

15
推荐指数
1
解决办法
4022
查看次数

Android MVP:在Presenter中安全使用Context

在我的应用程序中,我使用ContentProvider和使用LoaderManager.LoaderCallbacks<Cursor>.

片段(查看)

public class ArticleCatalogFragment extends BaseFragment
        implements ArticleCatalogPresenter.View,
        LoaderManager.LoaderCallbacks<Cursor> {

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return onCreateArticleCatalogLoader(args);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {        
         data.registerContentObserver(new LoaderContentObserver(new Handler(), loader));
         updateUI(data);        
    }   

    private Loader onCreateArticleCatalogLoader(Bundle args) {
            int categoryId = args.getInt(CATEGORY_ID);
            Loader loader = new ArticleCatalogLoader(this.getActivity(), categoryId);            
            return loader;
    }

}
Run Code Online (Sandbox Code Playgroud)

从MVP的角度来看,我需要:

主持人

public class ArticleCatalogPresenter extends BasePresenter
        implements LoaderManager.LoaderCallbacks<Cursor> {

    View view;

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return onCreateArticleCatalogLoader(args); …
Run Code Online (Sandbox Code Playgroud)

mvp android design-patterns android-cursor

15
推荐指数
1
解决办法
5956
查看次数

尝试重新打开已经关闭的对象:java.lang.IllegalStateException:?

我知道这个问题在SO中多次提出过,但我无法弄清楚我的确切问题.

我使用以下代码从数据库(表1)获取数据,并根据检索值更新另一个Table2.它在一些Android版本中工作正常,但是当我用Android 4.0.3进行测试时.我这个迷途java.lang.IllegalStateException:?.attempt to re-open an already-closed objectsum_cursor.moveToNext();.

我在AsyncTask中使用此代码.

 /** Sum of total matched values*/
            Cursor sum_cursor = db.gettotalMatchvalue(this);
             if(sum_cursor!=null)
             {
                 sum_cursor.moveToFirst();
                 for(int j=0; j<sum_cursor.getCount();j++)
                 {    
                     float totalmatchedscore = sum_cursor.getInt(0);
                     float totalingredients = Float.parseFloat(sum_cursor.getString(sum_cursor.getColumnIndex(APPDatabase.CK_TOTALINCREDIENTS)));
                     /**average = totalscore/totalingredients*/
                     double average = totalmatchedscore/totalingredients;
                     int id = Integer.parseInt(sum_cursor.getString(sum_cursor.getColumnIndex(APPDatabase.CK_ID))); 

                 db.updateAverage(id, average); 
                 sum_cursor.moveToNext(); //Here is the problem
                 }  
             }   
             db.close();  
Run Code Online (Sandbox Code Playgroud)

我的更新方法编码

/** Update average */
public void updateAverage(int id,double average)
{
    SQLiteDatabase db = getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(CK_FINALVALUE,average); …
Run Code Online (Sandbox Code Playgroud)

android illegalstateexception android-cursor android-activity

14
推荐指数
1
解决办法
1万
查看次数

Android数据库 - 由于连接池已关闭,无法执行此操作

我有android数据库和游标的奇怪问题.不时(非常罕见)发生,我收到客户的崩溃报告.很难找到崩溃的原因,因为我有大约150,000个活跃用户,每周大约有1个报告,所以这真的是一个小错误.这是例外:

STACK_TRACE=java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:962)
at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:599)
at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:834)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:144)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
at sk.mildev84.agendareminder.a.c.a(SourceFile:169)
Run Code Online (Sandbox Code Playgroud)

在每个游标"迭代和探索"之前,我使用此代码确保一切正常:

db = instance.getWritableDatabase();
cursor = db.rawQuery(selectQuery, null);

if (isCursorEmptyOrNotPrepared(cursor)) {
    ...
    }

private synchronized boolean isCursorEmptyOrNotPrepared(Cursor cursor) {
        if (cursor == null)
            return true;

        if (cursor.isClosed())
            return true;

        if (cursor.getCount() == 0) // HERE IT CRASHES
            return true;

        return false;
    }
Run Code Online (Sandbox Code Playgroud)

它符合一致:

if (cursor.getCount() == 0)
Run Code Online (Sandbox Code Playgroud)

谁知道为什么?我想,我正在检查所有可能的例外情况和条件......为什么我的应用程序崩溃了?

PS:所有数据库方法都是同步的,我在所有情况下都正确地打开和关闭数据库/游标,我多次检查它.

database android android-cursor

14
推荐指数
2
解决办法
2万
查看次数

Intent.ACTION_PICK为某些联系人返回空光标

我有一个应用程序,其中一个方面是用户选择联系人并通过应用程序向该联系人发送文本.该应用程序仅适用于某些联系人,而其他联系人则失败 更确切地说:

对于我手工输入联系人的联系人,可以Intent.ACTION_PICK轻松找到并将其返回给应用程序,即cursor.moveToFirst()属实.

但对于Facebook导入的联系人(我的手机设置为与Facebook联系人同步),android.database.CursorIndexOutOfBoundsException我点击联系人后得到以下内容.我有一个明显的问题是:在我真正选择了一个联系人后,为什么结果大小为0?为什么是cursor.moveToFirst()假的?

...Caused by: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
05-15 17:57:04.741: E/AndroidRuntime(21301):    at android.database.AbstractCursor.checkPosition(AbstractCursor.java:418)
05-15 17:57:04.741: E/AndroidRuntime(21301):    at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
05-15 17:57:04.741: E/AndroidRuntime(21301):    at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
05-15 17:57:04.741: E/AndroidRuntime(21301):    at android.database.CursorWrapper.getString(CursorWrapper.java:114)
05-15 17:57:04.741: E/AndroidRuntime(21301):    at com.company.Game.SendTextActivity.onActivityResult(SendTextActivity.java:118)
05-15 17:57:04.741: E/AndroidRuntime(21301):    at android.app.Activity.dispatchActivityResult(Activity.java:5436)
05-15 17:57:04.741: E/AndroidRuntime(21301):    at android.app.ActivityThread.deliverResults(ActivityThread.java:3188)
05-15 17:57:04.741: E/AndroidRuntime(21301):    ... 11 more
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

dispatchIntent:

Intent pickContactIntent = new Intent(Intent.ACTION_PICK,  Uri.parse("content://contacts"));
pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone …
Run Code Online (Sandbox Code Playgroud)

sqlite android contacts android-intent android-cursor

13
推荐指数
1
解决办法
849
查看次数

何时关闭SimpleCursorAdapter中使用的Cursor

我正在使用SimpleCursorAdapter在ListView中显示结果,但由于我必须在搜索期间(使用SearchView小部件)多次查询我的数据库,因此我担心光标可能会被打开.

这是我查询我的数据库并在ListView中显示结果的方法:

class SearchCustomers extends AsyncTask<String,Void,Cursor>{

        @Override
        protected Cursor doInBackground(String... params) {         
            //get the query
            String query=params[0].toLowerCase(Locale.getDefault());
            Cursor cursor=mDB.searchCustomersByName((query != null ? query : "@@@@"));
            return cursor;

        }

        @Override
        protected void onPostExecute(Cursor result) {           

            if (result != null) {

                String[] from = new String[] { QuickOrderDB.ID,
                        QuickOrderDB.NAME,
                        QuickOrderDB.ADDRESS,
                        QuickOrderDB.PHONE_NUMBER };

                int[] to = new int[] { R.id.customerIDTextView,
                        R.id.customerNameTextView,R.id.customerAddressTextView ,
                        R.id.customerPhoneTextView };

                SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(SearchCustomersActivity.this,
                        R.layout.results_customer_item, result, from, to);
                mResultsListView.setAdapter(cursorAdapter);                 

            }
        }           

    }   
Run Code Online (Sandbox Code Playgroud)

我已经尝试了很多东西来关闭光标,但即使我mResultsListView.setAdapter(cursorAdapter);在结果总是相同之后关闭它:一个空的ListView.

我已经看到了几个问题,其中提到光标将自动关闭,但我想确保这是真的. …

android simplecursoradapter android-cursor searchview

13
推荐指数
1
解决办法
4805
查看次数

LoaderManager做什么?

我试图了解loadermanager做了什么.任何人都可以与它共享一个例子吗?我创建游标时必须使用它们吗?如果不是我应该如何使用?非常感谢一个简单的例子.

android android-cursor android-loadermanager android-cursorloader

12
推荐指数
1
解决办法
5756
查看次数

MediaStore.Images.Thumbnails.getThumbnail返回错误的缩略图而不是NULL

考虑如下图所示的场景:

本土Galery

三张照片,其中一张是大型GIF文件(3MP).

我正在查询MediaStore以检索相应的缩略图.如果我使用此sortOrder通过CursorLoader初始化Cursor:

MediaStore.Images.Media.DATE_ADDED + " DESC""
Run Code Online (Sandbox Code Playgroud)

会发生什么: MediaStore返回先前成功检索的缩略图:

DESC

预期的行为:当MediaStore由于某种原因无法检索给定图像的缩略图时,它必须返回NULL,根据其Javadoc:"...返回一个Bitmap实例.如果与origId关联的原始图像不是,则它可以为null存在或记忆不够."

如果我用这个sortOrder初始化Cursor:

MediaStore.Images.Media.DATE_ADDED + " ASC""
Run Code Online (Sandbox Code Playgroud)

它运行得很好:

ASC

但是我不能简单地改变sortOrder,因为要求是先显示最新的图片.

下面是我的示例代码,这里是完整的示例项目以及用于重现的三个图像.

package com.example.getimagefrommediastore;

import android.app.Activity;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import android.widget.ImageView;
import android.widget.TextView;

public class GetThumbnailsFromMediaStoreSampleActivity extends Activity {

TextView mThumb_id_01;
TextView mThumb_id_02;
TextView mThumb_id_03;
ImageView mImg_01;
ImageView mImg_02;
ImageView mImg_03;
boolean isThumb01 = true; // Simple flag to control this example
boolean isThumb02 = true;
Cursor mCursorLoader;
int mColumnIndex;
long …
Run Code Online (Sandbox Code Playgroud)

java android mediastore android-cursor android-cursorloader

12
推荐指数
1
解决办法
4923
查看次数

对于某些文件,Android MediaStore查询MediaStore.MediaColumns.TITLE列为null

我正在对Android的MediaStore文件数据库查询- - MediaStore.Files.getContentUri("external"),对于某些特定的文件夹,无论是MediaStore.MediaColumns.TITLEMediaStore.MediaColumns.DISPLAY_NAME是零,而其他文件夹,这个值存在.我找不到任何关于MediaStore.MediaColumns.TITLE可能为null的文档.

对于一些内部Android目录会发生这种情况,例如:

_data: /storage/emulated/0/Music, title: null, _display_name: null
_data: /storage/emulated/0/Notifications, title: null, _display_name: null
_data: /storage/emulated/0/Pictures, title: null, _display_name: null
Run Code Online (Sandbox Code Playgroud)

但是,对于其他一些文件夹,标题是:

 _data: /storage/emulated/0/Android, title: Android, _display_name: null
 _data: /storage/emulated/0/DCIM, title: DCIM, _display_name: null
 _data: /storage/emulated/0/Download, title: Download, _display_name: null
Run Code Online (Sandbox Code Playgroud)

所有数据都直接来自MediaStore查询.

我知道我可以直接使用数据但我正在尝试根据TITLE对查询进行排序,这会导致错误的结果,因为有些是null.

这是预期的行为吗?如何处理它并检索按标题正确排序的所有文件?

android sql-order-by mediastore android-cursor

12
推荐指数
1
解决办法
568
查看次数