0

I just finished adding a search feature to my android widget to search through a list of the users installed applications. My app installs fine and everything but when I go to search something the app force closes and I get this error:

10-18 11:10:49.393: E/AndroidRuntime(10901): FATAL EXCEPTION: main
10-18 11:10:49.393: E/AndroidRuntime(10901): java.lang.NullPointerException
10-18 11:10:49.393: E/AndroidRuntime(10901):    at com.example.awesomefilebuilderwidget.AppInfoAdapter.getCount(AppInfoAdapter.java:33)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at android.widget.AdapterView$AdapterDataSetObserver.onChanged(AdapterView.java:778)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:31)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at com.example.awesomefilebuilderwidget.AppInfoAdapter$1.publishResults(AppInfoAdapter.java:98)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:282)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at android.os.Handler.dispatchMessage(Handler.java:99)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at android.os.Looper.loop(Looper.java:150)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at android.app.ActivityThread.main(ActivityThread.java:4333)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at java.lang.reflect.Method.invokeNative(Native Method)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at java.lang.reflect.Method.invoke(Method.java:507)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
10-18 11:10:49.393: E/AndroidRuntime(10901):    at dalvik.system.NativeStart.main(Native Method)

Here is my AppInfoAdapter so I might have messed up somewhere along the line:

package com.example.awesomefilebuilderwidget;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;

public class AppInfoAdapter extends BaseAdapter implements Filterable {
private Context mContext;
private List<ApplicationInfo> mListAppInfo;
private PackageManager mPackManager;
private List<ApplicationInfo> originalListAppInfo;
private Filter filter;

public AppInfoAdapter(Context c, List<ApplicationInfo> listApp, PackageManager pm) {
    mContext = c;
    this.originalListAppInfo = this.mListAppInfo = listApp;
    mPackManager = pm;
    }

@Override
public int getCount() {
    return mListAppInfo.size();
}

@Override
public Object getItem(int position) {
    return mListAppInfo.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // get the selected entry
    ApplicationInfo entry = (ApplicationInfo) mListAppInfo.get(position);

    // reference to convertView
    View v = convertView;

    // inflate new layout if null
    if(v == null) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        v = inflater.inflate(R.layout.layout_appinfo, null);
    }

    // load controls from layout resources
    ImageView ivAppIcon = (ImageView)v.findViewById(R.id.ivIcon);
    TextView tvAppName = (TextView)v.findViewById(R.id.tvName);
    TextView tvPkgName = (TextView)v.findViewById(R.id.tvPack);

    // set data to display
    ivAppIcon.setImageDrawable(entry.loadIcon(mPackManager));
    tvAppName.setText(entry.loadLabel(mPackManager));
    tvPkgName.setText(entry.packageName);

    // return view
    return v;
}
@Override
public Filter getFilter() {
    if(filter == null) {
        filter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();
                List<ApplicationInfo> myFilteredAppList = new ArrayList<ApplicationInfo>();
                constraint = constraint.toString().toLowerCase();

                for (ApplicationInfo appInfo : originalListAppInfo) {
                    String somefield = appInfo.name;
                    if (somefield.toLowerCase().contains(constraint.toString())) {
                        myFilteredAppList.add(appInfo);
                    }
                }
                results.count = myFilteredAppList.size();
                results.values = myFilteredAppList;
                return results;
            }


            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                mListAppInfo = (List<ApplicationInfo>)results.values;
                notifyDataSetChanged();
            }
        };
    }
    return filter;
}

}

What's the problem?

ADDED: Here is my Drag_and_Drop_App.java:

package com.example.awesomefilebuilderwidget;

import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;

public class Drag_and_Drop_App extends Activity {
private ListView mListAppInfo;
// Search EditText
EditText inputSearch;
public static AppInfoAdapter adapter;


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // set layout for the main screen
    setContentView(R.layout.drag_and_drop_app);
    // import buttons
    Button btnLinkToFeedback = (Button) findViewById(R.id.btnLinkToFeedback);

    // Link to Feedback Screen
    btnLinkToFeedback.setOnClickListener(new View.OnClickListener() {

        public void onClick(View view) {
            Intent i = new Intent(getApplicationContext(),
                    Feedback.class);
            startActivity(i);
            finish();
        }
    });
    // create new adapter
    adapter = new AppInfoAdapter(this, (List<ApplicationInfo>) Utilities.getInstalledApplication(this), getPackageManager());
    // load list application
   mListAppInfo = (ListView)findViewById(R.id.lvApps);
    // set adapter to list view
    mListAppInfo.setAdapter(adapter);
    // search bar
    inputSearch = (EditText) findViewById(R.id.inputSearch);

    inputSearch.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
            // When user changed the Text
            // Drag_and_Drop_App.this.adapter.getFilter().filter(cs);  
             if (Drag_and_Drop_App.this.adapter == null){
                 // some print statement saying it is null
                 Log.d ("msg_error", "adapter_is_null");
             }
                Drag_and_Drop_App.this.adapter.getFilter().filter(cs);

            }

        @Override
        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
                int arg3) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable arg0) {
            // TODO Auto-generated method stub                          
        }
        });


    // implement event when an item on list view is selected
    mListAppInfo.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
            // get the list adapter
            AppInfoAdapter appInfoAdapter = (AppInfoAdapter)parent.getAdapter();
            // get selected item on the list
            ApplicationInfo appInfo = (ApplicationInfo)appInfoAdapter.getItem(pos);
            // launch the selected application
            Utilities.launchApp(parent.getContext(), getPackageManager(), appInfo.packageName);
        }

    });

    // implement event when an item on list view is selected via long-click for drag and drop
    mListAppInfo.setOnItemLongClickListener(new OnItemLongClickListener(){

        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view,
                int pos, long id) {
            // TODO Auto-generated method stub
            // get the list adapter
            AppInfoAdapter appInfoAdapter = (AppInfoAdapter)parent.getAdapter();
            // get selected item on the list
            ApplicationInfo appInfo = (ApplicationInfo)appInfoAdapter.getItem(pos);
            // launch the selected application
            Utilities.launchApp(parent.getContext(), getPackageManager(), appInfo.packageName);
            return true;
        }


    });
}
}

ADDED CLASS: Here is my Utilities class:

package com.example.awesomefilebuilderwidget;

import java.util.List;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.widget.Toast;

public class Utilities {

/*
 * Get all installed application on mobile and return a list
 * @param   c   Context of application
 * @return  list of installed applications
 */
public static List<?> getInstalledApplication(Context c) {
    return c.getPackageManager().getInstalledApplications(PackageManager.GET_META_DATA);
}

/*
 * Launch an application
 * @param   c   Context of application
 * @param   pm  the related package manager of the context
 * @param   pkgName Name of the package to run
 */
public static boolean launchApp(Context c, PackageManager pm, String pkgName) {
    // query the intent for lauching
    Intent intent = pm.getLaunchIntentForPackage(pkgName);
    // if intent is available
    if(intent != null) {
        try {
            // launch application
            c.startActivity(intent);
            // if succeed
            return true;

        // if fail
        } catch(ActivityNotFoundException ex) {
            // quick message notification
            Toast toast = Toast.makeText(c, "Application Not Found", Toast.LENGTH_LONG);
            // display message
            toast.show();
        }
    }
    // by default, fail to launch
    return false;
}
}
user1628978
  • 501
  • 2
  • 6
  • 24
  • 3
    It looks like `mListAppInfo` is `null`. – codeMagic Oct 18 '13 at 17:17
  • So how can I fix this? – user1628978 Oct 18 '13 at 17:23
  • 1
    I get a safety warning on mListAppInfo = (List)results.values; saying it is an unchecked cast from Object to List as well if that helps – user1628978 Oct 18 '13 at 17:26
  • Is `listApp` `null` when you call your `Adapter constructor`? – codeMagic Oct 18 '13 at 17:30
  • Whatever you are passisng as listApp in the constructor, I'm betting it's null, hence mlistAppInfo is as well. Judging by your previous code, `Utilities.getInstalledApplication(this)` is returning is null. – Otra Oct 18 '13 at 17:30
  • @Otra yes that's right it is – user1628978 Oct 18 '13 at 17:31
  • On the Utilities line it says "Type Safety: Unchecked cast from List to List – user1628978 Oct 18 '13 at 17:34
  • Where is the Utilities code? – Otra Oct 18 '13 at 17:45
  • I'll add it in, it's another class that handles user events in my list – user1628978 Oct 18 '13 at 17:46
  • I added the Utilities class to the question – user1628978 Oct 18 '13 at 22:17
  • Or if you mean the actual Utilities line I was talking about I mean this line "Utilities.getInstalledApplication(this)" I really apperciate your help by the way, I'm at a loss on what to do so it's amazing to see everyone figure this out. – user1628978 Oct 18 '13 at 22:22
  • Actually the full Utilities line I was talking about that gave the type safety error is "adapter = new AppInfoAdapter(this, (List) Utilities.getInstalledApplication(this), getPackageManager());" in my Drag and Drop App and the other line I get the error on is "mListAppInfo = (List)results.values;" in my AppInfoAdapter, which could explain why it's returning null but then how to go about fixing it – user1628978 Oct 18 '13 at 22:30

3 Answers3

1

Add this code before for loop:

if (constraint.length() == 0) {
myFilteredAppList.addAll(originalListAppInfo);
} 

i.e

@Override
    public Filter getFilter() {
        if(filter == null) {
            filter = new Filter() {
                @Override
                protected FilterResults performFiltering(CharSequence constraint) {
                    FilterResults results = new FilterResults();
                    List<ApplicationInfo> myFilteredAppList = new ArrayList<ApplicationInfo>();
                    constraint = constraint.toString().toLowerCase();

                     if (constraint.length() == 0) {
                         myFilteredAppList.addAll(originalListAppInfo);
                        } 

                    for (ApplicationInfo appInfo : originalListAppInfo) {
                        String somefield = appInfo.name;
                        if (somefield.toLowerCase().contains(constraint.toString())) {
                            myFilteredAppList.add(appInfo);
                        }
                    }
                    results.count = myFilteredAppList.size();
                    results.values = myFilteredAppList;
                    return results;
                }

                @Override
                protected void publishResults(CharSequence constraint, FilterResults results) {
                    mListAppInfo = (List<ApplicationInfo>)results.values;
                    notifyDataSetChanged();
                }
            };
        }
        return filter;
    }
Abhishek V
  • 12,488
  • 6
  • 51
  • 63
1

Seems that mListAppInfo is null in

@Override
public int getCount() {
    return mListAppInfo.size();
}

Which makes me suppose that for some reason your call to getInstalledApplications when you instantiate the adapter returns null.

znat
  • 13,144
  • 17
  • 71
  • 106
  • So is there a way I could fix it? If you look at some of the other answers or questions that could help to rule out certain things. I'm at a loss of what to do. – user1628978 Oct 18 '13 at 22:17
1

Your list contains appInfo.packageName not appInfo.name.

In performFiltering method you are adding appInfo.name to filtered list. Instead you should add appInfo.packageName.

Your for loop should be like this

 for (ApplicationInfo appInfo : originalListAppInfo) {
        String somefield = appInfo.packageName;
        if (somefield.toLowerCase().contains(constraint.toString())) {
              myFilteredAppList.add(appInfo);
        }
  }

This should work. And never forget to check for null values in publishResults method

 @Override
protected void publishResults(CharSequence constraint, FilterResults results) {

  if(results.values != null)
  {
    mListAppInfo = (List<ApplicationInfo>)results.values;
    notifyDataSetChanged();
  }

}
Abhishek V
  • 12,488
  • 6
  • 51
  • 63
  • Oh wow that fixed it and got the search working! Thanks a bunch! I know we're not supposed to say "thanks" but after trying to fix this for a few days it feels good to have it working. – user1628978 Oct 20 '13 at 02:12