我有一个应用程序,它在互联网(客户端 - 服务器应用程序)上请求数据信息,但这种通信非常慢,因此我决定创建一个AsyncTask来管理延迟。
在doInBackground内部我调用Looper.prepare()
然后调用我的“视图生成器(可以检索数据)”。
详细(问题):
我有一个动态创建列表视图的行。但每次我尝试给行充气时,android会抛出一个Looper异常“每个线程只能创建一个Looper”
我按照以下步骤操作:
Looper.preapare()
我想我不能两次充气,但我不知道如何解决这个问题
的AsyncTask
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);
}
....
....
}
N.B。如果我放下第二个适配器PlayerRowListAdapter
......一切正常......(显然没有列表)
此致
P.S。对不起我的英文
答案 0 :(得分:4)
不是只调用Looper.prepare();
,而是首先检查你的Thread是否已经存在Looper,如果没有,则调用该函数。像这样:
if (Looper.myLooper()==null)
Looper.prepare();
答案 1 :(得分:0)
您需要调用Looper.prepare()
和Looper.loop()
的唯一原因是您希望在不是UI线程的线程中发送消息Handler
。基本上,它使线程永远保持活动,以便在线程内创建的Handler
仍然可以发送和接收消息。回调方法也是如此,例如LocationListener
或类似的东西。您有责任通过在线程内部调用Looper.getMyLooper().quit()
来完成线程的杀死。
如果您在UI线程中夸大视图,则无需致电Looper.prepare()
或Looper.loop()
,因为这已在后台完成。你永远不应该在UI线程之外膨胀Views
。
答案 2 :(得分:0)
AsyncTask已经有了自己的Looper
。如果您想从doInBackground()
方法更新用户界面,请使用publishProgress(..)
,然后在主线程中调用onProgressUpdate(..)
。在onProgressUpdate
中,您可以对视图进行充气并将其添加到用户界面中。
编辑:示例代码:http://developer.android.com/reference/android/os/AsyncTask.html
答案 3 :(得分:0)
以下是我如何解决这个问题。
正如Developer Reference for AsyncTask所说,
doInBackground
创建一个新线程来管理它(这迫使我调用Looper.prepare()
),而onPostExecute()
使用主线程。
所以我将processAct()
分为两个方法:prepareData()
检索数据,createView()
调用适配器。
我已将第一种方法放入doInBackground()
,将第二种方法(createView()
)放入onPostExecute()
。