Android应用程序执行缓慢,潜在的内存泄漏

时间:2014-01-26 14:14:33

标签: android performance memory-management memory-leaks garbage-collection

我已经在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。但是,即使我改变了它,它仍然工作得很差。我知道有一些内存泄漏,但我没有指出在哪里。所以,请帮助我。

1 个答案:

答案 0 :(得分:0)

查看您使用的资源。如果你有一些可以使用大内存的绘图,那么内存较小的设备可以非常缓慢地使用你的应用程序。