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  

我想这可能是数据库线程的一些问题?当我将它从主线程传递给 AsyncAllPlayAll 时。

所以我尝试在内部类(不同的实例)中打开数据库线程并将其构造函数更改为:

    public AsyncAllPlayAll(Context context, StournamentDbAdapter dbHelper)
    {
        this.mContext = context;
        this.mDbHelper = dbHelper;
        mDbHelper  = new StournamentDbAdapter(context);
        mDbHelper.open();
    }

这也没有帮助:(

现在我尝试添加一个 Looper(如AsyncTask 和 Looper.prepare() error中所建议的)

    @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() 中使用了太多代码,在我取出大部分代码并将其放回我的 Activity 之后,我的 ListView 出现了奇怪的行为:有时它显示为空结果。有时它只显示一行(共 23 行)有结果,有时显示不同的行有结果。当我运行应用程序时 - 我大多没有或只有一行结果。当我使用调试器时 - 我得到了所有结果都很好!怎么来的???- 好吧 - 在第二个线程设法用结果更新数据库之前,我在主线程上更新我的 ListView 是错误的。所以主线程从数据库中抓取了空结果。我也摆脱了循环。

我的 Async 类现在看起来像这样:

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() 在我的主线程上调用填充方法。我仍然需要更新我的 Toast 消息,但我明天会这样做:-)

感谢您阅读这个超长的传奇......

于 2012-06-15T10:36:29.947 回答