我已经在IRC聊天客户端工作了一个星期。现在我已经完成了应用程序,我坚持一件事:它在特定活动上表现得非常慢。 我不知道原因,也许是因为我编码很差。我没有在UI线程上做任何网络工作。我正在使用一个服务,而服务又使用一个线程来完成工作。如果你能看一下我的代码并指出我做错的地方,那就太好了。当我在edittext上输入时,特定的 RoomActivity 执行缓慢,有时会卡住。这是我的RoomActivity代码:
public class RoomActivity extends ActionBarActivity{
Context mContext=this;
ListView chatStream;
PMListAdapter pmAdapter;
StreamAdapter adapter;
ArrayList<String> streamMsgs=new ArrayList<String>();
ArrayList<String> pmConversations;
String curChannel="Connecting";
String curNick="ME";
ChatService service;
SlidingMenu menu;
UserListAdapter userList;
boolean isRegistered=false;
ProgressDialog dialog;
private SoundPool soundPool;
private int pm_soundID;
boolean loaded = false;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chatroom);
chatStream=(ListView) findViewById(R.id.stream);
dialog=ProgressDialog.show(mContext, "","Connecting..");
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
// Load the sound
soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId,
int status) {
loaded = true;
}
});
pm_soundID = soundPool.load(this, R.raw.new_msg, 1);
}
private void playPMSound(){
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
float actualVolume = (float) audioManager
.getStreamVolume(AudioManager.STREAM_MUSIC);
float maxVolume = (float) audioManager
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
float volume = actualVolume / maxVolume;
// Is the sound loaded already?
if (loaded) {
soundPool.play(pm_soundID, volume, volume, 1, 0, 1f);
}
}
private void setEverything(){
getSupportActionBar().setTitle(curChannel);
adapter=new StreamAdapter(streamMsgs,mContext);
chatStream.setAdapter(adapter);
RoomDatabase room_db=new RoomDatabase(mContext);
room_db.open();
List<String> lostMsgs=room_db.getAllMessages();
room_db.close();
if(lostMsgs!=null){
//show all those lost msgs
for(String text:lostMsgs){
streamMsgs.add(text);
adapter.notifyDataSetChanged();
}
}
registerReceiver(msgreceiver,new IntentFilter(ChatService.BROADCAST_CHANMSG));
registerReceiver(userjoinreceiver,new IntentFilter(ChatService.BROADCAST_USERJOIN));
registerReceiver(userListArrive,new IntentFilter(ChatService.BROADCAST_USERLISTARRIVE));
registerReceiver(userleavereceiver,new IntentFilter(ChatService.BROADCAST_USERLEAVE));
registerReceiver(pmreceiver,new IntentFilter(ChatService.BROADCAST_PMMSG));
registerReceiver(alertreceiver,new IntentFilter(ChatService.BROADCAST_ALERT));
registerReceiver(kickreceiver,new IntentFilter(ChatService.BROADCAST_KICKED));
registerReceiver(nickchangereceiver,new IntentFilter(ChatService.BROADCAST_KICKED));
isRegistered=true;
ImageButton sendBtn=(ImageButton) findViewById(R.id.sendBtn);
sendBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String message=((EditText)findViewById(R.id.sendMsg)).getText().toString();
message=message.trim();
if(!message.contentEquals("")|| message!=null){
if(message.startsWith("/")){
message=message.replaceFirst("[/]","");
service.sendCommand(message.trim());
((EditText)findViewById(R.id.sendMsg)).setText("");
streamMsgs.add("Me: "+message.trim());
adapter.notifyDataSetChanged();
}else{
Message msg=new Message(curNick,curChannel,message);
((EditText)findViewById(R.id.sendMsg)).setText("");
streamMsgs.add("Me: "+message);
adapter.notifyDataSetChanged();
service.send(msg);
}
}
}
});
}
private void setLeftMenu(ArrayList<User> users){
menu = new SlidingMenu(this);
menu.setMode(SlidingMenu.LEFT);
menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);
// menu.setShadowWidthRes(R.dimen.shadow_width);
// menu.setShadowDrawable(R.drawable.shadow);
menu.setBehindOffset(250);
menu.setBehindWidth(300);
menu.setShadowWidth(100);
menu.setFadeDegree(0.2f);
menu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
LayoutInflater inflater=getLayoutInflater();
View v=inflater.inflate(R.layout.left_menu, null);
TextView title=(TextView) v.findViewById(R.id.roomTitle);
title.setText(curChannel+" USERS");
ListView list=(ListView) v.findViewById(R.id.user_list);
userList=new UserListAdapter(users);
list.setAdapter(userList);
menu.setMenu(v);
}
private void setRightMenu(){
SlidingMenu rightmenu = new SlidingMenu(this);
rightmenu.setMode(SlidingMenu.RIGHT);
rightmenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);
// menu.setShadowWidthRes(R.dimen.shadow_width);
// menu.setShadowDrawable(R.drawable.shadow);
rightmenu.setBehindOffset(250);
rightmenu.setBehindWidth(300);
rightmenu.setShadowWidth(100);
rightmenu.setFadeDegree(0.2f);
rightmenu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
LayoutInflater inflater=getLayoutInflater();
View v=inflater.inflate(R.layout.right_menu, null);
TextView title=(TextView) v.findViewById(R.id.title);
title.setText("PRIVATE MESSAGES");
ListView list=(ListView) v.findViewById(R.id.pm_list);
pmAdapter=new PMListAdapter(pmConversations);
list.setAdapter(pmAdapter);
rightmenu.setMenu(v);
}
private void resetLeftMenu(ArrayList<User> users){
userList.update(users);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.home, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_logout:
confirmLogout();
return true;
case R.id.action_register:
registerDialog();
return true;
case R.id.action_changeNick:
changeNickDialog();
return true;
case R.id.action_setQuitMessage:
quitMsgDialog();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void registerDialog(){
AlertDialog.Builder builder=new AlertDialog.Builder(this);
builder.setCancelable(true);
builder.setTitle("Register Nick ");
final EditText passwordInput = new EditText(this);
final EditText emailInput = new EditText(this);
passwordInput.setHint("Password");
emailInput.setHint("Email");
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
passwordInput.setLayoutParams(lp);
emailInput.setLayoutParams(lp);
LinearLayout layout=new LinearLayout(mContext);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(emailInput);
layout.addView(passwordInput);
builder.setView(layout);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
String password=passwordInput.getText().toString();
String email=emailInput.getText().toString();
if(password.contentEquals("")|| email.contentEquals("")){
Toast.makeText(mContext, "Please fill the feilds properly.", Toast.LENGTH_LONG).show();
}else{
service.sendCommand("NS REGISTER "+password+" "+email);
}
arg0.dismiss();
}
});
builder.setNegativeButton("CANCEL",null);
builder.setIcon(R.drawable.ic_launcher);
builder.create().show();
}
private void changeNickDialog(){
AlertDialog.Builder builder=new AlertDialog.Builder(this);
builder.setCancelable(true);
builder.setTitle("Change Nick ");
final EditText input = new EditText(this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
input.setLayoutParams(lp);
builder.setView(input);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
String newNick=input.getText().toString();
if(!newNick.equals("")){
service.changeNick(newNick);
}
else Toast.makeText(mContext, "Invalid nickname.", Toast.LENGTH_LONG).show();
arg0.dismiss();
}
});
builder.setNegativeButton("CANCEL",null);
builder.setIcon(R.drawable.ic_launcher);
builder.create().show();
}
private void quitMsgDialog(){
AlertDialog.Builder builder=new AlertDialog.Builder(this);
builder.setCancelable(true);
builder.setTitle("Quit Message ");
final EditText input = new EditText(this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
input.setLayoutParams(lp);
builder.setView(input);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
String msg=input.getText().toString();
if(!msg.equals(""))
service.setQuitMsg(msg);
else Toast.makeText(mContext, "Cannot set empty message.", Toast.LENGTH_LONG).show();
arg0.dismiss();
}
});
builder.setNegativeButton("CANCEL",null);
builder.setIcon(R.drawable.ic_launcher);
builder.create().show();
}
private void confirmLogout() {
// TODO Auto-generated method stub
AlertDialog.Builder builder=new AlertDialog.Builder(this);
builder.setCancelable(true);
builder.setTitle("Log Out: ");
builder.setMessage("Are you sure you want to leave the chat?");
builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
if(service.quit()){
service.stopForeground(true);
service.stopSelf();
finish();
}else arg0.dismiss();
}
});
builder.setNegativeButton("NO",null);
builder.setIcon(R.drawable.ic_launcher);
builder.create().show();
}
private void kickDialog(String msg) {
// TODO Auto-generated method stub
AlertDialog dialog;
AlertDialog.Builder builder=new AlertDialog.Builder(this);
builder.setCancelable(true);
builder.setTitle(curChannel);
builder.setMessage("You have been kicked from "+curChannel+"\n"+msg+"\n Do you want to rejoin?");
builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int arg1) {
// TODO Auto-generated method stub
service.reJoin();
d.dismiss();
}
});
builder.setNegativeButton("NO",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
service.stopForeground(true);
service.stopSelf();
finish();
}
});
builder.setIcon(R.drawable.ic_launcher);
dialog=builder.create();
dialog.show();
}
private class UserListAdapter extends BaseAdapter{
ArrayList<User> users;
String[] menu={"Private Message","Kick","Whois"};
public UserListAdapter(ArrayList<User> users){
this.users=users;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return users.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return users.get(arg0);
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater inflater = (LayoutInflater)mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView=convertView;
if (gridView == null) {
gridView = inflater.inflate(R.layout.user_item, null);
}
TextView username=(TextView) gridView.findViewById(R.id.userName);
final User user=users.get(position);
username.setText(user.nick);
gridView.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
showUserDialog(user);
}
});
return gridView;
}
public void update(ArrayList<User> users){
this.users=users;
this.notifyDataSetChanged();
}
private void showUserDialog(final User user){
AlertDialog dialog;
AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
.setItems(menu, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int which) {
// The 'which' argument contains the index position
// of the selected item
switch(which){
case 0://Private Message
Intent i=new Intent(mContext,PMActivity.class);
String peer=user.nick;
if(user.mode==User.USER_OPERATOR){
peer=peer.substring(1);
}
i.putExtra("PEER",peer);
service.putToPMList(peer);
pmAdapter.notifyDataSetChanged();
d.dismiss();
startActivity(i);
break;
case 1://Kick
Message msg=new Message(curNick,curChannel,"!kick "+user.nick);
streamMsgs.add("Me: "+msg.getPayload());
adapter.notifyDataSetChanged();
service.send(msg);
d.dismiss();
break;
case 2://WHOIS
Message messg=new Message(curNick,curChannel,"!whois "+user.nick);
streamMsgs.add("Me: "+messg.getPayload());
adapter.notifyDataSetChanged();
d.dismiss();
service.send(messg);
break;
}
}
});
dialog=builder.create();
dialog.show();
}
}
private class PMListAdapter extends BaseAdapter{
ArrayList<String> users;
String[] menu={"View","Block"};
public PMListAdapter(ArrayList<String> users){
this.users=users;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return users.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return users.get(arg0);
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater inflater = (LayoutInflater)mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView=convertView;
if (gridView == null) {
gridView = inflater.inflate(R.layout.pm_item, null);
}
TextView username=(TextView) gridView.findViewById(R.id.userName);
final String user=users.get(position);
username.setText(user);
gridView.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
showUserDialog(user);
}
});
return gridView;
}
private void showUserDialog(final String peer){
AlertDialog dialog;
AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
.setItems(menu, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int which) {
// The 'which' argument contains the index position
// of the selected item
switch(which){
case 0://Private Message
Intent i=new Intent(mContext,PMActivity.class);
i.putExtra("PEER",peer);
service.putToPMList(peer);
pmAdapter.notifyDataSetChanged();
d.dismiss();
startActivity(i);
break;
case 1://block
Message msg=new Message(curNick,curChannel,"!ignore "+peer);
streamMsgs.add("Me: "+msg.getPayload());
adapter.notifyDataSetChanged();
service.send(msg);
d.dismiss();
break;
}
}
});
dialog=builder.create();
dialog.show();
}
}
private BroadcastReceiver pmreceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context c, Intent i) {
// TODO Auto-generated method stub
//String msg=i.getStringExtra("MESSAGE");
String from=i.getStringExtra("FROM");
Log.d("FROM",from);
if(!pmConversations.contains(from)){
//if it doesnot exist.
Log.d("FROM",from+" does not exist, added.");
pmConversations.add(from);
}
pmAdapter.notifyDataSetChanged();
playPMSound();
}
};
private void removeItemsFromList(){
for(int i=0;i<20;i++){
streamMsgs.remove(i);
}
}
private BroadcastReceiver msgreceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context c, Intent i) {
// TODO Auto-generated method stub
String msg=i.getStringExtra("MESSAGE");
String from=i.getStringExtra("FROM");
streamMsgs.add(from+": "+msg);
if(streamMsgs.size()>50)
{
removeItemsFromList();
}
//playGMSound();
adapter.notifyDataSetChanged();
}
};
private BroadcastReceiver userjoinreceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context c, Intent i) {
// TODO Auto-generated method stub
String nick=i.getStringExtra("NICK");
streamMsgs.add(curChannel+":"+nick+" has joined.");
adapter.notifyDataSetChanged();
if(userList!=null)
resetLeftMenu(service.getUsers());
else
setLeftMenu(service.getUsers());
}
};
private BroadcastReceiver userleavereceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context c, Intent i) {
// TODO Auto-generated method stub
String nick=i.getStringExtra("NICK");
String msg=i.getStringExtra("MESSAGE");
streamMsgs.add(curChannel+":"+nick+" has left.("+msg+")");
adapter.notifyDataSetChanged();
if(userList!=null)
resetLeftMenu(service.getUsers());
else
setLeftMenu(service.getUsers());
}
};
private BroadcastReceiver nickchangereceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context c, Intent i) {
// TODO Auto-generated method stub
curNick=service.getCurNick();
}
};
private BroadcastReceiver alertreceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context c, Intent i) {
// TODO Auto-generated method stub
String msg=i.getStringExtra("MESSAGE");
streamMsgs.add(msg);
adapter.notifyDataSetChanged();
}
};
private BroadcastReceiver userListArrive=new BroadcastReceiver(){
@Override
public void onReceive(Context c, Intent i) {
// TODO Auto-generated method stub
setLeftMenu(service.getUsers());
}
};
private BroadcastReceiver kickreceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context c,Intent i){
String kickMsg=i.getStringExtra("MESSAGE");
kickDialog(kickMsg);
}
};
@Override
protected void onResume() {
super.onResume();
bindService(new Intent(this, ChatService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onPause() {
super.onPause();
unbindService(mConnection);
}
@Override
protected void onDestroy(){
super.onDestroy();
if(isRegistered){
unregisterReceiver(this.msgreceiver);
unregisterReceiver(this.userjoinreceiver);
unregisterReceiver(this.userleavereceiver);
unregisterReceiver(this.userListArrive);
unregisterReceiver(this.pmreceiver);
unregisterReceiver(this.alertreceiver);
unregisterReceiver(this.kickreceiver);
unregisterReceiver(this.nickchangereceiver);
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
service = ((ChatService.LocalBinder) binder).getService();
Log.d("ROOM","SERVICE ATTACHED");
if(!service.hasIRC()){
Toast.makeText(mContext, "Sorry,you have been disconnected from the server.Please login.",Toast.LENGTH_LONG ).show();
service.stopSelf();
Intent home=new Intent(mContext,Home.class);
startActivity(home);
finish();
return;
}
curChannel=service.getCurChannel();
curNick=service.getCurNick();
if(curChannel!=null && curNick!=null)
dialog.dismiss();
pmConversations=service.getPMList();
if(userList!=null)
resetLeftMenu(service.getUsers());
else
setLeftMenu(service.getUsers());
setEverything();
setRightMenu();
}
public void onServiceDisconnected(ComponentName className) {
service = null;
unregisterReceiver(kickreceiver);
}
};
}
当我检查Logcat时,在处理此活动时,我收到了很多垃圾收集:
/dalvikvm(22339): GC_CONCURRENT freed 1729K, 35% free 9251K/14151K, paused 15ms+25ms, total 130ms
D/dalvikvm(22339): WAIT_FOR_CONCURRENT_GC blocked 150ms
当我用足够好的内存(1GB)测试应用程序时它很好但是当我使用内存低至512K的设备进行测试时,性能确实很低。我在谷歌中搜索过类似的问题,发现其中大部分是由于relativelayout中的edittext。但是,即使我改变了它,它仍然工作得很差。我知道有一些内存泄漏,但我没有指出在哪里。所以,请帮助我。
答案 0 :(得分:0)
查看您使用的资源。如果你有一些可以使用大内存的绘图,那么内存较小的设备可以非常缓慢地使用你的应用程序。