Java Android:片段、SQLite和加载程序

Java Android:片段、SQLite和加载程序,java,android,sqlite,android-fragments,Java,Android,Sqlite,Android Fragments,因此,我需要为我的应用程序实现一个SQLite数据库。 根据“Android开发的繁忙程序员指南”,我创建了一个DatabaseHelper类,它扩展了SQLiteOpenHelper 我的一个用例是对数据库运行查询,并在片段中的列表视图上显示结果(我使用支持库中的片段) 据我所知,使用managedQuery()并不是很合适,即使是这样,也不建议使用,因为封装在该方法中的一些逻辑实际上是在主线程上执行的,特别是reQuery()据我所知,这是在重新启动活动时执行的 因此,我第一次尝试熟悉Loa

因此,我需要为我的应用程序实现一个SQLite数据库。 根据“Android开发的繁忙程序员指南”,我创建了一个DatabaseHelper类,它扩展了
SQLiteOpenHelper

我的一个用例是对数据库运行查询,并在
片段中的
列表视图上显示结果(我使用支持库中的片段)

据我所知,使用
managedQuery()
并不是很合适,即使是这样,也不建议使用,因为封装在该方法中的一些逻辑实际上是在主线程上执行的,特别是
reQuery()
据我所知,这是在重新启动
活动时执行的

因此,我第一次尝试熟悉
Loader
类,结果发现:

“加载程序提供的唯一具体实现是CursorLoader,它仅用于ContentProvider”

我最初的想法是实现我自己的内容提供商,并可能阻止其他应用程序访问它,然后我通过developer.android.com在
ContentProvider
文档中阅读了以下内容:

“如果完全在您自己的应用程序中使用SQLite数据库,则不需要提供程序。”

我也一直在玩这个:

但我不熟悉这个项目,也不确定它是否可以用于生产环境

所以,现在我所能想到的就是在我的
片段中创建一组
AsyncTask
实例,并适当地管理它们的生命周期,确保它们在需要时被取消等等


还有其他选择吗?

我认为实现内容提供商是一个好主意,不管数据在应用程序之外无法访问。它提供了非常现代的界面,根据我的经验,它使您的应用程序容易出现数据库锁定问题和其他特定于数据库的问题


我在最新的项目中实现了它,我很高兴使用它。

您可以扩展Loader类,以便执行其他异步工作,例如直接从数据库加载

这就是一个例子


编辑:添加了一个更好的加载程序使用示例

终于找到了真正帮助我理解事情是如何运作的教程

通过扩展loader类,您可以避免与内容观察者发生冲突,并且它非常容易实现(最后) 代码中需要进行的修改如下

  • 添加
    LoaderManager.LoaderCallbacks的实现,其中
    D
    是您的数据列表(代码段1)
  • 创建加载程序类,复制代码段2,并添加从数据库加载数据
  • 最后调用装入器1调用init,然后刷新restart调用。(片段2和3)
片段1:如何将加载程序与片段“链接”:

public static class AppListFragment extends ListFragment implements
      LoaderManager.LoaderCallbacks<List<SampleItem>> {

  public Loader<List<SampleItem>> onCreateLoader(int id, Bundle args) { 
     //...
     return new SampleLoader (getActivity());
  }

  public void onLoadFinished(Loader<List<SampleItem>> loader, List<SampleItem> data) {
    // ... 
     mAdapter.setData(data);

     if (isResumed()) {
       setListShown(true);
     } else {
       setListShownNoAnimation(true);
     }
    // ... 
 }

  public void onLoaderReset(Loader<List<SampleItem>> loader) { 
    // ... 
    mAdapter.setData(null);
    // ... 
  }

  /* ... */
}
片段4:用于刷新数据(调用查询)

参考:

  • 代码片段1:从中提取的加载程序的用法
  • 代码片段2:有关更多信息和逻辑,请通读本文
  • 代码片段3和4:它们只是加载程序的用法

完整的代码也由创建者上传到

如果你的数据库包含数千条记录,考虑MaldiMAD的答案
如果不让它保持愚蠢和简单,请使用

SQLiteOpenHelper
并创建一个方法,将数据作为字符串数组返回给您,或者定义一个对象。

也可以使用自定义/常规或。

我使用SQLiteOpenHelper创建数据库。我为所有表创建了Java类,当我从数据库中获取数据时,我将其放入ArrayList中。然后我将ArrayList加载到Listview的适配器中。

我推荐library,它是一种轻量级的对象关系映射,可以在Android上使用。这个图书馆会让你的生活更轻松。您不需要手动创建或更新数据库,也不需要专注于管理数据库连接,使用
DAO
方法(通常您不需要编写自己的sql查询)和许多功能,所有查询选择、插入、更新都会更容易。你可以从他们开始

如果您想使用
加载程序
,则可以在
github
上使用ORMLite的附加功能(您可以使用与支持android库兼容的支持包)。以下是我上一个项目的使用示例:

public class EventsFragment extends Fragment implements LoaderCallbacks<Cursor>{
   private static final int LOADER_ID = EventsFragment.class.getName().hashCode();
   @Override
   public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getLoaderManager().initLoader(LOADER_ID, null, this);
   }

    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View layoutRoot = inflater.inflate(
            R.layout.fragment_events, null);
    lvEvents = (ListView) layoutRoot.findViewById(R.id.lvEvents);   

    adapter = new EventAdapter(getActivity(), null, null);
    lvEvents.setAdapter(adapter);

    return layoutRoot;
}

    @Override
    public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
       try {
           PreparedQuery<Event> query = getDatabaseHelper().getEventDao().getQuery();
           return getDatabaseHelper().getEventDao().getSQLCursorLoader(query );
        } catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
    adapter.swapCursor(cursor);
    try {
        adapter.setQuery(getDatabaseHelper().getEventDao().getQuery());
    } catch (SQLException e) {
        e.printStackTrace();
    }
      }

@Override
public void onLoaderReset(Loader<Cursor> arg0) {
    adapter.swapCursor(null);
}

    private OrmliteDatabaseHelper getDatabaseHelper(){
         return ((MainActivity)getActivity()).getDatabaseHelper();
    }
 }

希望这能有所帮助

我会使用Commonware中的SQLiteCursorLoader,它似乎能完全满足您的需求。我认为在生产应用程序中使用它没有任何问题。您需要只显示数据库中的数据,还是还需要对数据进行操作?@NickF在这种情况下,我只想检索数据。如其他地方所述,这可能适用于较小的记录集,并且可能存在问题。它是否在运行时阻止UI线程?如果你有一个在后台线程中使用的策略,你能更新你的答案来反映这一点吗?我还想在答案中看到一个好的参考样本谢谢你的意思是说实现一个内容提供者会使你的应用程序“免疫”锁定问题,而不是说它会使你的应用程序“容易出错”锁定问题吗?
  // Initialize a Loader with an id. If the Loader with this id is not 
  // initialized before
  getLoaderManager().initLoader(LOADER_ID, null, this);
 // Check if the loader exists and then restart it.
 if (getLoaderManager().getLoader(LOADER_ID) != null)
     getLoaderManager().restartLoader(LOADER_ID, null, this);
public class EventsFragment extends Fragment implements LoaderCallbacks<Cursor>{
   private static final int LOADER_ID = EventsFragment.class.getName().hashCode();
   @Override
   public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getLoaderManager().initLoader(LOADER_ID, null, this);
   }

    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View layoutRoot = inflater.inflate(
            R.layout.fragment_events, null);
    lvEvents = (ListView) layoutRoot.findViewById(R.id.lvEvents);   

    adapter = new EventAdapter(getActivity(), null, null);
    lvEvents.setAdapter(adapter);

    return layoutRoot;
}

    @Override
    public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
       try {
           PreparedQuery<Event> query = getDatabaseHelper().getEventDao().getQuery();
           return getDatabaseHelper().getEventDao().getSQLCursorLoader(query );
        } catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
    adapter.swapCursor(cursor);
    try {
        adapter.setQuery(getDatabaseHelper().getEventDao().getQuery());
    } catch (SQLException e) {
        e.printStackTrace();
    }
      }

@Override
public void onLoaderReset(Loader<Cursor> arg0) {
    adapter.swapCursor(null);
}

    private OrmliteDatabaseHelper getDatabaseHelper(){
         return ((MainActivity)getActivity()).getDatabaseHelper();
    }
 }
 public class EventAdapter extends OrmliteCursorAdapter<Event>{

public EventAdapter(Context context, Cursor c, PreparedQuery<Event> query) {
    super(context, c, query);
}

@Override
public void bindView(View itemView, Context context, Event item) {
    TextView tvEventTitle = (TextView) itemView.findViewById(R.id.tvEventTitle); 
    TextView tvEventStartDate = (TextView) itemView.findViewById(R.id.tvEventStartDate);

    tvEventTitle.setText(item.getTitle());
    tvEventStartDate.setText(item.getFormatStartDate());
}

@Override
public View newView(Context context, Cursor arg1, ViewGroup arg2) {
    LayoutInflater inflater = LayoutInflater.from(context);
    View retView = inflater.inflate(R.layout.event_item_row, arg2, false);
    return retView;
}
 }
public interface IEventDao extends Dao<Event, Integer>{
    PreparedQuery<Event> getQuery() throws SQLException;
    OrmliteCursorLoader<Event> getSQLCursorLoader(Context context, PreparedQuery<Event> query) throws SQLException;
}

public class EventDao extends AndroidBaseDaoImpl<Event, Integer> implements IEventDao{

public EventDao(ConnectionSource connectionSource) throws SQLException {
    super(connectionSource, Event.class);
}

public EventDao(ConnectionSource connectionSource,
        DatabaseTableConfig<Event> tableConfig) throws SQLException {
    super(connectionSource, tableConfig);
}

@Override
public PreparedQuery<Event> getQuery() throws SQLException{
    return queryBuilder().prepare();
}
}