0

I have a FragmentActivity that has 5 Fragments

On my 2nd fragment is a gridview that displays many images.

That GridFragment is starting an AsyncTask with callback to get the arraylist of images.

It then sets an adapter using the following as arguments (listener, context, arraylist) context is getActivity()

when adapter starts it tries to do LayoutInflater.from(Context);

That is where im getting my null pointer. If the async task is complete it will not crash. but it i rotate while async task is working it crashes.

Is there any way around this?

Fragment

public class IconsFrag extends GridFragmentIcons implements AdapterIcons.AdapterListener {

    AsyncTaskIconsAll aTask;
    Button button;
    final String TAG = "IconsFrag";
    private ArrayList<Integer> mThumbs;
    private final String KEY_LIST_DATA = "icons_cache";
    private final String KEY_LIST_POSITION = "icons_position";
    private int mPosition = -1;
    private AdapterIcons mAdapter;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        Log.i(TAG, "onActivityCreated");
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null){
            Log.i(TAG, "savedInstanceState null");
            aTask = new AsyncTaskIconsAll();
            aTask.updateActivity(this, getActivity(), new AsyncTaskIconsAll.Callback() {
                @Override
                public void onData(ArrayList<Integer> data) {
                    mThumbs = data;

                    mAdapter = new AdapterIcons(IconsFrag.this, getActivity(), mThumbs);
                    getGridView().setNumColumns(getResources().getInteger(R.integer.column_count_icon));
                    setGridAdapter(mAdapter);
                    getGridView().setOnItemClickListener(null);
                }
            });
            aTask.execute();
        }

AsyncTask

public class AsyncTaskIconsAll extends AsyncTask<Void, Integer, ArrayList<Integer>> {

    private Activity mContext;
    private Fragment mFragment;
    private ArrayList<Integer> mThumbs;
    final String TAG = "AsyncTaskIconsAll";
    Callback mCallback;

    public static interface Callback{
        public void onData(ArrayList<Integer> data);
    }

    public void updateActivity(Fragment f, Activity a, final Callback c) {
        Log.i(TAG, "updateActivity");
        mContext = a;
        mFragment = f;
        mCallback = c;
        if(mThumbs != null)
            Log.i(TAG, "Callback not null");
            mCallback.onData(mThumbs);
    }

    @Override
    protected void onPreExecute() {

    }

    @Override
    protected ArrayList<Integer> doInBackground(Void... unused){
        Log.i(TAG, "doInBackground");
        mThumbs = new ArrayList<Integer>();
        final String[] extras = mContext.getResources().getStringArray(R.array.icon_pack);
            for (String extra : extras) {
                String uri = "drawable/" + extra;
                int res = mContext.getResources().getIdentifier(uri, null, mContext.getPackageName());
                if (res != 0) {
                    mThumbs.add(res);
                }
            }
        return mThumbs;
    }

    protected void onProgressUpdate(Integer... progress) {

    }

    @Override
    protected void onPostExecute(ArrayList<Integer> icons) {
        Log.i(TAG, "onPostExecute");
        mThumbs = icons;
        mCallback.onData(mThumbs);
        ProgressBar mProgess = (ProgressBar) mFragment.getView().findViewById(R.id.pending);
        mProgess.setVisibility(mFragment.getView().GONE);
    }
}

Adapter

public class AdapterIcons extends BaseAdapter implements SpinnerAdapter {

    private final String TAG = "AdapterIcons";
    private AdapterListener mListener;
    private ArrayList<?> mData;
    private final LayoutInflater mInflater;

    public AdapterIcons(AdapterListener listener, Activity activity) {
        this.mData = new ArrayList<Object>();
        this.mInflater = LayoutInflater.from(activity);
        this.mListener = listener;
    }

    public AdapterIcons(AdapterListener listener, Context Context, ArrayList<?> data) {
        this.mData = (data == null) ? new ArrayList<Object>() : data;
        this.mInflater = LayoutInflater.from(Context);
        this.mListener = listener;
    }

    public ArrayList<?> getData () {
        return this.mData;
    }

    public void setData (ArrayList<?> data) {
        this.mData = data;
    }

    public void clearData () {
        this.mData.clear();
    }

    public static abstract interface AdapterListener
    {
        public abstract View getView(int paramInt, View paramView, ViewGroup paramViewGroup);
    }

    public Intent.ShortcutIconResource getResource(int position){
        Icons icons= new Icons();
        ArrayList<Integer> list = (ArrayList<Integer>) mData;
        return Intent.ShortcutIconResource.fromContext(icons.getBaseContext(), list.get(position));
    }

    @Override
    public int getCount () {
        if (mData == null)
            Log.d(TAG, "getCount() Data Set Is Null");
        return (mData != null) ? mData.size() : 0;
    }

    @Override
    public Object getItem (int position) {
        if (mData == null)
            Log.d(TAG, "getItem(int position) Data Set Is Null");
        return (mData != null) ? mData.get(position) : null;
    }

    @Override
    public long getItemId (int position) {
        if (mData == null)
            Log.d(TAG, "getItemId(int position) Data Set Is Null");
        return (mData != null) ? position : 0;
    }

    @Override
    public View getView (int position, View convertView, ViewGroup parent) {
        return (mListener == null) ? new LinearLayout(mInflater.getContext()) : this.mListener.getView(position, convertView, parent);
    }

    @Override
    public View getDropDownView (int position, View convertView, ViewGroup parent) {
        return (mListener == null) ? new LinearLayout(mInflater.getContext()) : this.mListener.getView(position, convertView, parent);
    }

}
BigDX
  • 3,519
  • 5
  • 38
  • 52

3 Answers3

0

Take a look on this answer. It's pretty much the same problem. You need to handle orientation changes which changes the activity state in default(if you don't override).

https://stackoverflow.com/a/7618739/1080954

Community
  • 1
  • 1
osayilgan
  • 5,873
  • 7
  • 47
  • 68
0

so in your onPostExecute() you try to add items to an activity which is (temporarily) destroyed. Check if your getActivity() == null before doing stuff with the context. Something like:

public void onPostExecute(){

    if(getActivity() == null){
        // activity is destroyed... skip
        return;
    }

    // proceed like normal

}

This is the best I can do without anymore code. Good luck

Entreco
  • 12,738
  • 8
  • 75
  • 95
0

Did you notice that you should use brackets {} in here, otherwise mCallback.onData(mThumbs) will always be called:

if(mThumbs != null){
        Log.i(TAG, "Callback not null");
        mCallback.onData(mThumbs);
}

Also you're passing the fragment and the activity in asyncTask updateActivity() method when you create the asyncTask but they will be null when you rotate your device, the activity is going to be recreated, so when you use them in asyncTask doInBackground() and onPostExecute() you have to check first if they are not null, otherwise you could end up with a NullPointerException.

Sergio Serra
  • 1,479
  • 3
  • 17
  • 25
  • @Bignadad response changed – Sergio Serra Nov 13 '13 at 18:03
  • Thanks for that tip, that will help when mthumbs has already been created. but for the problem im having mthumbs is null. if the user rotates device while mthumbs is building it crashes – BigDX Nov 13 '13 at 18:11