時間がかかるものを計算しています。そのために、AsyncTaskをサブクラス化する内部クラスを作成しました。
private class AsyncAllPlayAll extends AsyncTask<String, Void, CharSequence>
{
StournamentDbAdapter mDbHelper;
public AsyncAllPlayAll(Context context, StournamentDbAdapter dbHelper)
{
this.mContext = context;
this.mDbHelper = dbHelper;
}
@Override
protected CharSequence doInBackground(String... tournamentRowIds)
{
Long tournamentRowId = Long.valueOf(tournamentRowIds[0]);
Tournament tournament = new Tournament(mDbHelper, tournamentRowId);
tournament.setupTournament();
Boolean tournamentHasWinner = mDbHelper.winningTournamentParticipantsExists(tournamentRowId);
// tournament already run: delete score
if(tournamentHasWinner)
{
mDbHelper.resetTournamentsStocksScore(tournamentRowId);
mDbHelper.resetTournamentWinnerStockId(tournamentRowId);
}
//run tournament!
tournament.allPlayAll();
TournamentParticipant tournamentParticipant = mDbHelper.insertWinningParticipant(tournamentRowId);
populateCompetitorsListView();
final CharSequence winner = "Winner is: " + tournamentParticipant.getStock().getName() + "(" + tournamentParticipant.getScore() + ")";
return winner;
}
@Override //the winner
protected void onPostExecute(final CharSequence result) {
super.onPostExecute(result);
final int duration = Toast.LENGTH_LONG;
TournamentEdit.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Hello", duration).show();
}
});
}
}
しかし、エラーが発生します。これは理解できません。「 Looper.prepare()を呼び出していないスレッド内にハンドラーを作成できません」
私はstackoverflowでいくつかのスレッドを読みましたが、それらに書かれたものを実装しても私の状況は変わりませんでした。
onPostExecuteで実行していたToastからエラーが発生したことは確かでしたが、これは問題ではありません。エラーはトーナメントを初期化しようとしたところから始まります。
Tournament tournament = new Tournament(mDbHelper, tournamentRowId);
これが私のスタックです:
Thread [<11> AsyncTask #1] (Suspended)
FragmentManagerImpl$1.<init>(FragmentManagerImpl) line: 423
FragmentManagerImpl.<init>() line: 423
Tournament(Activity).<init>() line: 702
Tournament.<init>(StournamentDbAdapter, Long) line: 48
TournamentEdit$AsyncAllPlayAll.doInBackground(String...) line: 346
TournamentEdit$AsyncAllPlayAll.doInBackground(Object...) line: 1
AsyncTask$2.call() line: 264
FutureTask$Sync.innerRun() line: 305
AsyncTask$3(FutureTask).run() line: 137
AsyncTask$SerialExecutor$1.run() line: 208
ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1076
ThreadPoolExecutor$Worker.run() line: 569
Thread.run() line: 856
私はそれがdbスレッドに何らかの問題がある可能性があると思いますか?メインスレッドからAsyncAllPlayAllに渡します。
そこで、内部クラス(別のインスタンス)でdbスレッドを開こうとし、そのコンストラクターを次のように変更しました。
public AsyncAllPlayAll(Context context, StournamentDbAdapter dbHelper)
{
this.mContext = context;
this.mDbHelper = dbHelper;
mDbHelper = new StournamentDbAdapter(context);
mDbHelper.open();
}
これも役に立ちませんでした:(
ここで、Looperを追加してみました(AsyncTaskおよびLooper.prepare()エラーで提案されているように)
@Override
protected CharSequence doInBackground(String... tournamentRowIds)
{
Looper.prepare();
Long tournamentRowId = Long.valueOf(tournamentRowIds[0]);
Tournament tournament = new Tournament(mDbHelper, tournamentRowId);
tournament.setupTournament();
Boolean tournamentHasWinner = mDbHelper.winningTournamentParticipantsExists(tournamentRowId);
// tournament already run: delete score
if(tournamentHasWinner)
{
mDbHelper.resetTournamentsStocksScore(tournamentRowId);
mDbHelper.resetTournamentWinnerStockId(tournamentRowId);
}
//run tournament!
tournament.allPlayAll();
TournamentParticipant tournamentParticipant = mDbHelper.insertWinningParticipant(tournamentRowId);
populateCompetitorsListView();
final CharSequence winner = "Winner is: " + tournamentParticipant.getStock().getName() + "(" + tournamentParticipant.getScore() + ")";
Looper.loop();
return winner;
}
コードはさらに進んだのですが、次のエラーが発生します。
原因:android.view.ViewRootImpl $ CalledFromWrongThreadException:ビュー階層を作成した元のスレッドのみがそのビューにアクセスできます。
これでpopulateCompetitorsListView()がクラッシュを引き起こし、その理由も明らかです。populateCompetitorsListView()の最後の行を見てください。
setListAdapter(tournamentStocks);
メインスレッドを変更しようとしています。私はそれをメインクラスに移動しましたが、それはそれを修正したようです:計算が実行されます。
@SuppressWarnings("deprecation")
private void populateCompetitorsListView()
{
// Get all of the notes from the database and create the item list
Cursor tournamentStocksCursor = mDbHelper.retrieveTrounamentStocks(mTournamentRowId);
startManagingCursor(tournamentStocksCursor);
// Create an array to specify the fields we want to display in the list (only name)
String[] from = new String[] {StournamentConstants.TblStocks.COLUMN_NAME, StournamentConstants.TblTournamentsStocks.TBL_COLUMN_TOURNAMENTS_STOCKS_STOCK_SCORE};
// and an array of the fields we want to bind those fields to (in this case just name)
int[] to = new int[]{R.id.competitor_name, R.id.competitor_score};
// Now create an array adapter and set it to display using our row
SimpleCursorAdapter tournamentStocks = new SimpleCursorAdapter(this, R.layout.competitor_row, tournamentStocksCursor, from, to);
//tournamentStocks.convertToString(tournamentStocksCursor);
setListAdapter(tournamentStocks);
}
しかし、今の問題は、 Looper.loop()の実装のために、doInBackground()内で立ち往生しているように見えることです。推測は無限ループを実行しますか?
他にアイデアはありますか?
ありがとう!