cdr*_*oid 13 java sqlite android android-fragments
所以我已经到了需要为我的应用程序实现SQLite数据库的地步.在"繁忙的编码器Android开发指南"之后,我创建了一个扩展的DatabaseHelper类SQLiteOpenHelper.
我的一个用例是对数据库运行查询并在a ListView内显示结果Fragment(我使用支持库中的片段).
根据我的理解,使用managedQuery()并不是真正合适的,即使它是不推荐的,因为这个方法中封装的一些逻辑实际上是在主线程上执行的,具体reQuery()是我理解的时候执行的Activity重新启动.
所以我Loader第一次尝试熟悉这门课,只看到这个:
"The only supplied concrete implementation of a Loader is CursorLoader, and that is only for use with a ContentProvider"
我最初的想法是实现我自己的内容提供商,并可能阻止其他应用程序访问它,然后我ContentProvider通过developer.android.com 阅读文档中的以下内容:
"You don't need a provider to use an SQLite database if the use is entirely within your own application."
我也一直在玩这个:
https://github.com/commonsguy/cwac-loaderex
但我不熟悉这个项目,也不确定它是否可以在生产环境中使用.
所以,现在我能想到的是AsyncTask在我的内部创建一堆实例Fragment并适当地管理它们的生命周期,确保它们在需要时被取消等等.
还有其他选择吗?
我认为实现内容提供商是一个好主意,无论数据是否都无法在应用程序之外访问.它提供了非常现代化的界面,根据我的经验,您的应用程序容易出现数据库锁定问题和其他特定于数据库的问题.
我已经在我的最新项目中实现了它,我很高兴使用它.
我推荐OrmLite库,一个可以用于Android的轻量级对象关系映射.这个图书馆将让您的生活更轻松.您不需要手动创建或更新数据库,您不需要专注于管理数据库连接,所有查询选择,插入,更新都会更容易用一种DAO方法(通常您不需要编写自己的SQL查询)和很多功能.他们有一些你可以开始的例子.
如果你想使用Loader,有一个ORMLite Extras,ORMLite的附加功能可用github(你可以使用与支持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();
}
}
Run Code Online (Sandbox Code Playgroud)
适配器
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;
}
}
Run Code Online (Sandbox Code Playgroud)
和PreparedQuery上面提供游标适配器的自定义Dao :
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();
}
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助!
您可以扩展Loader类以执行其他异步工作,例如直接从数据库加载.
这是一个例子
编辑:添加了Loader使用的更好示例.
最后设法找到真正帮助我理解工作原理的教程.
通过扩展loader类,您可以避免弄乱内容观察者,并且很容易实现(最后)代码中需要进行的修改
LoaderManager.LoaderCallbacks<D>,D您的数据列表在哪里(代码段1)代码段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);
// ...
}
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
代码段2:你的自定义加载器的模式:(我已经对观察者的事情进行了评论,因为我认为从一开始就很难实现它,你可以简单地回想起加载器而不会搞乱自动刷新)
public class SampleLoader extends AsyncTaskLoader<List<SampleItem>> {
// We hold a reference to the Loader’s data here.
private List<SampleItem> mData;
public SampleLoader(Context ctx) {
// Loaders may be used across multiple Activitys (assuming they aren't
// bound to the LoaderManager), so NEVER hold a reference to the context
// directly. Doing so will cause you to leak an entire Activity's context.
// The superclass constructor will store a reference to the Application
// Context instead, and can be retrieved with a call to getContext().
super(ctx);
}
/****************************************************/
/** (1) A task that performs the asynchronous load **/
/****************************************************/
@Override
public List<SampleItem> loadInBackground() {
// This method is called on a background thread and should generate a
// new set of data to be delivered back to the client.
List<SampleItem> data = new ArrayList<SampleItem>();
// TODO: Perform the query here and add the results to 'data'.
return data;
}
/********************************************************/
/** (2) Deliver the results to the registered listener **/
/********************************************************/
@Override
public void deliverResult(List<SampleItem> data) {
if (isReset()) {
// The Loader has been reset; ignore the result and invalidate the data.
releaseResources(data);
return;
}
// Hold a reference to the old data so it doesn't get garbage collected.
// We must protect it until the new data has been delivered.
List<SampleItem> oldData = mData;
mData = data;
if (isStarted()) {
// If the Loader is in a started state, deliver the results to the
// client. The superclass method does this for us.
super.deliverResult(data);
}
// Invalidate the old data as we don't need it any more.
if (oldData != null && oldData != data) {
releaseResources(oldData);
}
}
/*********************************************************/
/** (3) Implement the Loader’s state-dependent behavior **/
/*********************************************************/
@Override
protected void onStartLoading() {
if (mData != null) {
// Deliver any previously loaded data immediately.
deliverResult(mData);
}
// Begin monitoring the underlying data source.
////if (mObserver == null) {
////mObserver = new SampleObserver();
// TODO: register the observer
////}
//// takeContentChanged() can still be implemented if you want
//// to mix your refreshing in that mechanism
if (takeContentChanged() || mData == null) {
// When the observer detects a change, it should call onContentChanged()
// on the Loader, which will cause the next call to takeContentChanged()
// to return true. If this is ever the case (or if the current data is
// null), we force a new load.
forceLoad();
}
}
@Override
protected void onStopLoading() {
// The Loader is in a stopped state, so we should attempt to cancel the
// current load (if there is one).
cancelLoad();
// Note that we leave the observer as is. Loaders in a stopped state
// should still monitor the data source for changes so that the Loader
// will know to force a new load if it is ever started again.
}
@Override
protected void onReset() {
// Ensure the loader has been stopped.
onStopLoading();
// At this point we can release the resources associated with 'mData'.
if (mData != null) {
releaseResources(mData);
mData = null;
}
// The Loader is being reset, so we should stop monitoring for changes.
////if (mObserver != null) {
// TODO: unregister the observer
//// mObserver = null;
////}
}
@Override
public void onCanceled(List<SampleItem> data) {
// Attempt to cancel the current asynchronous load.
super.onCanceled(data);
// The load has been canceled, so we should release the resources
// associated with 'data'.
releaseResources(data);
}
private void releaseResources(List<SampleItem> data) {
// For a simple List, there is nothing to do. For something like a Cursor, we
// would close it in this method. All resources associated with the Loader
// should be released here.
}
/*********************************************************************/
/** (4) Observer which receives notifications when the data changes **/
/*********************************************************************/
// NOTE: Implementing an observer is outside the scope of this post (this example
// uses a made-up "SampleObserver" to illustrate when/where the observer should
// be initialized).
// The observer could be anything so long as it is able to detect content changes
// and report them to the loader with a call to onContentChanged(). For example,
// if you were writing a Loader which loads a list of all installed applications
// on the device, the observer could be a BroadcastReceiver that listens for the
// ACTION_PACKAGE_ADDED intent, and calls onContentChanged() on the particular
// Loader whenever the receiver detects that a new application has been installed.
// Please don’t hesitate to leave a comment if you still find this confusing! :)
////private SampleObserver mObserver;
}
Run Code Online (Sandbox Code Playgroud)
代码段3:如何首次调用加载程序(仅限)
// Initialize a Loader with an id. If the Loader with this id is not
// initialized before
getLoaderManager().initLoader(LOADER_ID, null, this);
Run Code Online (Sandbox Code Playgroud)
代码段4:用于刷新数据(调用查询)
// Check if the loader exists and then restart it.
if (getLoaderManager().getLoader(LOADER_ID) != null)
getLoaderManager().restartLoader(LOADER_ID, null, this);
Run Code Online (Sandbox Code Playgroud)
参考:
这些的完整代码也由创建者在github上传
| 归档时间: |
|
| 查看次数: |
3939 次 |
| 最近记录: |