Android AsyncTaskLoader需要注意的问题

在使用AsyncTaskLoader的时候,遇到两个问题:
1.继承AsyncTaskLoader并实现了必要的方法后,发现loadInBackground()没有被执行
  在网上查找之后,得到如下解决方法:

继承AsyncTaskLoader后,需要重载以下方法供系统调用:

@Override
protected void onStartLoading() {
	// TODO Auto-generated method stub
	super.onStartLoading();
	forceLoad();
}

2.使用问题1的解决方案后,Loader开始工作了,但是又遇到了新的问题,我在Activity里面写了一个ListView,ListView的数据通过AsyncTaskLoader
  来进行加载,当从当前Activity跳到另一个Activity并按back键返回时,此时没有问题,但是当点击ListView中的某一项时,报出以下的错误:
  E/AndroidRuntime(1141): java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(16908298, class android.widget.ListView) with Adapter(class com.study.ActivityAdapter)]
以下是我自定义AsyncTaskLoader的代码:

public class ActivityListLoader extends AsyncTaskLoader<Integer>{
	
	private Context context;
	private Bundle args;
	private String path;
	
	private List<Map<String, Object>> data;

	public ActivityListLoader(Context context,Bundle args) {
		super(context);
		this.context = context;
		this.args = args;
		path = args.getString("path");
		data = new ArrayList<Map<String,Object>>();
	}

	@Override
	public Integer loadInBackground() {
		
		PackageManager pm = context.getPackageManager();
		Intent matchIntent = new Intent();
		matchIntent.setAction(Constants.ACTION_MAIN);
		matchIntent.addCategory(Constants.CATEGORY_STUDY);
		matchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		
		List<ResolveInfo> list = pm.queryIntentActivities(matchIntent,0);
		String label = null;
		for(ResolveInfo info:list)
		{
			label = info.loadLabel(pm).toString();
			if(label.startsWith(path))
			{
				String[] paths = path.split("/");
				String[] files = label.split("/");
				Map<String, Object> map = new HashMap<String, Object>();
				Intent intent = new Intent();
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				
				int pathlen = paths.length;
				
				if(path.equals(""))
				{
					pathlen = 0;
				}
				
				if(files.length - pathlen == 1)
				{
					map.put("isFile", true);
					intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name));
					map.put("intent", intent);
				}else
				{
					map.put("isFile", false);
					intent.setClass(context, MainActivity.class);
					intent.putExtra("path", path+files[pathlen]+"/");
					map.put("intent", intent);
				}
				data.add(map);
			}
		}
		
		return 0;
	}

	@Override
	protected void onStartLoading() {
		// TODO Auto-generated method stub
		super.onStartLoading();
		forceLoad();
	}
	
	public List<Map<String, Object>> getData()
	{
		return data;
	}
	
}

MainActivity的代码:
public class MainActivity extends ListActivity implements
		LoaderCallbacks<Integer> {

	private ListActivity context;
	private List<Map<String,Object>> datalist;

	enum Type {
		ShowProgress, DismissProgress,UpdateAdapter
	};
	
	private ProgressDialog progress;

	private Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			Type type = (Type) msg.obj;
			switch (type) {
			case ShowProgress:
				progress.show();
				break;
			case DismissProgress:
				if(progress.isShowing())
					progress.dismiss();
				break;
			case UpdateAdapter:
				ActivityAdapter adapter = new ActivityAdapter(context, datalist);
				setListAdapter(adapter);
				adapter.notifyDataSetChanged();
				break;
			default:
				break;
			}
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		context = this;
		initProgressDialog();
		
		Intent intent = getIntent();
		String path = intent.getStringExtra("path");
		if (path == null)
			path = "";
		Bundle args = new Bundle();
		args.putString("path", path);
		getLoaderManager().initLoader(0, args, this);
		Message msg = Message.obtain(handler, 0, Type.ShowProgress);
		msg.sendToTarget();
		
		setListAdapter(new ActivityAdapter(this, new ArrayList<Map<String,Object>>()));
		
		getListView().setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				@SuppressWarnings("unchecked")
				Map<String, Object> map = (Map<String, Object>) getListAdapter().getItem(position);
				Intent intent = (Intent)map.get("intent");	
				startActivity(intent);
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	private void initProgressDialog()
	{
		progress = new ProgressDialog(this);
		progress.setMessage("加载所有的Activity信息");
		progress.setCanceledOnTouchOutside(false);
	}

	@Override
	public Loader<Integer> onCreateLoader(int id, Bundle args) {
		return new ActivityListLoader(context, args);
	}

	@Override
	public void onLoadFinished(Loader<Integer> loader, Integer data) {
		ActivityListLoader aloader = (ActivityListLoader) loader;
		datalist = aloader.getData();
		LogUtils.e("debug");
		
		Message msg = Message.obtain(handler, 0, Type.DismissProgress);
		msg.sendToTarget();
		
		Message msgUpdate = Message.obtain(handler, 0, Type.UpdateAdapter);
		msgUpdate.sendToTarget();
	}

	@Override
	public void onLoaderReset(Loader<Integer> loader) {
		LogUtils.e("debug");
		Message msgUpdate = Message.obtain(handler, 0, Type.UpdateAdapter);
		msgUpdate.sendToTarget();
	}

}

更新ListView数据的操作都是发生在UI线程,所以应该是系统在我们不知道的地方更新了数据而没有通知ListView.
查看Activity.java的源码可以看到:

protected void onStart() {
	if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
	mCalled = true;
	if (!mLoadersStarted) {
		mLoadersStarted = true;
		if (mLoaderManager != null) {
			mLoaderManager.doStart(); //系统会执行Loader的onStartLoading函数
		} else if (!mCheckedForLoaderManager) {
			mLoaderManager = getLoaderManager(null, mLoadersStarted, false);
		}
		mCheckedForLoaderManager = true;
	}
	getApplication().dispatchActivityStarted(this);
}

Activity恢复的时候,会重新调用onStart函数,从而最终调用到我们Loader里的onStartLoading函数,
而我们的onStartLoading函数是这样:

@Override
protected void onStartLoading() {
	// TODO Auto-generated method stub
	super.onStartLoading();
	forceLoad();
}

也就是说,不管如何,都会在后台将数据重新加载一遍,因为是系统调用的,所以没有通知ListView,造成数据的不同步.
到这里,解决方案就呼之欲出了:
改造如下:

@Override
protected void onStartLoading() {
	// TODO Auto-generated method stub
	super.onStartLoading();
	if(data.size() == 0)
		forceLoad();
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值