-1

Good morning everyone. In order to have an autocompletion editText that can find a character sequence between parentheses or brackets I followed this AutoCompleteTextView not completing words inside parentheses but the CustomArrayAdapter I've created made a NoClassDefFoundError :

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.paullemesnager.flashbac, PID: 4665
    java.lang.NoClassDefFoundError: com.paullemesnager.flashbac.CustomArrayAdapter
    at com.paullemesnager.flashbac.SelectAssocActivity.onCreate(SelectAssocActivity.java:64)
    at android.app.Activity.performCreate(Activity.java:5990)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2332)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2442)
    at android.app.ActivityThread.access$800(ActivityThread.java:156)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1351)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:211)
    at android.app.ActivityThread.main(ActivityThread.java:5373)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1020)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:815)

I can't understand why I get this error and how to resolve it, can someone help me please ?

EDIT : The code of the CustomArrayAdapter is the same as here but I changed one class :

 private class ArrayFilter extends Filter {
    @Override
    protected FilterResults performFiltering(CharSequence prefix) {
        FilterResults results = new FilterResults();

        if (mOriginalValues == null) {
            synchronized (mLock) {
                mOriginalValues = new ArrayList<T>(mObjects);
            }
        }

        if (prefix == null || prefix.length() == 0) {
            ArrayList<T> list;
            synchronized (mLock) {
                list = new ArrayList<T>(mOriginalValues);
            }
            results.values = list;
            results.count = list.size();
        } else {
            String prefixString = prefix.toString().toLowerCase();

            ArrayList<T> values;
            synchronized (mLock) {
                values = new ArrayList<T>(mOriginalValues);
            }

            final int count = values.size();
            final ArrayList<T> newValues = new ArrayList<T>();

            for (int i = 0; i < count; i++) {
                final T value = values.get(i);
                final String valueText = value.toString().toLowerCase();

                // First match against the whole, non-splitted value
                if (valueText.startsWith(prefixString)) {
                    newValues.add(value);
                } else {
                    final String[] words = valueText.split(" ");
                    final int wordCount = words.length;

                    // Start at index 0, in case valueText starts with space(s)
                    for (int k = 0; k < wordCount; k++) {
                        if (words[k].startsWith(prefixString)) {
                            newValues.add(value);
                            break;
                        }
                    }
                }
            }

            results.values = newValues;
            results.count = newValues.size();
        }

        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        //noinspection unchecked
        mObjects = (List<T>) results.values;
        if (results.count > 0) {
            notifyDataSetChanged();
        } else {
            notifyDataSetInvalidated();
        }
    }
}

EDIT 2 : As requested here how I create the CustomArrayAdapter object :

      public class SelectAssocActivity extends AppCompatActivity {
      private CustomArrayAdapter<String> adapterA;

      .
      .
      .

    lv = (ListView) findViewById(R.id.lvAssoc);
    textView = (AutoCompleteTextView) findViewById(R.id.editTextAssoc);
    adapterA = new CustomArrayAdapter<>(this, android.R.layout.simple_list_item_1, associations);
    lv.setAdapter(adapterA);

CustomArrayAdapter.java :

      package com.paullemesnager.flashbac;

      import android.content.Context;
      import android.content.res.Resources;
      import android.util.Log;
      import android.view.ContextThemeWrapper;
      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.TextView;
      import android.widget.ThemedSpinnerAdapter;

      import java.util.ArrayList;
      import java.util.Arrays;
      import java.util.Collection;
      import java.util.Collections;
      import java.util.Comparator;
      import java.util.List;

public class CustomArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSpinnerAdapter {
/**
 * Lock used to modify the content of {@link #mObjects}. Any write operation
 * performed on the array should be synchronized on this lock. This lock is also
 * used by the filter (see {@link #getFilter()} to make a synchronized copy of
 * the original array of data.
 */
private final Object mLock = new Object();

private final LayoutInflater mInflater;

/**
 * Contains the list of objects that represent the data of this CustomArrayAdapter.
 * The content of this list is referred to as "the array" in the documentation.
 */
private List<T> mObjects;

/**
 * The resource indicating what views to inflate to display the content of this
 * array adapter.
 */
private int mResource;

/**
 * The resource indicating what views to inflate to display the content of this
 * array adapter in a drop down widget.
 */
private int mDropDownResource;

/**
 * If the inflated resource is not a TextView, {@link #mFieldId} is used to find
 * a TextView inside the inflated views hierarchy. This field must contain the
 * identifier that matches the one defined in the resource file.
 */
private int mFieldId = 0;

/**
 * Indicates whether or not {@link #notifyDataSetChanged()} must be called whenever
 * {@link #mObjects} is modified.
 */
private boolean mNotifyOnChange = true;

private Context mContext;

// A copy of the original mObjects array, initialized from and then used instead as soon as
// the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
private ArrayList<T> mOriginalValues;
private ArrayFilter mFilter;

/** Layout inflater used for {@link #getDropDownView(int, View, ViewGroup)}. */
private LayoutInflater mDropDownInflater;

/**
 * Constructor
 *
 * @param context The current context.
 * @param resource The resource ID for a layout file containing a TextView to use when
 *                 instantiating views.
 */
public CustomArrayAdapter(Context context,  int resource) {
    this(context, resource, 0, new ArrayList<T>());
}

/**
 * Constructor
 *
 * @param context The current context.
 * @param resource The resource ID for a layout file containing a layout to use when
 *                 instantiating views.
 * @param textViewResourceId The id of the TextView within the layout resource to be populated
 */
public CustomArrayAdapter(Context context,  int resource,  int textViewResourceId) {
    this(context, resource, textViewResourceId, new ArrayList<T>());
}

/**
 * Constructor
 *
 * @param context The current context.
 * @param resource The resource ID for a layout file containing a TextView to use when
 *                 instantiating views.
 * @param objects The objects to represent in the ListView.
 */
public CustomArrayAdapter(Context context,  int resource,  T[] objects) {
    this(context, resource, 0, Arrays.asList(objects));
}

/**
 * Constructor
 *
 * @param context The current context.
 * @param resource The resource ID for a layout file containing a layout to use when
 *                 instantiating views.
 * @param textViewResourceId The id of the TextView within the layout resource to be populated
 * @param objects The objects to represent in the ListView.
 */
public CustomArrayAdapter(Context context,  int resource,  int textViewResourceId,
                           T[] objects) {
    this(context, resource, textViewResourceId, Arrays.asList(objects));
}

/**
 * Constructor
 *
 * @param context The current context.
 * @param resource The resource ID for a layout file containing a TextView to use when
 *                 instantiating views.
 * @param objects The objects to represent in the ListView.
 */
public CustomArrayAdapter(Context context,  int resource,  List<T> objects) {
    this(context, resource, 0, objects);
}

/**
 * Constructor
 *
 * @param context The current context.
 * @param resource The resource ID for a layout file containing a layout to use when
 *                 instantiating views.
 * @param textViewResourceId The id of the TextView within the layout resource to be populated
 * @param objects The objects to represent in the ListView.
 */
public CustomArrayAdapter(Context context, int resource,  int textViewResourceId,
                           List<T> objects) {
    mContext = context;
    mInflater = LayoutInflater.from(context);
    mResource = mDropDownResource = resource;
    mObjects = objects;
    mFieldId = textViewResourceId;
}

/**
 * Adds the specified object at the end of the array.
 *
 * @param object The object to add at the end of the array.
 */
public void add(T object) {
    synchronized (mLock) {
        if (mOriginalValues != null) {
            mOriginalValues.add(object);
        } else {
            mObjects.add(object);
        }
    }
    if (mNotifyOnChange) notifyDataSetChanged();
}

/**
 * Adds the specified Collection at the end of the array.
 *
 * @param collection The Collection to add at the end of the array.
 */
public void addAll(Collection<? extends T> collection) {
    synchronized (mLock) {
        if (mOriginalValues != null) {
            mOriginalValues.addAll(collection);
        } else {
            mObjects.addAll(collection);
        }
    }
    if (mNotifyOnChange) notifyDataSetChanged();
}

/**
 * Adds the specified items at the end of the array.
 *
 * @param items The items to add at the end of the array.
 */
public void addAll(T ... items) {
    synchronized (mLock) {
        if (mOriginalValues != null) {
            Collections.addAll(mOriginalValues, items);
        } else {
            Collections.addAll(mObjects, items);
        }
    }
    if (mNotifyOnChange) notifyDataSetChanged();
}

/**
 * Inserts the specified object at the specified index in the array.
 *
 * @param object The object to insert into the array.
 * @param index The index at which the object must be inserted.
 */
public void insert(T object, int index) {
    synchronized (mLock) {
        if (mOriginalValues != null) {
            mOriginalValues.add(index, object);
        } else {
            mObjects.add(index, object);
        }
    }
    if (mNotifyOnChange) notifyDataSetChanged();
}

/**
 * Removes the specified object from the array.
 *
 * @param object The object to remove.
 */
public void remove(T object) {
    synchronized (mLock) {
        if (mOriginalValues != null) {
            mOriginalValues.remove(object);
        } else {
            mObjects.remove(object);
        }
    }
    if (mNotifyOnChange) notifyDataSetChanged();
}

/**
 * Remove all elements from the list.
 */
public void clear() {
    synchronized (mLock) {
        if (mOriginalValues != null) {
            mOriginalValues.clear();
        } else {
            mObjects.clear();
        }
    }
    if (mNotifyOnChange) notifyDataSetChanged();
}

/**
 * Sorts the content of this adapter using the specified comparator.
 *
 * @param comparator The comparator used to sort the objects contained
 *        in this adapter.
 */
public void sort(Comparator<? super T> comparator) {
    synchronized (mLock) {
        if (mOriginalValues != null) {
            Collections.sort(mOriginalValues, comparator);
        } else {
            Collections.sort(mObjects, comparator);
        }
    }
    if (mNotifyOnChange) notifyDataSetChanged();
}

/**
 * {@inheritDoc}
 */
@Override
public void notifyDataSetChanged() {
    super.notifyDataSetChanged();
    mNotifyOnChange = true;
}

/**
 * Control whether methods that change the list ({@link #add},
 * {@link #insert}, {@link #remove}, {@link #clear}) automatically call
 * {@link #notifyDataSetChanged}.  If set to false, caller must
 * manually call notifyDataSetChanged() to have the changes
 * reflected in the attached view.
 *
 * The default is true, and calling notifyDataSetChanged()
 * resets the flag to true.
 *
 * @param notifyOnChange if true, modifications to the list will
 *                       automatically call {@link
 *                       #notifyDataSetChanged}
 */
public void setNotifyOnChange(boolean notifyOnChange) {
    mNotifyOnChange = notifyOnChange;
}

/**
 * Returns the context associated with this array adapter. The context is used
 * to create views from the resource passed to the constructor.
 *
 * @return The Context associated with this adapter.
 */
public Context getContext() {
    return mContext;
}

/**
 * {@inheritDoc}
 */
public int getCount() {
    return mObjects.size();
}

/**
 * {@inheritDoc}
 */
public T getItem(int position) {
    return mObjects.get(position);
}

/**
 * Returns the position of the specified item in the array.
 *
 * @param item The item to retrieve the position of.
 *
 * @return The position of the specified item.
 */
public int getPosition(T item) {
    return mObjects.indexOf(item);
}

/**
 * {@inheritDoc}
 */
public long getItemId(int position) {
    return position;
}

/**
 * {@inheritDoc}
 */
public View getView(int position, View convertView, ViewGroup parent) {
    return createViewFromResource(mInflater, position, convertView, parent, mResource);
}

private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
        ViewGroup parent, int resource) {
    View view;
    TextView text;

    if (convertView == null) {
        view = inflater.inflate(resource, parent, false);
    } else {
        view = convertView;
    }

    try {
        if (mFieldId == 0) {
            //  If no custom field is assigned, assume the whole resource is a TextView
            text = (TextView) view;
        } else {
            //  Otherwise, find the TextView field within the layout
            text = (TextView) view.findViewById(mFieldId);
        }
    } catch (ClassCastException e) {
        Log.e("CustomArrayAdapter", "You must supply a resource ID for a TextView");
        throw new IllegalStateException(
                "CustomArrayAdapter requires the resource ID to be a TextView", e);
    }

    T item = getItem(position);
    if (item instanceof CharSequence) {
        text.setText((CharSequence)item);
    } else {
        text.setText(item.toString());
    }

    return view;
}

/**
 * <p>Sets the layout resource to create the drop down views.</p>
 *
 * @param resource the layout resource defining the drop down views
 * @see #getDropDownView(int, android.view.View, android.view.ViewGroup)
 */
public void setDropDownViewResource(int resource) {
    this.mDropDownResource = resource;
}

/**
 * Sets the {@link Resources.Theme} against which drop-down views are
 * inflated.
 * <p>
 * By default, drop-down views are inflated against the theme of the
 * {@link Context} passed to the adapter's constructor.
 *
 * @param theme the theme against which to inflate drop-down views or
 *              {@code null} to use the theme from the adapter's context
 * @see #getDropDownView(int, View, ViewGroup)
 */
@Override
public void setDropDownViewTheme(Resources.Theme theme) {
    if (theme == null) {
        mDropDownInflater = null;
    } else if (theme == mInflater.getContext().getTheme()) {
        mDropDownInflater = mInflater;
    } else {
        final Context context = new ContextThemeWrapper(mContext, theme);
        mDropDownInflater = LayoutInflater.from(context);
    }
}

@Override
public Resources.Theme getDropDownViewTheme() {
    return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme();
}

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater;
    return createViewFromResource(inflater, position, convertView, parent, mDropDownResource);
}

/**
 * Creates a new CustomArrayAdapter from external resources. The content of the array is
 * obtained through {@link android.content.res.Resources#getTextArray(int)}.
 *
 * @param context The application's environment.
 * @param textArrayResId The identifier of the array to use as the data source.
 * @param textViewResId The identifier of the layout used to create views.
 *
 * @return An CustomArrayAdapter<CharSequence>.
 */
public static CustomArrayAdapter<CharSequence> createFromResource(Context context,
                                                                   int textArrayResId,  int textViewResId) {
    CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
    return new CustomArrayAdapter<CharSequence>(context, textViewResId, strings);
}

/**
 * {@inheritDoc}
 */
public Filter getFilter() {
    if (mFilter == null) {
        mFilter = new ArrayFilter();
    }
    return mFilter;
}

/**
 * <p>An array filter constrains the content of the array adapter with
 * a prefix. Each item that does not start with the supplied prefix
 * is removed from the list.</p>
 */
private class ArrayFilter extends Filter {
    @Override
    protected FilterResults performFiltering(CharSequence prefix) {
        FilterResults results = new FilterResults();

        if (mOriginalValues == null) {
            synchronized (mLock) {
                mOriginalValues = new ArrayList<T>(mObjects);
            }
        }

        if (prefix == null || prefix.length() == 0) {
            ArrayList<T> list;
            synchronized (mLock) {
                list = new ArrayList<T>(mOriginalValues);
            }
            results.values = list;
            results.count = list.size();
        } else {
            String prefixString = prefix.toString().toLowerCase();

            ArrayList<T> values;
            synchronized (mLock) {
                values = new ArrayList<T>(mOriginalValues);
            }

            final int count = values.size();
            final ArrayList<T> newValues = new ArrayList<T>();

            for (int i = 0; i < count; i++) {
                final T value = values.get(i);
                final String valueText = value.toString().toLowerCase();

                // First match against the whole, non-splitted value
                if (valueText.startsWith(prefixString)) {
                    newValues.add(value);
                } else {
                    final String[] words = valueText.split(" ");
                    final int wordCount = words.length;

                    // Start at index 0, in case valueText starts with space(s)
                    for (int k = 0; k < wordCount; k++) {
                        if (words[k].startsWith(prefixString)) {
                            newValues.add(value);
                            break;
                        }
                    }
                }

                if (valueText.startsWith(prefixString) || valueText.contains(prefixString)) {
                    newValues.add(value);
                } else {
                    final String[] words = valueText.split(" ");
                    final int wordCount = words.length;
                    // Start at index 0, in case valueText starts with space(s)
                    for (int k = 0; k < wordCount; k++) {
                        if (words[k].startsWith(prefixString) || words[k].contains(prefixString)) {
                            newValues.add(value);
                            break;
                        }
                    }
                }
            }

            results.values = newValues;
            results.count = newValues.size();
        }

        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        //noinspection unchecked
        mObjects = (List<T>) results.values;
        if (results.count > 0) {
            notifyDataSetChanged();
        } else {
            notifyDataSetInvalidated();
        }
    }
}
 }

The path of the 2 files :

 app\src\main\java\com\paullemesnager\flashbac\CustomArrayAdapter.java
 app\src\main\java\com\paullemesnager\flashbac\SelectAssocActivity.java
Community
  • 1
  • 1
Paul Lemesnager
  • 119
  • 1
  • 10

2 Answers2

0

The javadoc's are pretty self explanatory

https://docs.oracle.com/javase/7/docs/api/java/lang/NoClassDefFoundError.html

Thrown if the Java Virtual Machine or a ClassLoader instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found. The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.

Generally it means at run-time jar which contains your CustomArrayAdapter class is missing

user1933888
  • 2,897
  • 3
  • 27
  • 36
0

As you can see in the logs, error is happening at:

java.lang.NoClassDefFoundError: com.paullemesnager.flashbac.CustomArrayAdapter
com.paullemesnager.flashbac.SelectAssocActivity.onCreate(SelectAssocActivity.java:64)
...

So, you have to open SelectAssocActivity.java, find line 64 and check what you wrote there.

It seems that you tried to create some object of type CustomArrayAdapter. However, that class does not exist (NoClassDefFoundError).

I checked the link that you posted. Name of that class is ArrayAdapter and not CustomArrayAdapter.

public class ArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSpinnerAdapter {
    ...
}

So, check SelectAssocActivity.java, line 64 and if change the object type from CustomArrayAdapter to ArrayAdapter.

guipivoto
  • 18,327
  • 9
  • 60
  • 75
  • In the link I posted he advised to rename the class, that's what I did. My class name is CustomArrayAdapter, that's why I didn't understand why it's not found. Here the line 64 : `adapterA = new CustomArrayAdapter<>(this,android.R.layout.simple_list_item_1,associations);` Do you have another clue ? Thanks for your time. – Paul Lemesnager May 18 '16 at 12:51
  • @PaulLemesnager Could you please update your answer and add the Adapter definition (CustomArrayAdapter.java) and share how you create the CustomArrayAdapter object? Post them in your answer, please... also, share the path where you save those files (the relative path only... inside app folder) – guipivoto May 18 '16 at 13:07
  • See "EDIT 2", I didn't understand all the things you say, there is all things you asked for ? – Paul Lemesnager May 18 '16 at 13:43