执行doInBackground()LoaderManager.LoaderCallbacks

时间:2019-05-09 15:44:33

标签: java android

我正在学习Udacity Android数据存储课程,但是我只是碰壁。我们正在制作一个宠物应用程序,用户可以在其中添加,更新和删除宠物。在一个片段中,我们不得不使用一个浮动按钮来转到另一个活动(从Catalog Activity到Edit Activity)。但是当我单击浮动按钮时,出现错误:

  

执行doInBackground()

时发生错误

我没有使用AsyncTask doInBackground()方法,但是我知道我的Loader使用的是AsyncTask类。我还认为问题可能是我试图在doInBackground()上显示某些内容。据我所知,我无法在后台线程上执行任何GUI工作。但是,我没有直接使用doInBackground()方法,那么如何更改未使用的内容?

我尝试使用Google搜索,尝试在android开发人员上查看任何内容,尝试在SO上找到一些帖子,但是我没有找到我知道如何应用的解决方案。

我的目录活动

public class CatalogActivity extends AppCompatActivity implements 
    LoaderManager.LoaderCallbacks<Cursor> {

    Uri newUri;
    /**
     * Identifier for the pet data loader
     */
    private static final int PET_LOADER = 0;
    PetCursorAdapter mCursorAdapter;

    /**
     * Database helper that will provide us access to the database
     */

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

        // Setup FAB to open EditorActivity
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(CatalogActivity.this, EditorActivity.class);
                startActivity(intent);

            }
        });
        // Find the ListView which will be populated with the pet data
        ListView petListView = (ListView) findViewById(R.id.list);


        // Find and set empty view on the ListView, so that it only shows when the list has 0 items.
        View emptyView = findViewById(R.id.empty_view);
        petListView.setEmptyView(emptyView);
        // Setup an Adapter to create a list item for each row of pet data in the Cursor.
        mCursorAdapter = new PetCursorAdapter(this, null);
        // Attach the adapter to the ListView.
        petListView.setAdapter(mCursorAdapter);
        // Prepare the loader.  Either re-connect with an existing one,
        // or start a new one.
        petListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Intent intent = new Intent(CatalogActivity.this, EditorActivity.class);
                Uri curentUri = ContentUris.withAppendedId(PetContract.Pets.CONTENT_URI, id);
                intent.setData(curentUri);
                startActivity(intent);

            }
        });
        getSupportLoaderManager().initLoader(PET_LOADER, null, this);
    }


    private void insertPet() {

        ContentValues contentValues = new ContentValues();
        contentValues.put(PetContract.Pets.COLUMN_NAME, "Toto");
        contentValues.put(PetContract.Pets.COLUMN_BREED, "Terrier");
        contentValues.put(PetContract.Pets.COLUMN_GENDER, PetContract.Pets.GENDER_MALE);
        contentValues.put(PetContract.Pets.COLUMN_WEIGHT, 7);
        newUri = getApplication().getContentResolver().insert(
                PetContract.Pets.CONTENT_URI,
                contentValues
        );
        // Show a toast message depending on whether or not the insertion was successful
        if (newUri == null) {
            // If the row ID is -1, then there was an error with insertion.
            Toast.makeText(this, "Error with saving pet", Toast.LENGTH_SHORT).show();
        } else {
            // Otherwise, the insertion was successful and we can display a toast with the row ID.
            Toast.makeText(this, "Pet saved with row id: ", Toast.LENGTH_SHORT).show();
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu options from the res/menu/menu_catalog.xml file.
        // This adds menu items to the app bar.
        getMenuInflater().inflate(R.menu.menu_catalog, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // User clicked on a menu option in the app bar overflow menu
        switch (item.getItemId()) {
            // Respond to a click on the "Insert dummy data" menu option
            case R.id.action_insert_dummy_data:
                insertPet();

                return true;
            // Respond to a click on the "Delete all entries" menu option
            case R.id.action_delete_all_entries:
                // Do nothing for now
                return true;
        }
        return super.onOptionsItemSelected(item);
    }


    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {


        //ovde su navedene kolone koje zelim da prikazem
        String[] projection = {
                PetContract.Pets._ID,
                PetContract.Pets.COLUMN_NAME,
                PetContract.Pets.COLUMN_BREED,
        };


        return new CursorLoader(
                this,
                PetContract.Pets.CONTENT_URI,
                projection,
                null,
                null,
                null);
    }
    // This is the Adapter being used to display the list's data.

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // Swap the new cursor in.  (The framework will take care of closing the
        // old cursor once we return.)
        mCursorAdapter.swapCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // This is called when the last Cursor provided to onLoadFinished()
        // above is about to be closed.  We need to make sure we are no
        // longer using it.
        mCursorAdapter.swapCursor(null);
    }
}

我的编辑器活动:

public class EditorActivity extends AppCompatActivity implements 
    LoaderManager.LoaderCallbacks<Cursor> {
    private Uri mCurrentPetUri;
    private static final int PET_LOADER = 0;

    public PetHelper mDbHelper;
    /**
     * EditText field to enter the pet's name
     */
    private EditText mNameEditText;

    /**
     * EditText field to enter the pet's breed
     */
    private EditText mBreedEditText;

    /**
     * EditText field to enter the pet's weight
     */
    private EditText mWeightEditText;

    /**
     * EditText field to enter the pet's gender
     */
    private Spinner mGenderSpinner;

    /**
     * Gender of the pet. The possible values are:
     * 0 for unknown gender, 1 for male, 2 for female.
     */
    private int mGender = 0;

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

        Intent intent = getIntent();
        mCurrentPetUri = intent.getData();

        if (mCurrentPetUri == null) {
            setTitle(getResources().getText(R.string.add_pet_title));
        } else setTitle(getResources().getText(R.string.edit_pet_title));


        // Find all relevant views that we will need to read user input from
        mNameEditText = (EditText) findViewById(R.id.edit_pet_name);
        mBreedEditText = (EditText) findViewById(R.id.edit_pet_breed);
        mWeightEditText = (EditText) findViewById(R.id.edit_pet_weight);
        mGenderSpinner = (Spinner) findViewById(R.id.spinner_gender);
        getSupportLoaderManager().initLoader(PET_LOADER, null, this);
        setupSpinner();

    }


    private void savetPet() {

        String insertName = mNameEditText.getText().toString().trim();
        String insertBreed = mBreedEditText.getText().toString().trim();
        String insertWeiightAsIteger = mWeightEditText.getText().toString().toString();
        int insertWeight = Integer.parseInt(insertWeiightAsIteger);


        mDbHelper = new PetHelper(this);


        ContentValues contentValues = new ContentValues();
        contentValues.put(PetContract.Pets.COLUMN_NAME, insertName);
        contentValues.put(PetContract.Pets.COLUMN_BREED, insertBreed);
        contentValues.put(PetContract.Pets.COLUMN_GENDER, mGender);
        contentValues.put(PetContract.Pets.COLUMN_WEIGHT, insertWeight);


        if (mCurrentPetUri == null) {
            Uri newUri = getApplication().getContentResolver().insert(
                    PetContract.Pets.CONTENT_URI,
                    contentValues);
            // Show a toast message depending on whether or not the insertion was successful
            if (newUri == null) {
                // If the row ID is -1, then there was an error with insertion.
                Toast.makeText(this, "Error with saving pet", Toast.LENGTH_SHORT).show();
            } else {
                // Otherwise, the insertion was successful and we can display a toast with the row ID.
                Toast.makeText(this, "Pet saved with row id: " + mCurrentPetUri, Toast.LENGTH_SHORT).show();
            }
        } else { // Otherwise this is an EXISTING pet, so update the pet with content URI: mCurrentPetUri
            // and pass in the new ContentValues. Pass in null for the selection and selection args
            // because mCurrentPetUri will already identify the correct row in the database that
            // we want to modify.
            int rowsAffected = getContentResolver().update(mCurrentPetUri, contentValues, null, null);

            // Show a toast message depending on whether or not the update was successful.
            if (rowsAffected == 0) {
                // If no rows were affected, then there was an error with the update.
                Toast.makeText(this, getString(R.string.editor_update_pet_failed),
                        Toast.LENGTH_SHORT).show();
            } else {
                // Otherwise, the update was successful and we can display a toast.
                Toast.makeText(this, getString(R.string.editor_update_pet_successful),
                        Toast.LENGTH_SHORT).show();
            }
        }


    }

    /**
     * Setup the dropdown spinner that allows the user to select the gender of the pet.
     */
    private void setupSpinner() {
        // Create adapter for spinner. The list options are from the String array it will use
        // the spinner will use the default layout
        ArrayAdapter genderSpinnerAdapter = ArrayAdapter.createFromResource(this,
                R.array.array_gender_options, android.R.layout.simple_spinner_item);

        // Specify dropdown layout style - simple list view with 1 item per line
        genderSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);

        // Apply the adapter to the spinner
        mGenderSpinner.setAdapter(genderSpinnerAdapter);

        // Set the integer mSelected to the constant values
        mGenderSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                String selection = (String) parent.getItemAtPosition(position);
                if (!TextUtils.isEmpty(selection)) {
                    if (selection.equals(getString(R.string.gender_male))) {
                        mGender = PetContract.Pets.GENDER_MALE; // Male
                    } else if (selection.equals(getString(R.string.gender_female))) {
                        mGender = PetContract.Pets.GENDER_FEMALE; // Female
                    } else {
                        mGender = PetContract.Pets.GENDER_UNKOWN; // Unknown
                    }
                }
            }

            // Because AdapterView is an abstract class, onNothingSelected must be defined
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                mGender = 0; // Unknown
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu options from the res/menu/menu_editor.xml file.
        // This adds menu items to the app bar.
        getMenuInflater().inflate(R.menu.menu_editor, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // User clicked on a menu option in the app bar overflow menu
        switch (item.getItemId()) {
            // Respond to a click on the "Save" menu option
            case R.id.action_save:
                // Save new pet
                savetPet();
                finish();
                return true;
            // Respond to a click on the "Delete" menu option
            case R.id.action_delete:
                // Do nothing for now
                return true;
            // Respond to a click on the "Up" arrow button in the app bar
            case android.R.id.home:
                // Navigate back to parent activity (CatalogActivity)
                NavUtils.navigateUpFromSameTask(this);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }


    @Override
    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
        // Since the editor shows all pet attributes, define a projection that contains
        // all columns from the pet table
        String[] projection = {
                PetContract.Pets._ID,
                PetContract.Pets.COLUMN_NAME,
                PetContract.Pets.COLUMN_BREED,
                PetContract.Pets.COLUMN_GENDER,
                PetContract.Pets.COLUMN_WEIGHT};

        // This loader will execute the ContentProvider's query method on a background thread
        return new CursorLoader(this,   // Parent activity context
                mCurrentPetUri,         // Query the content URI for the current pet
                projection,             // Columns to include in the resulting Cursor
                null,                   // No selection clause
                null,                   // No selection arguments
                null);                  // Default sort order
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        // Bail early if the cursor is null or there is less than 1 row in the cursor
        if (cursor == null || cursor.getCount() < 1) {
            return;
        }

        // Proceed with moving to the first row of the cursor and reading data from it
        // (This should be the only row in the cursor)
        if (cursor.moveToFirst()) {
            // Find the columns of pet attributes that we're interested in
            int nameColumnIndex = cursor.getColumnIndex(PetContract.Pets.COLUMN_NAME);
            int breedColumnIndex = cursor.getColumnIndex(PetContract.Pets.COLUMN_BREED);
            int genderColumnIndex = cursor.getColumnIndex(PetContract.Pets.COLUMN_GENDER);
            int weightColumnIndex = cursor.getColumnIndex(PetContract.Pets.COLUMN_WEIGHT);

            // Extract out the value from the Cursor for the given column index
            String name = cursor.getString(nameColumnIndex);
            String breed = cursor.getString(breedColumnIndex);
            int gender = cursor.getInt(genderColumnIndex);
            int weight = cursor.getInt(weightColumnIndex);

            // Update the views on the screen with the values from the database
            mNameEditText.setText(name);
            mBreedEditText.setText(breed);
            mWeightEditText.setText(Integer.toString(weight));

            // Gender is a dropdown spinner, so map the constant value from the database
            // into one of the dropdown options (0 is Unknown, 1 is Male, 2 is Female).
            // Then call setSelection() so that option is displayed on screen as the current selection.
            switch (gender) {
                case PetContract.Pets.GENDER_MALE:
                    mGenderSpinner.setSelection(1);
                    break;
                case PetContract.Pets.GENDER_FEMALE:
                    mGenderSpinner.setSelection(2);
                    break;
                default:
                    mGenderSpinner.setSelection(0);
                    break;
            }
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // If the loader is invalidated, clear out all the data from the input fields.
        mNameEditText.setText("");
        mBreedEditText.setText("");
        mWeightEditText.setText("");
        mGenderSpinner.setSelection(0); // Select "Unknown" gender
    }
}

logcat

FATAL EXCEPTION: AsyncTask #2
Process: com.example.android.pets, PID: 31266
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:354)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)


Caused by: java.lang.NullPointerException: uri
at 
com.android.internal.util.Preconditions.checkNotNull(Preconditions.java:128)
at android.content.ContentResolver.query(ContentResolver.java:787)
at android.content.ContentResolver.query(ContentResolver.java:753)
at android.content.CursorLoader.loadInBackground(CursorLoader.java:68)
at android.content.CursorLoader.loadInBackground(CursorLoader.java:45)
at android.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:319)
at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:73)
at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:61)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:764) 

0 个答案:

没有答案