- 浏览: 928584 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
itzhongyuan:
java Random类详解 -
david_je:
你好,我看到你在C里面回调JAVA里面的方法是在native里 ...
Android NDK开发(1)----- Java与C互相调用实例详解 -
fykyx521:
请求锁是在 oncreate 释放实在ondestroy?? ...
Android如何保持程序一直运行 -
aduo_vip:
不错,总结得好!
Android读取assets目录下的资源 -
f839903061:
给的网址很给力哦!
Android 4.0.1 源码下载,编译和运行
在Android 3.0中提供了一个新概念Loaders,通过LoaderManager类可以很轻松的异步加载数据从Fragment或Activity中,Loaders提供了回调机制通知最终的运行结果,有点类似AsyncTask类,但由于Loader对于并发可以用过Loader管理器统一管理,所以更适合批量处理多个异步任务的处理(当然内部仍然是多线程)。下面就让Android123一起和大家看下honeycomb中的新特性吧,对于解决多重异步I/O加快Android平板应用的运行是十分有效的。
一、LoaderManager
LoaderManager类位于android.app.LoaderManager,提供了以下几个方法
abstract void destroyLoader(int id) //停止并移除loader通过ID
abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) //打印LoaderManager的状态到一个流中
static void enableDebugLogging(boolean enabled) //启用debug记录
abstract <D> Loader<D> getLoader(int id) //返回找到的ID或没有匹配的在Loader中
abstract <D> Loader<D> initLoader(int id, Bundle args, LoaderCallbacks<D> callback) //初始化Loader使其成为活动状态
abstract <D> Loader<D> restartLoader(int id, Bundle args, LoaderCallbacks<D> callback) //启动一个新的或重启一个存在的Loader在管理器中
同时LoaderManager还有一个回调接口android.app.LoaderManager.LoaderCallbacks<D> 用于和LoaderManager交互
abstract Loader<D> onCreateLoader(int id, Bundle args) //举例并返回一个新Loader通过ID
abstract void onLoadFinished(Loader<D> loader, D data) //当前面一个Loader已经完成时回调
abstract void onLoaderReset(Loader<D> loader) //当一个新的loader或存在的loader重启时回调
二、Loader
Loader类位于android.content.Loader<D>,整体比较复杂,主要成员有
1. 构造方法 Loader(Context context) //作为唯一实例化方法参数只有一个Context
2. Public Methods
void abandon() //高速Loader他在绑定
String dataToString(D data) //用于调试,转换一个Loader数据类的实例为字符串用于打印
void deliverResult(D data) //发送一个load注册的listener结果
void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) //打印loader状态通过给定的流
void forceLoad() //强制一个异步载入
Context getContext() //返回Context实例
int getId()
boolean isAbandoned() //判断是否已经绑定
boolean isReset() //判断是否已经重启
boolean isStarted() //判断是否已经执行
void onContentChanged() //内容变化回调
registerListener(int id, OnLoadCompleteListener<D> listener)
void reset() //重置一个Loader的状态
final void startLoading() //启动一个异步的载入从Loader的数据
void stopLoading() //停止载入
boolean takeContentChanged() String toString()
void unregisterListener(OnLoadCompleteListener<D> listener)
提供的子类 android.content.Loader.ForceLoadContentObserver 和 接口 android.content.Loader.OnLoadCompleteListener<D>
为了更清晰的表达Android开发网给出一个SDK例子完整代码,来作分析
public class LoaderThrottle extends Activity {
static final String TAG = "LoaderThrottle";
public static final String AUTHORITY = "com.example.android.apis.app.LoaderThrottle";
public static final class MainTable implements BaseColumns {
// This class cannot be instantiated
private MainTable() {}
public static final String TABLE_NAME = "main";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/main");
public static final Uri CONTENT_ID_URI_BASE
= Uri.parse("content://" + AUTHORITY + "/main/");
public static final String CONTENT_TYPE
= "vnd.android.cursor.dir/vnd.example.api-demos-throttle";
public static final String CONTENT_ITEM_TYPE
= "vnd.android.cursor.item/vnd.example.api-demos-throttle";
public static final String DEFAULT_SORT_ORDER = "data COLLATE LOCALIZED ASC";
public static final String COLUMN_NAME_DATA = "data";
}
static class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "loader_throttle.db";
private static final int DATABASE_VERSION = 2;
DatabaseHelper(Context context) {
// calls the super constructor, requesting the default cursor factory.
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + MainTable.TABLE_NAME + " ("
+ MainTable._ID + " INTEGER PRIMARY KEY,"
+ MainTable.COLUMN_NAME_DATA + " TEXT"
+ ");");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Logs that the database is being upgraded
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
// Kills the table and existing data
db.execSQL("DROP TABLE IF EXISTS notes");
// Recreates the database with a new version
onCreate(db);
}
}
public static class SimpleProvider extends ContentProvider {
// A projection map used to select columns from the database
private final HashMap<String, String> mNotesProjectionMap;
// Uri matcher to decode incoming URIs.
private final UriMatcher mUriMatcher;
// The incoming URI matches the main table URI pattern
private static final int MAIN = 1;
// The incoming URI matches the main table row ID URI pattern
private static final int MAIN_ID = 2;
// Handle to a new DatabaseHelper.
private DatabaseHelper mOpenHelper;
public SimpleProvider() {
// Create and initialize URI matcher.
mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mUriMatcher.addURI(AUTHORITY, MainTable.TABLE_NAME, MAIN);
mUriMatcher.addURI(AUTHORITY, MainTable.TABLE_NAME + "/#", MAIN_ID);
// Create and initialize projection map for all columns. This is
// simply an identity mapping.
mNotesProjectionMap = new HashMap<String, String>();
mNotesProjectionMap.put(MainTable._ID, MainTable._ID);
mNotesProjectionMap.put(MainTable.COLUMN_NAME_DATA, MainTable.COLUMN_NAME_DATA);
}
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
// Assumes that any failures will be reported by a thrown exception.
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Constructs a new query builder and sets its table name
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(MainTable.TABLE_NAME);
switch (mUriMatcher.match(uri)) {
case MAIN:
// If the incoming URI is for main table.
qb.setProjectionMap(mNotesProjectionMap);
break;
case MAIN_ID:
// The incoming URI is for a single row.
qb.setProjectionMap(mNotesProjectionMap);
qb.appendWhere(MainTable._ID + "=?");
selectionArgs = DatabaseUtils.appendSelectionArgs(selectionArgs,
new String[] { uri.getLastPathSegment() });
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (TextUtils.isEmpty(sortOrder)) {
sortOrder = MainTable.DEFAULT_SORT_ORDER;
}
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor c = qb.query(db, projection, selection, selectionArgs,
null /* no group */, null /* no filter */, sortOrder);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
@Override
public String getType(Uri uri) {
switch (mUriMatcher.match(uri)) {
case MAIN:
return MainTable.CONTENT_TYPE;
case MAIN_ID:
return MainTable.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
if (mUriMatcher.match(uri) != MAIN) {
// Can only insert into to main URI.
throw new IllegalArgumentException("Unknown URI " + uri);
}
ContentValues values;
if (initialValues != null) {
values = new ContentValues(initialValues);
} else {
values = new ContentValues();
}
if (values.containsKey(MainTable.COLUMN_NAME_DATA) == false) {
values.put(MainTable.COLUMN_NAME_DATA, "");
}
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(MainTable.TABLE_NAME, null, values);
// If the insert succeeded, the row ID exists.
if (rowId > 0) {
Uri noteUri = ContentUris.withAppendedId(MainTable.CONTENT_ID_URI_BASE, rowId);
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
String finalWhere;
int count;
switch (mUriMatcher.match(uri)) {
case MAIN:
count = db.delete(MainTable.TABLE_NAME, where, whereArgs);
break;
case MAIN_ID:
finalWhere = DatabaseUtils.concatenateWhere(
MainTable._ID + " = " + ContentUris.parseId(uri), where);
count = db.delete(MainTable.TABLE_NAME, finalWhere, whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
String finalWhere;
switch (mUriMatcher.match(uri)) {
case MAIN:
// If URI is main table, update uses incoming where clause and args.
count = db.update(MainTable.TABLE_NAME, values, where, whereArgs);
break;
case MAIN_ID:
// If URI is for a particular row ID, update is based on incoming
// data but modified to restrict to the given ID.
finalWhere = DatabaseUtils.concatenateWhere(
MainTable._ID + " = " + ContentUris.parseId(uri), where);
count = db.update(MainTable.TABLE_NAME, values, finalWhere, whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getFragmentManager();
if (fm.findFragmentById(android.R.id.content) == null) {
ThrottledLoaderListFragment list = new ThrottledLoaderListFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class ThrottledLoaderListFragment extends ListFragment
implements LoaderManager.LoaderCallbacks<Cursor> {
static final int POPULATE_ID = Menu.FIRST;
static final int CLEAR_ID = Menu.FIRST+1;
SimpleCursorAdapter mAdapter;
String mCurFilter;
AsyncTask<Void, Void, Void> mPopulatingTask;
@Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setEmptyText("No data. Select 'Populate' to fill with data from Z to A at a rate of 4 per second.");
setHasOptionsMenu(true);
// Create an empty adapter we will use to display the loaded data.
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_1, null,
new String[] { MainTable.COLUMN_NAME_DATA },
new int[] { android.R.id.text1 }, 0);
setListAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(Menu.NONE, POPULATE_ID, 0, "Populate")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add(Menu.NONE, CLEAR_ID, 0, "Clear")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
@Override public boolean onOptionsItemSelected(MenuItem item) {
final ContentResolver cr = getActivity().getContentResolver();
switch (item.getItemId()) {
case POPULATE_ID:
if (mPopulatingTask != null) {
mPopulatingTask.cancel(false);
}
mPopulatingTask = new AsyncTask<Void, Void, Void>() {
@Override protected Void doInBackground(Void... params) {
for (char c='Z'; c>='A'; c--) {
if (isCancelled()) {
break;
}
StringBuilder builder = new StringBuilder("Data ");
builder.append(c);
ContentValues values = new ContentValues();
values.put(MainTable.COLUMN_NAME_DATA, builder.toString());
cr.insert(MainTable.CONTENT_URI, values);
// Wait a bit between each insert.
try {
Thread.sleep(250);
} catch (InterruptedException e) {
}
}
return null;
}
};
mPopulatingTask.executeOnExecutor(
AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
return true;
case CLEAR_ID:
if (mPopulatingTask != null) {
mPopulatingTask.cancel(false);
mPopulatingTask = null;
}
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
@Override protected Void doInBackground(Void... params) {
cr.delete(MainTable.CONTENT_URI, null, null);
return null;
}
};
task.execute((Void[])null);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override public void onListItemClick(ListView l, View v, int position, long id) {
// Insert desired behavior here.
Log.i(TAG, "Item clicked: " + id);
}
// These are the rows that we will retrieve.
static final String[] PROJECTION = new String[] {
MainTable._ID,
MainTable.COLUMN_NAME_DATA,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cl = new CursorLoader(getActivity(), MainTable.CONTENT_URI,
PROJECTION, null, null, null);
cl.setUpdateThrottle(2000); // update at most every 2 seconds.
return cl;
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
}
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
}
一、LoaderManager
LoaderManager类位于android.app.LoaderManager,提供了以下几个方法
abstract void destroyLoader(int id) //停止并移除loader通过ID
abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) //打印LoaderManager的状态到一个流中
static void enableDebugLogging(boolean enabled) //启用debug记录
abstract <D> Loader<D> getLoader(int id) //返回找到的ID或没有匹配的在Loader中
abstract <D> Loader<D> initLoader(int id, Bundle args, LoaderCallbacks<D> callback) //初始化Loader使其成为活动状态
abstract <D> Loader<D> restartLoader(int id, Bundle args, LoaderCallbacks<D> callback) //启动一个新的或重启一个存在的Loader在管理器中
同时LoaderManager还有一个回调接口android.app.LoaderManager.LoaderCallbacks<D> 用于和LoaderManager交互
abstract Loader<D> onCreateLoader(int id, Bundle args) //举例并返回一个新Loader通过ID
abstract void onLoadFinished(Loader<D> loader, D data) //当前面一个Loader已经完成时回调
abstract void onLoaderReset(Loader<D> loader) //当一个新的loader或存在的loader重启时回调
二、Loader
Loader类位于android.content.Loader<D>,整体比较复杂,主要成员有
1. 构造方法 Loader(Context context) //作为唯一实例化方法参数只有一个Context
2. Public Methods
void abandon() //高速Loader他在绑定
String dataToString(D data) //用于调试,转换一个Loader数据类的实例为字符串用于打印
void deliverResult(D data) //发送一个load注册的listener结果
void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) //打印loader状态通过给定的流
void forceLoad() //强制一个异步载入
Context getContext() //返回Context实例
int getId()
boolean isAbandoned() //判断是否已经绑定
boolean isReset() //判断是否已经重启
boolean isStarted() //判断是否已经执行
void onContentChanged() //内容变化回调
registerListener(int id, OnLoadCompleteListener<D> listener)
void reset() //重置一个Loader的状态
final void startLoading() //启动一个异步的载入从Loader的数据
void stopLoading() //停止载入
boolean takeContentChanged() String toString()
void unregisterListener(OnLoadCompleteListener<D> listener)
提供的子类 android.content.Loader.ForceLoadContentObserver 和 接口 android.content.Loader.OnLoadCompleteListener<D>
为了更清晰的表达Android开发网给出一个SDK例子完整代码,来作分析
public class LoaderThrottle extends Activity {
static final String TAG = "LoaderThrottle";
public static final String AUTHORITY = "com.example.android.apis.app.LoaderThrottle";
public static final class MainTable implements BaseColumns {
// This class cannot be instantiated
private MainTable() {}
public static final String TABLE_NAME = "main";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/main");
public static final Uri CONTENT_ID_URI_BASE
= Uri.parse("content://" + AUTHORITY + "/main/");
public static final String CONTENT_TYPE
= "vnd.android.cursor.dir/vnd.example.api-demos-throttle";
public static final String CONTENT_ITEM_TYPE
= "vnd.android.cursor.item/vnd.example.api-demos-throttle";
public static final String DEFAULT_SORT_ORDER = "data COLLATE LOCALIZED ASC";
public static final String COLUMN_NAME_DATA = "data";
}
static class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "loader_throttle.db";
private static final int DATABASE_VERSION = 2;
DatabaseHelper(Context context) {
// calls the super constructor, requesting the default cursor factory.
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + MainTable.TABLE_NAME + " ("
+ MainTable._ID + " INTEGER PRIMARY KEY,"
+ MainTable.COLUMN_NAME_DATA + " TEXT"
+ ");");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Logs that the database is being upgraded
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
// Kills the table and existing data
db.execSQL("DROP TABLE IF EXISTS notes");
// Recreates the database with a new version
onCreate(db);
}
}
public static class SimpleProvider extends ContentProvider {
// A projection map used to select columns from the database
private final HashMap<String, String> mNotesProjectionMap;
// Uri matcher to decode incoming URIs.
private final UriMatcher mUriMatcher;
// The incoming URI matches the main table URI pattern
private static final int MAIN = 1;
// The incoming URI matches the main table row ID URI pattern
private static final int MAIN_ID = 2;
// Handle to a new DatabaseHelper.
private DatabaseHelper mOpenHelper;
public SimpleProvider() {
// Create and initialize URI matcher.
mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mUriMatcher.addURI(AUTHORITY, MainTable.TABLE_NAME, MAIN);
mUriMatcher.addURI(AUTHORITY, MainTable.TABLE_NAME + "/#", MAIN_ID);
// Create and initialize projection map for all columns. This is
// simply an identity mapping.
mNotesProjectionMap = new HashMap<String, String>();
mNotesProjectionMap.put(MainTable._ID, MainTable._ID);
mNotesProjectionMap.put(MainTable.COLUMN_NAME_DATA, MainTable.COLUMN_NAME_DATA);
}
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
// Assumes that any failures will be reported by a thrown exception.
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Constructs a new query builder and sets its table name
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(MainTable.TABLE_NAME);
switch (mUriMatcher.match(uri)) {
case MAIN:
// If the incoming URI is for main table.
qb.setProjectionMap(mNotesProjectionMap);
break;
case MAIN_ID:
// The incoming URI is for a single row.
qb.setProjectionMap(mNotesProjectionMap);
qb.appendWhere(MainTable._ID + "=?");
selectionArgs = DatabaseUtils.appendSelectionArgs(selectionArgs,
new String[] { uri.getLastPathSegment() });
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (TextUtils.isEmpty(sortOrder)) {
sortOrder = MainTable.DEFAULT_SORT_ORDER;
}
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor c = qb.query(db, projection, selection, selectionArgs,
null /* no group */, null /* no filter */, sortOrder);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
@Override
public String getType(Uri uri) {
switch (mUriMatcher.match(uri)) {
case MAIN:
return MainTable.CONTENT_TYPE;
case MAIN_ID:
return MainTable.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
if (mUriMatcher.match(uri) != MAIN) {
// Can only insert into to main URI.
throw new IllegalArgumentException("Unknown URI " + uri);
}
ContentValues values;
if (initialValues != null) {
values = new ContentValues(initialValues);
} else {
values = new ContentValues();
}
if (values.containsKey(MainTable.COLUMN_NAME_DATA) == false) {
values.put(MainTable.COLUMN_NAME_DATA, "");
}
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(MainTable.TABLE_NAME, null, values);
// If the insert succeeded, the row ID exists.
if (rowId > 0) {
Uri noteUri = ContentUris.withAppendedId(MainTable.CONTENT_ID_URI_BASE, rowId);
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
String finalWhere;
int count;
switch (mUriMatcher.match(uri)) {
case MAIN:
count = db.delete(MainTable.TABLE_NAME, where, whereArgs);
break;
case MAIN_ID:
finalWhere = DatabaseUtils.concatenateWhere(
MainTable._ID + " = " + ContentUris.parseId(uri), where);
count = db.delete(MainTable.TABLE_NAME, finalWhere, whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
String finalWhere;
switch (mUriMatcher.match(uri)) {
case MAIN:
// If URI is main table, update uses incoming where clause and args.
count = db.update(MainTable.TABLE_NAME, values, where, whereArgs);
break;
case MAIN_ID:
// If URI is for a particular row ID, update is based on incoming
// data but modified to restrict to the given ID.
finalWhere = DatabaseUtils.concatenateWhere(
MainTable._ID + " = " + ContentUris.parseId(uri), where);
count = db.update(MainTable.TABLE_NAME, values, finalWhere, whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getFragmentManager();
if (fm.findFragmentById(android.R.id.content) == null) {
ThrottledLoaderListFragment list = new ThrottledLoaderListFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class ThrottledLoaderListFragment extends ListFragment
implements LoaderManager.LoaderCallbacks<Cursor> {
static final int POPULATE_ID = Menu.FIRST;
static final int CLEAR_ID = Menu.FIRST+1;
SimpleCursorAdapter mAdapter;
String mCurFilter;
AsyncTask<Void, Void, Void> mPopulatingTask;
@Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setEmptyText("No data. Select 'Populate' to fill with data from Z to A at a rate of 4 per second.");
setHasOptionsMenu(true);
// Create an empty adapter we will use to display the loaded data.
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_1, null,
new String[] { MainTable.COLUMN_NAME_DATA },
new int[] { android.R.id.text1 }, 0);
setListAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(Menu.NONE, POPULATE_ID, 0, "Populate")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add(Menu.NONE, CLEAR_ID, 0, "Clear")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
@Override public boolean onOptionsItemSelected(MenuItem item) {
final ContentResolver cr = getActivity().getContentResolver();
switch (item.getItemId()) {
case POPULATE_ID:
if (mPopulatingTask != null) {
mPopulatingTask.cancel(false);
}
mPopulatingTask = new AsyncTask<Void, Void, Void>() {
@Override protected Void doInBackground(Void... params) {
for (char c='Z'; c>='A'; c--) {
if (isCancelled()) {
break;
}
StringBuilder builder = new StringBuilder("Data ");
builder.append(c);
ContentValues values = new ContentValues();
values.put(MainTable.COLUMN_NAME_DATA, builder.toString());
cr.insert(MainTable.CONTENT_URI, values);
// Wait a bit between each insert.
try {
Thread.sleep(250);
} catch (InterruptedException e) {
}
}
return null;
}
};
mPopulatingTask.executeOnExecutor(
AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
return true;
case CLEAR_ID:
if (mPopulatingTask != null) {
mPopulatingTask.cancel(false);
mPopulatingTask = null;
}
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
@Override protected Void doInBackground(Void... params) {
cr.delete(MainTable.CONTENT_URI, null, null);
return null;
}
};
task.execute((Void[])null);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override public void onListItemClick(ListView l, View v, int position, long id) {
// Insert desired behavior here.
Log.i(TAG, "Item clicked: " + id);
}
// These are the rows that we will retrieve.
static final String[] PROJECTION = new String[] {
MainTable._ID,
MainTable.COLUMN_NAME_DATA,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cl = new CursorLoader(getActivity(), MainTable.CONTENT_URI,
PROJECTION, null, null, null);
cl.setUpdateThrottle(2000); // update at most every 2 seconds.
return cl;
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
}
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
}
发表评论
-
Android使用binder访问service的方式
2013-08-23 09:42 16291. 我们先来看一个与本地service通信的例子。 pub ... -
android-Service和Thread的区别
2013-08-23 09:17 913servie是系统的组件,它由系统进程托管(servicema ... -
git介绍
2013-08-01 14:49 1029git介绍 使用Git的第一件事就是设置你的名字和email ... -
cocos2d-x学习之自动内存管理和常见宏
2013-07-29 15:41 9071.自动内存管理 1)概述 C++语言默认是 ... -
cocos2dx中利用xcode 调用java中的函数
2013-07-29 11:36 25231. 先把cocos2dx根目录中的 /Users/zhaos ... -
cocos2dx(v2.x)与(v1.x)的一些常用函数区别讲解
2013-07-29 10:35 1108第一个改动: CCLayer初始化 自定义Layer,类名 ... -
xcode与eclipse整合cocos2dx
2013-07-29 10:32 1219文档xcode版本是 204 1. 在xcode中创建coc ... -
git提交代码
2013-07-23 16:00 10481. 在本地创建一个Git的工作空间,在里面创建一个工程(如H ... -
Android.mk的用法和基础
2013-07-19 14:11 4329一个Android.mk file用来向编译系统描述你的源代码 ... -
eclipse配置NDK-Builder命令
2013-07-18 11:02 10341. 2. -
eclipse配置javah命令
2013-07-18 10:48 19931.找到javah命令所在的目录 我的为 /usr/bi ... -
Android SDL2.0 编译
2013-07-17 13:40 19651,下载: wget http://www.libsdl.o ... -
IntelliJ Idea 常用快捷键列表
2013-05-27 10:19 0Alt+回车 导入包,自动修 ... -
android应用后台安装
2013-05-21 12:02 1012android应用后台安装,静默安装的代码实现方法 http ... -
编译linux内核映像
2013-05-21 11:33 960a)准备交叉编译工具链 android代码树中有一个pr ... -
如何单独编译Android源代码中的模块
2013-05-21 11:29 992一. 首先在Android源代码 ... -
Ubuntu安装JDK6和JDK5
2013-05-19 19:04 1006sudo apt-get install sun-java6- ... -
java_jni详解_01
2013-05-08 17:15 956java中的jni 例子HelloWorld 准备过程: 1 ... -
下载android源码 中断解决原因
2013-05-07 15:51 1313解决方法 1. 浏览器登录https://android.go ... -
mac下编译ffmpeg1.1.4
2013-05-07 14:55 1362经过一番网上搜索 与 无数次的编译 终于成功了 下面献上编译 ...
相关推荐
Android Support Library V4,简称`android-support-v4`,是Android开发者广泛使用的库,旨在提供对Android早期版本的兼容性,同时包含许多先进的特性,使得应用能够运行在从Android 2.1 (API级别7)到最新的Android...
`android-support-v4`库包含了大量实用类和接口,这些组件可以扩展Android API,增加了对新特性的支持,同时避免了因目标API级别较低而无法使用的限制。例如,它提供了对Fragment、Loader、ViewPager等高级UI组件的...
v7-appcompat库,全称为android-support-v7-appcompat,是Android Support Library的一个子集,主要用于提供对Android早期版本(API等级低于11)的支持,引入了许多新特性,特别是对ActionBar的支持。ActionBar是...
在旧版本的Android系统中,ActionBar是API级别11(Android 3.0)引入的,但`AppCompatActivity`使得开发者可以在更低版本的系统上使用它,增强了应用的导航体验。 4. **ViewModel**和**LiveData**: 虽然`ViewModel`...
`android-support-v7-appcompat`是一个至关重要的库,它是Android Support Library的一部分,为开发者提供了对Android API版本的向下兼容,使得开发者可以在低版本的Android系统上使用一些高版本引入的新特性。...
Android support-v4库是Android开发中不可或缺的一部分,它为Android 2.1(API级别7)及以上的设备提供了大量API支持,使得开发者能够利用新特性,同时保持对旧版本Android系统的兼容性。本文将深入探讨这个库的核心...
1. **API兼容性**:`android-support-v4`库的主要目标是提供对Android 2.1(API级别7)及以上的版本支持,使得开发者可以使用新API级别的特性,而不用担心应用程序在旧设备上运行不正常。 2. **功能扩展**:包含了...
它增加了对冰激凌三明治(Ice Cream Sandwich)系统的支持,提供了许多新特性,如ViewPager、LoaderManager和ActionBar的增强功能。ViewPager允许用户左右滑动来切换页面,LoaderManager则帮助管理数据加载,避免...
API级别14(Ice Cream Sandwich,ICS)到17(Jelly Bean)是Android发展中的重要阶段,引入了许多新特性和改进。以下是一些关键更新: 1. **Action Bar**:在API 14中,引入了Action Bar,作为应用程序的导航和操作...
这个库的目标是帮助开发者编写兼容低版本Android系统(甚至低于Android 3.0 Honeycomb)的应用,同时也引入了一些新特性。 1. **Fragment支持**:在API 11以下的版本,原生的Fragment类不可用,`support-v4`库提供...
9. **迁移至AndroidX**:虽然这些是旧版的Support Library,但现在新的项目推荐使用AndroidX库,它提供了更好的性能和更多的组件。不过,理解这些老版本的库对于维护旧项目或理解Android的历史发展仍然是有价值的。 ...
这个库包含了众多对早期API版本的扩展功能,使得开发者能够在低版本的Android设备上享受到新版本的特性。本篇文章将深入探讨Android V4库的关键组件和源码分析,旨在帮助开发者更好地理解和利用这一强大的工具。 1....
10. **Fragment**: Fragment是Android 3.0引入的新特性,它可以看作是Activity的一部分,有自己的生命周期和UI。Fragment可以在Activity之间切换,适合在平板电脑等大屏设备上创建灵活的布局。 11. **权限管理**: ...
LoaderManager.LoaderCallbacks是3.0之后出现的新特性,通过LoaderManager.LoaderCallbacks接口可以很轻松的实现异步加载数据到Fragment或Activity 中,Loaders提供了回调机制onLoadFinished()通知最终的运行结果,...
3. **Loader框架**:Android 3.0引入了LoaderManager和Loader接口,提供了一种更系统化的方式来处理数据加载。Loader可以在后台线程中加载数据,并在数据变化时自动通知UI更新,适用于需要实时更新的数据加载场景。 ...
Loader的概念起源于Android 3.0(API级别11),主要设计目的是解决AsyncTask在处理数据加载时的一些局限性,如生命周期管理、内存泄漏等问题。Loader提供了一个生命周期感知的能力,可以在Activity或Fragment的生命...