0

時間がかかるものを計算しています。そのために、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()内で立ち往生しているように見えることです。推測は無限ループを実行しますか?

他にアイデアはありますか?

ありがとう!

4

1 に答える 1

0

多くの調査の結果、問題が何であるかがわかりました。doInBackground()内で使用しているコードが多すぎて、ほとんどのコードを取り出してアクティビティに戻した後、ListViewの動作がおかしくなりました。結果。結果のある行が1つ(23行中)だけ表示される場合もあれば、結果のある別の行が表示される場合もあります。アプリを実行すると、ほとんどの場合、結果がまったく表示されないか、1行しか表示されません。デバッガーを使用したとき-すべての結果がうまくいきました!どうして???-ええと-2番目のスレッドが結果でdbを更新する前に、メインスレッドでListViewを更新するという間違いをしていました。したがって、メインスレッドはdbから空の結果を取得しました。私もループを取り除きました。

私の非同期クラスは次のようになります。

private class AsyncAllPlayAll extends AsyncTask<String, Void, Long> 
{
    Tournament mTournament = null;

    public AsyncAllPlayAll(Tournament tournament)
    {
        this.mTournament = tournament;
    }

    @Override
    protected Long doInBackground(String... string) 
    {
        Long ml = null;
        //run tournament!
        mTournament.allPlayAll();

        return ml = (long) 0;
    }

    @Override
    protected void onPostExecute(Long result) 
    {
        TournamentEdit.this.runOnUiThread(new Runnable() {

            public void run() {
                // TODO Auto-generated method stub
                populateCompetitorsListView();
            }
        });
    }
} 

runOnUiThread()を使用して、メインスレッドでpopulateメソッドを呼び出しています。トーストメッセージを更新する必要がありますが、これは明日行います:-)

この超ロングサガを読んでいただきありがとうございます...

于 2012-06-15T10:36:29.947 に答える