在数据库操作中,只有查询是比较难的,因为这个操作数据过多的话很可能会造成主线程阻塞。以前我总是把查询数据的方法放在新开的子线程中来进行,今天发现了一个好方法。
并且这个方法不管在Acitivity里还是在Fragment都很好用。
首先呢要声明一个LoaderManager对象,
然后要初始化LoaderManager,第一个参数id,可以随便写,第二个参数是可选项,第三个是回调方法
然后需要实现callback接口public class MainActivity extends Activity implements LoaderCallbacks<Cursor>
会生成三个方法,在具体代码中会说明方法的作用,
最后还要写一个类来实现一个异步的Loader,这里需要注意的是这个继承的类必须是静态的
static class MyAsycLoader extends AsyncTaskLoader<Cursor>
java代码
package com.example.loader; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.app.Activity; import android.app.LoaderManager; import android.app.LoaderManager.LoaderCallbacks; import android.content.AsyncTaskLoader; import android.content.ContentResolver; import android.content.Context; import android.content.Loader; import android.database.Cursor; import android.widget.Toast; public class MainActivity extends Activity implements LoaderCallbacks<Cursor> { private LoaderManager manager; static ContentResolver resolver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); resolver = getContentResolver(); manager = getLoaderManager(); manager.initLoader(1001, null, this); // 调用这个方法必须在主线程中,如果数据发生了改变,显示的数据会随之改变 manager.getLoader(1001).onContentChanged(); } // 返回要查询的对象 // 完成查询操作,把结果返回给调用者 @Override public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { // TODO Auto-generated method stub return new MyAsycLoader(this); } // 更新ui操作 @Override public void onLoadFinished(Loader<Cursor> arg0, Cursor query) { while (query.moveToNext()) { System.out.println(query.getString(0)); Toast.makeText(this, query.getString(0), 0).show(); } } @Override public void onLoaderReset(Loader<Cursor> arg0) { // TODO Auto-generated method stub } // 异步的loader // 这个类必须为static static class MyAsycLoader extends AsyncTaskLoader<Cursor> { public MyAsycLoader(Context context) { super(context); // TODO Auto-generated constructor stub } // 执行查询操作 @Override public Cursor loadInBackground() { Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; // 要查询的字段 String[] projection = { MediaStore.Video.Media.TITLE, MediaStore.Video.Media.DURATION, MediaStore.Video.Media.SIZE, MediaStore.Video.Media.DATA }; Cursor query = resolver.query(uri, projection, null, null, null); return query; } //必须实现 @Override protected void onStartLoading() { // TODO Auto-generated method stub super.onStartLoading(); // 如果内容发生改变,通知调用者 if (takeContentChanged()) { forceLoad(); } } } }
这里更新ui的操作只是弹出了吐司。
下面来看在Fragment里的操作,因为Fragment的生命周期比较复杂
package com.mingrikeji.fragment; import java.util.ArrayList; import java.util.List; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.MediaStore; import android.support.v4.app.Fragment; import android.support.v4.app.ListFragment; 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.text.format.Formatter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.example.videoplayer.R; import com.mingrikeji.bean.VideoBean; import com.mingrikeji.utils.PlayerUtils; /** * A simple {@link android.support.v4.app.Fragment} subclass. * */ public class TwoFragment extends ListFragment implements LoaderCallbacks<Cursor> { // 声明LoaderManager对象 private LoaderManager loader; // 声明适配器对象 private VideoAdapter mAdapter; @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); // 获得LoaderManager loader = getLoaderManager(); // 实例化VideoAdapter mAdapter = new VideoAdapter(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // 初始化一个Loader,并注册回调事件,第一个参数id,可以随便写,第二个参数是可选项,第三个是回调方法 loader.initLoader(0, null, this); return inflater.inflate(R.layout.fragment_two, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onActivityCreated(savedInstanceState); } @Override public void onListItemClick(ListView l, View v, int position, long id) { // TODO Auto-generated method stub super.onListItemClick(l, v, position, id); VideoBean video = (VideoBean) mAdapter.getItem(position); Toast.makeText(getActivity(), video.getPath(), 0).show(); } class VideoAdapter extends BaseAdapter { private List<VideoBean> list; // 绑定数据 public void bindData(List<VideoBean> list) { this.list = list; } // 获取显示列表的总数 @Override public int getCount() { return list.size(); } // 返回当前位置的对象 @Override public Object getItem(int arg0) { return list.get(arg0); } // 返回当前位置的id @Override public long getItemId(int arg0) { return arg0; } // 返回要显示的view对象 @Override public View getView(int position, View arg1, ViewGroup arg2) { // 声明view View v = null; // 声明ViewHolder对象 ViewHolder viewHolder = null; // 判断是否有缓存,有的话就可以用缓存,没有的话重新把视图对象转化成view对象 if (arg1 != null) { v = arg1; viewHolder = (ViewHolder) v.getTag(); } else { // 把布局文件转化成视图对象 v = View.inflate(getActivity(), R.layout.item_videolist, null); // 实例化ViewHolder viewHolder = new ViewHolder(); // 实例化标题textview viewHolder.tv_title = (TextView) v .findViewById(R.id.item_videolist_title); // 实例化大小textview viewHolder.tv_size = (TextView) v .findViewById(R.id.item_videolist_size); // 实例化时间textview viewHolder.tv_time = (TextView) v .findViewById(R.id.item_videolist_time); // 放入tag对象里 v.setTag(viewHolder); } // 根据位置设置标题 viewHolder.tv_title.setText(list.get(position).getTitle()); // 根据位置设置时间,和文件长度 String size = PlayerUtils.getTime(list.get(position).getTime()); String time = Formatter.formatFileSize(getActivity(), Long.parseLong(list.get(position).getSize())); viewHolder.tv_time.setText(time); viewHolder.tv_size.setText(size); return v; } } /** * ViewHolder对象 * * @author Administrator * */ static class ViewHolder { //标题 TextView tv_title; //长度 TextView tv_size; //时间 TextView tv_time; } //返回要查询的对象 //完成查询操作,把结果返回给调用者 @Override public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; // 要查询的数据 String[] projection = { MediaStore.Video.Media.TITLE, MediaStore.Video.Media.DURATION, MediaStore.Video.Media.SIZE, MediaStore.Video.Media.DATA }; CursorLoader cu = new CursorLoader(getActivity(), uri, projection, null, null, null); return cu; } //更新ui操作 @Override public void onLoadFinished(Loader<Cursor> arg0, Cursor query) { // TODO Auto-generated method stub List<VideoBean> list = new ArrayList<VideoBean>(); while (query.moveToNext()) { VideoBean video = new VideoBean(); // 设置bean video.setTitle(query.getString(0)); video.setTime(query.getString(1)); video.setSize(query.getString(2)); video.setPath(query.getString(3)); list.add(video); } // 发送数据到适配器 mAdapter.bindData(list); // 设置适配器 setListAdapter(mAdapter); } @Override public void onLoaderReset(Loader<Cursor> arg0) { } }
在Fragment里我们用到了
CursorLoader ,这个方法同样的不会造成ANR,就不用写异步的loader了。
CursorLoader 这个方法有两个构造方法,这里用的是第一个,第二个是直接可以传递上下文,然后一个一个的设置参数。