1

我有一个在 Internet 上请求数据信息的应用程序(客户端-服务器应用程序),但是这种通信非常慢,因此我决定创建一个 AsyncTask 来管理延迟。在 doInBackground 内部,我称之为Looper.prepare()“视图生成器(检索数据)”。

详细(问题):

我有一个动态创建列表视图行的活动。但每次我尝试增加行时,android 都会抛出 Looper 异常“每个线程只能创建一个 Looper”

我按照以下步骤操作:

  • 称呼Looper.preapare()
  • 使用第一次膨胀来创建我的列表的容器
  • 使用第二次膨胀来创建列表行

我想我不能充气两次,但我不知道如何解决这个问题

异步任务

private class DrawerView extends AsyncTask<ActivityGroup, String, View>{
    Exception exc=null;     

    @Override protected void onPreExecute() {
    super.onPreExecute();   
}

@Override protected View doInBackground(ActivityGroup... params) {
    try {
        Looper.prepare();
    return processAct();
    }catch (ConnectionException e) {    
        exc =e;
    return null;                
    }
    catch (Exception e) {
        exc = e;
    return null;
    }
}

@Override protected void onPostExecute(View result) {
    super.onPostExecute(result);
    if(exc!= null){
        Utils.usrMessage(getApplicationContext(), "Oh Noo!:\n"+exc.getMessage());
        Utils.logErr(getApplicationContext(), exc);
    finish();
    }
    if(result!= null){
        setContentView(result);
    }
}
}

processAct()是这样实现的抽象方法

@Override protected View processAct() throws Exception {

    Bundle bundle = getIntent().getExtras();
    User user = (User)bundle.getSerializable("user");

    Team team =  Team.getTeamInformation(this,user.getTeamId());
    ArrayList<Player> players =Player.getPlayerList(this,user.getTeamId());

    PlayersListAdapter view = new PlayersListAdapter(this,players,team);
    return view;
}

PlayerListAdapter是构建/设置第一个视图(列表容器)的类..这里是第一个通货膨胀

public PlayersListAdapter(Context context, ArrayList<Player> players,Team team) throws Exception{
    super(context);
    View view = inflate(getContext(), R.layout.team_players, this);

    TextView tv_teamName = (TextView)view.findViewById(R.id.tbplrs_tmnm);
    TextView tv_playersNum = (TextView)view.findViewById(R.id.tbplrs_nplrs);

    tv_teamName.setText(team.getName());

    String msg = players.size()+" ";
    msg += (players.size()!=1)?context.getString(R.string.playerPlural):context.getString(R.string.playerSingle);
    tv_playersNum.setText(msg);

    ListView lView = (ListView)view.findViewById(R.id.tbplrs_plrslst);
    PlayersRowListAdapter plAdapter = new PlayersRowListAdapter(context, players);
    lView.setAdapter(plAdapter);
} 

最后PlayerRowListAdapter扩展了 BaseAdapter,...这里是第二次通货膨胀

@Override public View getView(int position, View view, ViewGroup parent) {
    if (view == null){
        LayoutInflater lInflator = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = lInflator.inflate(R.layout.team_player_singlplayer,null);
    }
    ....
    ....
}

注意如果我放弃第二个适配器PlayerRowListAdapter......一切正常......(显然没有列表)

问候

ps对不起我的英语

4

4 回答 4

4

Looper.prepare();首先检查您的线程是否不存在 Looper,而不是仅仅调用,如果不存在,则调用该函数。像这样:

if (Looper.myLooper()==null)
    Looper.prepare();
于 2016-02-07T03:37:17.877 回答
0

您需要调用的唯一原因Looper.prepare()Looper.loop()当您希望Handler在不是 UI 线程的线程中接收消息时。基本上,它使线程永远保持活动状态,以便Handler在线程内创建的线程仍然可以发送和接收消息。LocationListener类似或类似的回调方法也是如此。您有责任通过在Looper.getMyLooper().quit()线程所在的线程内部调用来杀死线程。

如果你在 UI 线程中膨胀视图,那么你不需要调用Looper.prepare()或者Looper.loop()因为这已经在后台完成了。你不应该Views在 UI 线程之外膨胀。

于 2012-07-13T12:37:32.697 回答
0

AsyncTask 已经有自己的Looper. 如果您想从您的doInBackground()方法使用更新您的 UI publishProgress(..),然后onProgressUpdate(..)在主线程中调用。在你的onProgressUpdate你可以膨胀你的视图并将它们添加到你的 UI 中。

编辑:示例代码:http: //developer.android.com/reference/android/os/AsyncTask.html

于 2012-07-13T12:38:18.813 回答
0

这是我解决这个问题的方法。

正如AsyncTask 的开发人员参考所说, doInBackground创建一个新线程来管理它(这迫使我调用Looper.prepare()),同时onPostExecute()使用主线程。

所以我processAct()分成了两种方法:prepareData()检索数据和createView()调用适配器。

我已经把第一个方法放进去doInBackground(),第二个(createView())我放进去onPostExecute()

于 2012-07-13T15:09:45.710 回答