Search code examples
androidstringclasscastexceptionpidonitemclick

ClassCastException for onItemClick variable


I am getting a ClassCastException for the pid variable that I am trying to show on screen. I know that the item at the onclick position is a string that is casting to RunningAppProcessInfo which is causing the exception, but I cant figure out how I can get the pid without using it though.

Here is my code

  ActivityManager activityManager = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
  List<RunningAppProcessInfo> list = activityManager.getRunningAppProcesses();

  ArrayList<String> info = new ArrayList<>();
  for (ActivityManager.RunningAppProcessInfo p : list) {
      info.add(p.processName);
  }

  ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, info);
  ListView listView = (ListView) findViewById(R.id.list);
  listView.setAdapter(adapter);

  listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
          int  uid = ((RunningAppProcessInfo)parent.getItemAtPosition(position)).pid;
          Toast.makeText(getApplicationContext(),uid,Toast.LENGTH_LONG).show();
        }
  });

Solution

  • Well, no. The way you've initialized your adapter, the item is going to be the process name, not the process ID. It certainly won't be an instance of RunningAppProcessInfo. If you want your items to be process IDs, redefine your adapter as follows:

    ArrayList<Integer> info = new ArrayList<>();
    for (ActivityManager.RunningAppProcessInfo p : list) {
        info.add(p.pid); // not p.processName
    }
    
    ArrayAdapter<Integer> adapter = new ArrayAdapter<>(this,
       android.R.layout.simple_list_item_1, info);
    

    and then retrieve it with:

    int uid = (Integer) parent.getItemAtPosition(position);
    

    If you need both, you'll have to define your own class that holds both the process name and the ID:

    class Info {
        final String processName;
        final int pid;
        Info(String processName, int pid) {
            this.processName = processName;
            this.pid = pid;
        }
        @Override
        public String toString() {
            return processName;
        }
    }
    ArrayList<Info> info = new ArrayList<>();
    for (ActivityManager.RunningAppProcessInfo p : list) {
        info.add(new Info(p.processName, p.pid));
    }
    
    ArrayAdapter<Info> adapter = new ArrayAdapter<>(this,
       android.R.layout.simple_list_item_1, info);
    

    and retrieve it with:

    int uid = ((Info)parent.getItemAtPosition(position)).pid;
    

    You might be tempted to write:

    ArrayList<RunningAppProcessInfo> info = new ArrayList<>();
    for (ActivityManager.RunningAppProcessInfo p : list) {
        info.add(p);
    }
    
    ArrayAdapter<RunningAppProcessInfo> adapter = new ArrayAdapter<>(this,
       android.R.layout.simple_list_item_1, info);
    

    and keep your original retrieval code, but unfortunately, RunningAppProcessInfo doesn't have a usable toString() method for the adapter to use, so you're going to have to write a container class one way or another.