سؤال

I'm writing a FragmentActivity where I have a ListFragment (using a SimpleCursorAdapter), a detailsFragment and a detailActivity (that is used when the phone is in portrait, embed the detailsFragment).
When I click on one item in the list it should populate the detailFragment with data from a second cursor, built using the _id of the selected item as a selectionArgs.
But, the _id doesn't seem to pass, I got a toast in ListFragment where I show the _id of the selected item (and it is correct), but in the detailsFragment the _id never arrives (it remains equals to 0, sending a NullPointerException). Where am I mistaking?

EDIT: I forgot to say also that when I go back from detailsActivity with the back button, the list is empty and it says something about the database being closed.
The Logcat messages can be found at the end of my post.

Parent Activity

package com.gmail.david.corsalini.sportscout;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

public class MatchesRugbyPage extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.matches_rugby);
    }
}

MatchesListFragment (my ListFragment)

package com.gmail.david.corsalini.sportscout;

import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;

/**
 * This is the "top-level" fragment, showing a list of items that the user can
 * pick. Upon picking an item, it takes care of displaying the data to the user
 * as appropriate based on the current UI layout.
 */
public class MatchesListFragment extends ListFragment {
    boolean mDualPane;
    private Cursor cursor;
    private SimpleCursorAdapter myAdapter;
    private long MATCH_ID;
    private int selected;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Database
        DBSportScout db = new DBSportScout(getActivity());
        db.open();
        // Cursor
        String[] selection = { DBSportScout.MatchMetaData.KEY_MNAME,
                DBSportScout.MatchMetaData.KEY_MROWID };
        cursor = db.fetch(DBSportScout.MatchMetaData.DATABASE_TABLE_MATCH,
                selection, null, null, null, null, null, null);
        getActivity().startManagingCursor(cursor);
        // Adapter
        String[] columns = { DBSportScout.MatchMetaData.KEY_MNAME };
        int[] to = { R.id.tv1ListItem };
        myAdapter = new SimpleCursorAdapter(getActivity(),
                R.layout.ss_list_item, cursor, columns, to);
        setListAdapter(myAdapter);
        db.close();

        // Check to see if we have a frame in which to embed the details
        // fragment directly in the containing UI.
        View detailsFrame = getActivity().findViewById(R.id.detailsFrame);
        mDualPane = detailsFrame != null
                && detailsFrame.getVisibility() == View.VISIBLE;

        if (savedInstanceState != null) {
            // Restore last state for checked position.
            MATCH_ID = savedInstanceState.getLong("curChoice", 0);
        }

        if (mDualPane) {
            // In dual-pane mode, the list view highlights the selected item.
            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
            // Make sure our UI is in the correct state.
            showDetails(MATCH_ID);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putLong("curChoice", MATCH_ID);
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        selected = position;
        MATCH_ID = myAdapter.getItemId(position);
        Toast.makeText(getActivity(), "Partita n. " + Long.toString(MATCH_ID),
                Toast.LENGTH_SHORT).show();
        showDetails(MATCH_ID);
        Log.i("Partita", "ID Partita selezionata= " + MATCH_ID);
    }

    /**
     * Helper function to show the details of a selected item, either by
     * displaying a fragment in-place in the current UI, or starting a whole new
     * activity in which it is displayed.
     */

    public void showDetails(long matchid) {

        if (mDualPane) {
            // We can display everything in-place with fragments, so update
            // the list to highlight the selected item and show the data.
            getListView().setItemChecked(selected, true);

            // Check what fragment is currently shown, replace if needed.
            MatchDetailsFragment f = (MatchDetailsFragment) getFragmentManager()
                    .findFragmentById(R.id.detailsFrame);
            if (f == null || f.getMATCH_ID() != matchid) {
                // Make new fragment to show this selection.
                f = new MatchDetailsFragment();

                // Supply index input as an argument.
                Bundle args = new Bundle();
                args.putLong("matchid", matchid);
                f.setArguments(args);

                // Execute a transaction, replacing any existing fragment
                // with this one inside the frame.
                FragmentTransaction ft = getFragmentManager()
                        .beginTransaction();
                ft.replace(R.id.detailsFrame, f);
                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                ft.addToBackStack(null);
                ft.commit();
            }

        } else {
            // Otherwise we need to launch a new activity to display
            // the dialog fragment with selected text.
            Intent intent = new Intent();
            intent.setClass(getActivity(), MatchDetailsActivity.class);
            intent.putExtra("index", matchid);
            startActivity(intent);
        }
    }

}

MatchDetailFragment (my detailsFragment)

package com.gmail.david.corsalini.sportscout;

import com.gmail.david.corsalini.sportscout.DBSportScout.MatchMetaData;

import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

/**
 * This is the secondary fragment, displaying the details of a particular item.
 */
public class MatchDetailsFragment extends Fragment {

    /**
     * Create a new instance of DetailsFragment, initialized to show the text at
     * 'matchid'.
     */
    public static MatchDetailsFragment newInstance(long matchid) {
        MatchDetailsFragment f = new MatchDetailsFragment();

        // Supply index input as an argument.
        Bundle args = new Bundle();
        args.putLong("matchid", matchid);
        f.setArguments(args);
        return f;
    }

    private TextView tvfTriesA;
    private TextView tvfTriesB;
    private TextView tvfName;
    private long MATCH_ID;
    public long getMATCH_ID() {
        MATCH_ID = getArguments().getLong("matchid", 0);
        return MATCH_ID;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (container == null) {
            // We have different layouts, and in one of them this
            // fragment's containing frame doesn't exist. The fragment
            // may still be created from its saved state, but there is
            // no reason to try to create its view hierarchy because it
            // won't be displayed. Note this is not needed -- we could
            // just run the code below, where we would create and return
            // the view hierarchy; it would just never be used.
            return null;
        }
        View view = inflater.inflate(R.layout.match_summary, container, false);
        populateDetails(MATCH_ID);
        return view;
    }

    public void populateDetails(long matchid) {

        // Create textviews
        tvfName = (TextView) getActivity().findViewById(R.id.tvfName);
        tvfTriesA = (TextView) getActivity().findViewById(R.id.tvfTriesA);
        tvfTriesB = (TextView) getActivity().findViewById(R.id.tvfTriesB);
        tvfName.setText(Long.toString(MATCH_ID));

        // Populate textviews
        DBSportScout db = new DBSportScout(getActivity());
        db.open();
        String selectionmatchid = Long.toString(matchid);
        String[] columns = { DBSportScout.MatchMetaData.KEY_MNAME,
                DBSportScout.MatchMetaData.KEY_MDATE,
                DBSportScout.MatchMetaData.KEY_MSTATUS,
                DBSportScout.MatchMetaData.KEY_MSUMMARY,
                DBSportScout.MatchMetaData.KEY_MTEAM_A_ID,
                DBSportScout.MatchMetaData.KEY_MTEAM_B_ID,
                DBSportScout.MatchMetaData.KEY_MCHAMP_ID,
                DBSportScout.MatchMetaData.KEY_MTURN,
                DBSportScout.MatchMetaData.KEY_MSPORT_ID,
                DBSportScout.MatchMetaData.KEY_MSCORE_A,
                DBSportScout.MatchMetaData.KEY_MSCORE_B,
                DBSportScout.MatchMetaData.KEY_MSTAT1_A,
                DBSportScout.MatchMetaData.KEY_MSTAT1_B,
                DBSportScout.MatchMetaData.KEY_MSTAT2_A,
                DBSportScout.MatchMetaData.KEY_MSTAT2_B,
                DBSportScout.MatchMetaData.KEY_MSTAT3_A,
                DBSportScout.MatchMetaData.KEY_MSTAT3_B,
                DBSportScout.MatchMetaData.KEY_MSTAT4_A,
                DBSportScout.MatchMetaData.KEY_MSTAT4_B,
                DBSportScout.MatchMetaData.KEY_MSTAT5_A,
                DBSportScout.MatchMetaData.KEY_MSTAT5_B,
                DBSportScout.MatchMetaData.KEY_MSTAT6_A,
                DBSportScout.MatchMetaData.KEY_MSTAT6_B,
                DBSportScout.MatchMetaData.KEY_MSTAT7_A,
                DBSportScout.MatchMetaData.KEY_MSTAT7_B,
                DBSportScout.MatchMetaData.KEY_MSTAT8_A,
                DBSportScout.MatchMetaData.KEY_MSTAT8_B,
                DBSportScout.MatchMetaData.KEY_MSTAT9_A,
                DBSportScout.MatchMetaData.KEY_MSTAT9_B,
                DBSportScout.MatchMetaData.KEY_MSTAT10_A,
                DBSportScout.MatchMetaData.KEY_MSTAT10_B,
                DBSportScout.MatchMetaData.KEY_MSTAT11_A,
                DBSportScout.MatchMetaData.KEY_MSTAT11_B,
                DBSportScout.MatchMetaData.KEY_MSTAT12_A,
                DBSportScout.MatchMetaData.KEY_MSTAT12_B,
                DBSportScout.MatchMetaData.KEY_MSTAT13_A,
                DBSportScout.MatchMetaData.KEY_MSTAT13_B,
                DBSportScout.MatchMetaData.KEY_MSTAT14_A,
                DBSportScout.MatchMetaData.KEY_MSTAT14_B,
                DBSportScout.MatchMetaData.KEY_MSTAT15_A,
                DBSportScout.MatchMetaData.KEY_MSTAT15_B,
                DBSportScout.MatchMetaData.KEY_MSTAT16_A,
                DBSportScout.MatchMetaData.KEY_MSTAT16_B,
                DBSportScout.MatchMetaData.KEY_MSTAT17_A,
                DBSportScout.MatchMetaData.KEY_MSTAT17_B,
                DBSportScout.MatchMetaData.KEY_MSTAT18_A,
                DBSportScout.MatchMetaData.KEY_MSTAT18_B,
                DBSportScout.MatchMetaData.KEY_MSTAT19_A,
                DBSportScout.MatchMetaData.KEY_MSTAT19_B,
                DBSportScout.MatchMetaData.KEY_MSTAT20_A,
                DBSportScout.MatchMetaData.KEY_MSTAT20_B,
                DBSportScout.MatchMetaData.KEY_MSTAT21_A,
                DBSportScout.MatchMetaData.KEY_MSTAT21_B,
                DBSportScout.MatchMetaData.KEY_MSTAT22_A,
                DBSportScout.MatchMetaData.KEY_MSTAT22_B,
                DBSportScout.MatchMetaData.KEY_MSTAT23_A,
                DBSportScout.MatchMetaData.KEY_MSTAT23_B,
                DBSportScout.MatchMetaData.KEY_MSTAT24_A,
                DBSportScout.MatchMetaData.KEY_MSTAT24_B,
                DBSportScout.MatchMetaData.KEY_MSTAT25_A,
                DBSportScout.MatchMetaData.KEY_MSTAT25_B,
                DBSportScout.MatchMetaData.KEY_MSTAT26_A,
                DBSportScout.MatchMetaData.KEY_MSTAT26_B,
                DBSportScout.MatchMetaData.KEY_MSTAT27_A,
                DBSportScout.MatchMetaData.KEY_MSTAT27_B,
                DBSportScout.MatchMetaData.KEY_MSTAT28_A,
                DBSportScout.MatchMetaData.KEY_MSTAT28_B,
                DBSportScout.MatchMetaData.KEY_MSTAT29_A,
                DBSportScout.MatchMetaData.KEY_MSTAT29_B,
                DBSportScout.MatchMetaData.KEY_MSTAT30_A,
                DBSportScout.MatchMetaData.KEY_MSTAT30_B,
                DBSportScout.MatchMetaData.KEY_MSTAT31_A,
                DBSportScout.MatchMetaData.KEY_MSTAT31_B,
                DBSportScout.MatchMetaData.KEY_MSTAT32_A,
                DBSportScout.MatchMetaData.KEY_MSTAT32_B,
                DBSportScout.MatchMetaData.KEY_MSTAT33_A,
                DBSportScout.MatchMetaData.KEY_MSTAT33_B,
                DBSportScout.MatchMetaData.KEY_MSTAT34_A,
                DBSportScout.MatchMetaData.KEY_MSTAT34_B,
                DBSportScout.MatchMetaData.KEY_MSTAT35_A,
                DBSportScout.MatchMetaData.KEY_MSTAT35_B,
                DBSportScout.MatchMetaData.KEY_MSTAT36_A,
                DBSportScout.MatchMetaData.KEY_MSTAT36_B,
                DBSportScout.MatchMetaData.KEY_MSTAT37_A,
                DBSportScout.MatchMetaData.KEY_MSTAT37_B,
                DBSportScout.MatchMetaData.KEY_MSTAT38_A,
                DBSportScout.MatchMetaData.KEY_MSTAT38_B,
                DBSportScout.MatchMetaData.KEY_MSTAT39_A,
                DBSportScout.MatchMetaData.KEY_MSTAT39_B,
                DBSportScout.MatchMetaData.KEY_MSTAT40_A,
                DBSportScout.MatchMetaData.KEY_MSTAT40_B };
        String[] selectionArgs = { selectionmatchid };

        Cursor c = db.fetch(DBSportScout.MatchMetaData.DATABASE_TABLE_MATCH,
                columns, DBSportScout.MatchMetaData.KEY_MROWID + "=?",
                selectionArgs, null, null, null, null);
        c.moveToFirst();

        tvfName.setText(c.getInt(c.getColumnIndexOrThrow(DBSportScout.MatchMetaData.KEY_MNAME)));
        tvfTriesA.setText(c.getInt(c.getColumnIndexOrThrow(DBSportScout.MatchMetaData.KEY_MSTAT1_A)));
        tvfTriesB.setText(c.getInt(c.getColumnIndexOrThrow(DBSportScout.MatchMetaData.KEY_MSTAT1_B)));
        db.close();
    }
}

fetch() method from DBSportScout

public Cursor fetch(String table, String[] columns, String selection,
        String[] args, String groupby, String having, String orderby,
        String limit) { // metodo per fare la query di tutti i dati
    Cursor cursor = mDb.query(table, columns, selection, args, groupby,
            having, orderby, limit);
    if (cursor != null) {
        cursor.moveToFirst();
    }
    return cursor;
}

Finally here is the LogCat

FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.gmail.david.corsalini.sportscout/com.gmail.david.corsalini.sportscout.MatchesRugbyPage}: java.lang.NullPointerException
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
    at android.app.ActivityThread.access$600(ActivityThread.java:123)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4424)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
    at com.gmail.david.corsalini.sportscout.MatchDetailsFragment.populateDetails(MatchDetailsFragment.java:77)
    at com.gmail.david.corsalini.sportscout.MatchDetailsFragment.onCreateView(MatchDetailsFragment.java:64)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:870)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1080)
    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:622)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1416)
    at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:505)
    at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1133)
    at android.app.Activity.performStart(Activity.java:4475)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1929)
    ... 11 more
هل كانت مفيدة؟

المحلول

I've never used a bundle unless I was starting a new activity. What I usually do (and I'm not claiming it's the best way, but it works for me), is to define a public static variable to hold the row id, and then use that.

An example (just the relevant bits).

Fragment 1 (Member List):

public static Long mRowId;

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    mRowId = id;
    MemberDisplayFragment memberdisplay = new MemberDisplayFragment();
    getFragmentManager().beginTransaction().replace(R.id.rightpane, memberdisplay).commit();
}

Fragment 2 (Member Detail Display):

Cursor memberdisplay = mDbHelper.fetchMember(MemberListFragment.mRowId);
getActivity().startManagingCursor(memberdisplay);
memberdisplay.moveToFirst();

Hope this helps!

نصائح أخرى

When you make the query, you don't ask for the _ID column in the projection

String[] selection= {DBSportScout.MatchMetaData.KEY_MNAME, DBSportScout.MatchMetaData.KEY_MROWID };

So it will always be zero, I think maybe you need to override your adapter to return your id of choice, or add an _id column to your table.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top