我正在将一个sqlite数据库读入tableLayout。我不想在一个单独的线程中执行此操作,而不是在没有ui更新的情况下等待很长时间。所以我使用AsyncTask来完成一些工作并发布结果。但是,我列表中只有大约1/4的项目实际上是在TableLayout上。没有AsyncTask它工作正常。列表中的大多数项都会抛出一个错误(我抓到了)java.util.concurrent.RejectedExecutionException。我不确定为什么会这样。这是我的代码。
myDB.execSQL("CREATE TABLE IF NOT EXISTS "
+ TableName
+ " (_id INTEGER PRIMARY KEY, filepath TEXT UNIQUE, title TEXT, artist TEXT, album TEXT, time TEXT, playcount NUMERIC);");
Cursor c = myDB.rawQuery("SELECT * FROM " + TableName, null);
c.moveToFirst();
if (c != null) {
int color = 0xFFdfe8ea;
this.startManagingCursor(c);
// Loop through all Results
do {
try{
MyAsyncTask aTask = new MyAsyncTask();
String[]strings= {c.getString(c.getColumnIndex("title")),c.getString(c.getColumnIndex("artist")),c.getString(c.getColumnIndex("time")),c.getString(c.getColumnIndex("album")),""+color};
aTask.execute(strings);
}catch(Exception e){
Log.w("****", e);
}
if (color == 0xFFdfe8ea) {
color = 0xFFf2f8fa;
} else {
color = 0xFFdfe8ea;
}
} while (c.moveToNext());
}
} catch (SQLException e) {
Log.e("****", e.toString());
} finally {
if (myDB != null) {
myDB.close();
}
}
这里是AsyncTask
class MyAsyncTask extends AsyncTask<String, Void, View> {
@Override
protected View doInBackground(String... params) {
int color = Integer.parseInt(params[4]);
TableRow tr = new TableRow(MainActivity.this);
tr.setLayoutParams(new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
TextView space = new TextView(MainActivity.this);
space.setText("");
space.setBackgroundColor(color); //0xFFf2f8fa alternating
space.setSingleLine();
space.setPadding(2, 2, 2, 2);
space.setGravity(Gravity.LEFT);
space.setTextColor(0xFF000000);
space.setLayoutParams(new LayoutParams(
findViewById(R.id.spaceColumn).getWidth(),
LayoutParams.WRAP_CONTENT));
/* Create a Button to be the row-content. */
TextView title = new TextView(MainActivity.this);
title.setText(params[0]);
title.setBackgroundColor(color); //0xFFf2f8fa alternating
title.setSingleLine();
title.setPadding(2, 2, 2, 2);
title.setGravity(Gravity.LEFT);
title.setTextColor(0xFF000000);
title.setEllipsize(TruncateAt.END);
title.setLayoutParams(new LayoutParams(
0,
LayoutParams.WRAP_CONTENT, 1));
/* Create a Button to be the row-content. */
TextView artist = new TextView(MainActivity.this);
artist.setText(params[1]);
artist.setBackgroundColor(color); //0xFFf2f8fa alternating
artist.setSingleLine();
artist.setPadding(2, 2, 2, 2);
artist.setGravity(Gravity.LEFT);
artist.setTextColor(0xFF000000);
artist.setEllipsize(TruncateAt.END);
artist.setLayoutParams(new LayoutParams(
0,
LayoutParams.WRAP_CONTENT, 1));
/* Create a Button to be the row-content. */
TextView time = new TextView(MainActivity.this);
time.setText(params[2]);
time.setBackgroundColor(color); //0xFFf2f8fa alternating
time.setSingleLine();
time.setPadding(2, 2, 2, 2);
time.setGravity(Gravity.LEFT);
time.setTextColor(0xFF000000);
time.setLayoutParams(new LayoutParams(
findViewById(R.id.timeColumn).getWidth(),
LayoutParams.WRAP_CONTENT));
/* Create a Button to be the row-content. */
TextView album = new TextView(MainActivity.this);
album.setText(params[3]);
album.setBackgroundColor(color); //0xFFf2f8fa alternating
album.setSingleLine();
album.setPadding(2, 2, 2, 2);
album.setGravity(Gravity.LEFT);
album.setTextColor(0xFF000000);
album.setEllipsize(TruncateAt.END);
album.setLayoutParams(new LayoutParams(
0,
LayoutParams.WRAP_CONTENT, 1));
/* Add Button to row. */
tr.addView(space);
tr.addView(title);
tr.addView(artist);
tr.addView(time);
tr.addView(album);
/* Add row to TableLayout. */
return tr;
}
@Override
protected void onPostExecute(View tr) {
((TableLayout) findViewById(R.id.tableLayout)).addView(tr, new TableLayout.LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
}
@Override
protected void onPreExecute() {
}
}
作为参考,这就是我修复它的方法。
class MyAsyncTask extends AsyncTask<Void, Song, Void> {
@Override
protected Void doInBackground(Void... params) {
SQLiteDatabase myDB = openOrCreateDatabase("DatabaseName", MODE_PRIVATE, null);
String TableName = "songs";
myDB.execSQL("CREATE TABLE IF NOT EXISTS "
+ TableName
+ " (_id INTEGER PRIMARY KEY, filepath TEXT UNIQUE, title TEXT, artist TEXT, album TEXT, time TEXT, playcount NUMERIC);");
Cursor c = myDB.rawQuery("SELECT * FROM " + TableName, null);
c.moveToFirst();
int filepathIndex=c.getColumnIndex("filepath");
int titleIndex=c.getColumnIndex("title");
int artistIndex=c.getColumnIndex("artist");
int albumIndex=c.getColumnIndex("album");
int timeIndex=c.getColumnIndex("time");
int playcountIndex=c.getColumnIndex("playcount");
if (c != null) {
int color = 0xFFdfe8ea;
// this.startManagingCursor(c);
// Loop through all Results
do {
Song song = new Song(c.getString(filepathIndex),c.getString(titleIndex),c.getString(artistIndex),c.getString(albumIndex),c.getString(timeIndex),c.getInt(playcountIndex),color);
// Add to song the data from your cursor
publishProgress(song);
if (color == 0xFFdfe8ea) {
color = 0xFFf2f8fa;
} else {
color = 0xFFdfe8ea;
}
} while (c.moveToNext());
}
return null;
}
@Override
protected void onPostExecute(Void item) {
}
@Override
protected void onPreExecute() {
}
@Override
protected void onProgressUpdate(Song... items) {
for (Song song : items) {
TableRow tr = new TableRow(MainActivity.this);
tr.setLayoutParams(new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
TextView space = new TextView(MainActivity.this);
space.setText("");
space.setBackgroundColor(song.color); //0xFFf2f8fa alternating
space.setSingleLine();
space.setPadding(2, 2, 2, 2);
space.setGravity(Gravity.LEFT);
space.setTextColor(0xFF000000);
space.setLayoutParams(new LayoutParams(
findViewById(R.id.spaceColumn).getWidth(),
LayoutParams.WRAP_CONTENT));
/* Create a Button to be the row-content. */
TextView title = new TextView(MainActivity.this);
title.setText(song.title);
title.setBackgroundColor(song.color); //0xFFf2f8fa alternating
title.setSingleLine();
title.setPadding(2, 2, 2, 2);
title.setGravity(Gravity.LEFT);
title.setTextColor(0xFF000000);
title.setEllipsize(TruncateAt.END);
title.setLayoutParams(new LayoutParams(
0,
LayoutParams.WRAP_CONTENT, 1));
/* Create a Button to be the row-content. */
TextView artist = new TextView(MainActivity.this);
artist.setText(song.artist);
artist.setBackgroundColor(song.color); //0xFFf2f8fa alternating
artist.setSingleLine();
artist.setPadding(2, 2, 2, 2);
artist.setGravity(Gravity.LEFT);
artist.setTextColor(0xFF000000);
artist.setEllipsize(TruncateAt.END);
artist.setLayoutParams(new LayoutParams(
0,
LayoutParams.WRAP_CONTENT, 1));
/* Create a Button to be the row-content. */
TextView time = new TextView(MainActivity.this);
time.setText(song.time);
time.setBackgroundColor(song.color); //0xFFf2f8fa alternating
time.setSingleLine();
time.setPadding(2, 2, 2, 2);
time.setGravity(Gravity.LEFT);
time.setTextColor(0xFF000000);
time.setLayoutParams(new LayoutParams(
findViewById(R.id.timeColumn).getWidth(),
LayoutParams.WRAP_CONTENT));
/* Create a Button to be the row-content. */
TextView album = new TextView(MainActivity.this);
album.setText(song.album);
album.setBackgroundColor(song.color); //0xFFf2f8fa alternating
album.setSingleLine();
album.setPadding(2, 2, 2, 2);
album.setGravity(Gravity.LEFT);
album.setTextColor(0xFF000000);
album.setEllipsize(TruncateAt.END);
album.setLayoutParams(new LayoutParams(
0,
LayoutParams.WRAP_CONTENT, 1));
/* Add Button to row. */
tr.addView(space);
tr.addView(title);
tr.addView(artist);
tr.addView(time);
tr.addView(album);
// Add the row to the table
((TableLayout) findViewById(R.id.tableLayout)).addView(tr, new TableLayout.LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
}
}
}
答案 0 :(得分:2)
您看到此RejectedExceutionException的原因几乎可以肯定是因为您提交的请求过多。
我刚进入AsyncTask的代码,我注意到了:
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
这将构建一个有界的LinkedBlockingQueue。绑定最多10个元素。该 MAXIMUM_POOL_SIZE我看到是128(这意味着如果需要,Executor最多会创建128个线程)。
一旦超过128个线程并提交到队列深度为10的新MyTask实例,您将获得RejectedExecutionException。当您使所有可用线程饱和并且队列中没有空间时,抛出此异常。
您可以通过在RejectedExecution发生时获取线程转储来轻松确认。
基本上,您可以在任何特定时间提交138个MyTask,但是一旦您同时提交了139个MyTask(不在应用程序的生命周期内),您将遇到此问题
编辑 我更详细地了解了代码,并且最新版本(实际上自2011年1月16日起)应该永远不会发生此错误。
如果版本较旧,则会遇到此issue。
简而言之,如果你升级版本,这个问题就会消失,但是每个任务都会连续执行而不是同时执行。
答案 1 :(得分:1)
如果您想使用AsyncTask执行此操作,请考虑使用publishProgress()
,这样每个项目都会在从数据库中获取时添加。这样:
注意:请注意Song
是一个包含name
,album
,artist
和time
属性的类。
class MyAsyncTask extends AsyncTask<Void, Song, Void> {
@Override
protected Void doInBackground(Void... params) {
myDB.execSQL("CREATE TABLE IF NOT EXISTS "
+ TableName
+ " (_id INTEGER PRIMARY KEY, filepath TEXT UNIQUE, title TEXT, artist TEXT, album TEXT, time TEXT, playcount NUMERIC);");
Cursor c = myDB.rawQuery("SELECT * FROM " + TableName, null);
c.moveToFirst();
if (c != null) {
int color = 0xFFdfe8ea;
this.startManagingCursor(c);
// Loop through all Results
do {
Song song = new Song();
// Add to song the data from your cursor
publishProgress(song);
} while (c.moveToNext());
}
return null;
}
@Override
protected void onPostExecute(Void item) {
}
@Override
protected void onPreExecute() {
}
@Override
protected void onProgressUpdate(Song... items) {
for (Song song : items) {
TableRow tr = new TableRow(MainActivity.this);
tr.setLayoutParams(new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
TextView space = new TextView(MainActivity.this);
space.setText("");
space.setBackgroundColor(color); //0xFFf2f8fa alternating
space.setSingleLine();
space.setPadding(2, 2, 2, 2);
space.setGravity(Gravity.LEFT);
space.setTextColor(0xFF000000);
space.setLayoutParams(new LayoutParams(
findViewById(R.id.spaceColumn).getWidth(),
LayoutParams.WRAP_CONTENT));
/* Create a Button to be the row-content. */
TextView title = new TextView(MainActivity.this);
title.setText(song.getTitle());
title.setBackgroundColor(color); //0xFFf2f8fa alternating
title.setSingleLine();
title.setPadding(2, 2, 2, 2);
title.setGravity(Gravity.LEFT);
title.setTextColor(0xFF000000);
title.setEllipsize(TruncateAt.END);
title.setLayoutParams(new LayoutParams(
0,
LayoutParams.WRAP_CONTENT, 1));
/* Create a Button to be the row-content. */
TextView artist = new TextView(MainActivity.this);
artist.setText(song.getArtist());
artist.setBackgroundColor(color); //0xFFf2f8fa alternating
artist.setSingleLine();
artist.setPadding(2, 2, 2, 2);
artist.setGravity(Gravity.LEFT);
artist.setTextColor(0xFF000000);
artist.setEllipsize(TruncateAt.END);
artist.setLayoutParams(new LayoutParams(
0,
LayoutParams.WRAP_CONTENT, 1));
/* Create a Button to be the row-content. */
TextView time = new TextView(MainActivity.this);
time.setText(song.getTime());
time.setBackgroundColor(color); //0xFFf2f8fa alternating
time.setSingleLine();
time.setPadding(2, 2, 2, 2);
time.setGravity(Gravity.LEFT);
time.setTextColor(0xFF000000);
time.setLayoutParams(new LayoutParams(
findViewById(R.id.timeColumn).getWidth(),
LayoutParams.WRAP_CONTENT));
/* Create a Button to be the row-content. */
TextView album = new TextView(MainActivity.this);
album.setText(song.getAlbum());
album.setBackgroundColor(color); //0xFFf2f8fa alternating
album.setSingleLine();
album.setPadding(2, 2, 2, 2);
album.setGravity(Gravity.LEFT);
album.setTextColor(0xFF000000);
album.setEllipsize(TruncateAt.END);
album.setLayoutParams(new LayoutParams(
0,
LayoutParams.WRAP_CONTENT, 1));
/* Add Button to row. */
tr.addView(space);
tr.addView(title);
tr.addView(artist);
tr.addView(time);
tr.addView(album);
// Add the row to the table
((TableLayout) findViewById(R.id.tableLayout)).addView(tr, new TableLayout.LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
}
}
}
我相信你错误地理解了AsyncTask背后的概念,我强烈建议你重读its documentation at Android Developers,因为它的概念有点难以理解,但是当你这么做时非常强大。正如Romain Guy对您的回答发表评论,您只能在onPreExecute(),onProgressUpdate()和onPostExecute()方法上执行UI代码。
答案 2 :(得分:0)
我认为你不需要为此创建一个AsyncTask。您无法从网络中获取任何内容或下载图像。它只是标准装载。
我会使用'limit'限制SQL中的结果。
另外,你是在适配器内做的吗?因为我认为您要将所有内容添加到列表中,您应该在布局中创建列表视图并设置适配器。也许扩展BaseAdapter。
每个适配器都有一个名为getView的方便方法,只有在它可见时才会被调用,并且应该有助于解决问题。
这是适配器的示例:
public class MyAdapter extends BaseAdapter {
private Context context = null;
private Cursor cursor;
public MyAdapter(Context context){
this.context = context;
SQLiteDatabase db = DatabaseHelper.getInstance(context).getReadableDatabase();
this.cursor = db.query("YOUR QUERY");
}
@Override
public int getCount() {
return this.cursor.getCount();
}
public Cursor getCursor() {
return cursor;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout row;
try {
cursor.moveToPosition(position);
if (convertView == null) {
row = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.myRowLayout, parent, false);
} else {
row = (LinearLayout) convertView;
}
TextView name = (TextView) row.findViewById(R.id.myLayoutId);
name.setText(cursor.getString(cursor.getColumnIndex("your column")));
} catch (Exception e) {
row = null;
Log.e(LOG_TAG, "" + e.getMessage());
e.printStackTrace();
}
return row;
}
@Override
public MoneyCurrency getItem(int position) {
this.cursor.moveToPosition(position);
long id = this.cursor.getLong(this.cursor.getColumnIndex("your column id"));
return new Object.read(id, context, null); //Return whatever you want to show in that row. This is used if you want to use onClick listeners or menus
}
@Override
public long getItemId(int position) {
this.cursor.moveToPosition(position);
return this.cursor.getLong(this.cursor.getColumnIndex("your id column"));
}
}