简体   繁体   English

IndexOutOfBoundsException崩溃的android应用

[英]IndexOutOfBoundsException crashing android app

I am clicking an item from a ViewList of the previous activity. 我正在单击上一个活动的ViewList中的项目。 This activity is supposed to take that object and display said object's characteristics. 本活动应采用该对象并显示该对象的特征。 When I click on the viewList the app crashes. 当我单击viewList时,应用程序崩溃。 Here is the logcat: 这是logcat:

04-16 19:37:09.183 22696-22696/cs4326.cook4me E/AndroidRuntime: FATAL EXCEPTION: main
Process: cs4326.cook4me, PID: 22696
java.lang.RuntimeException: Unable to start activity ComponentInfo{cs4326.cook4me/cs4326.cook4me.RecipeInstructActivity}: java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
     at android.app.ActivityThread.-wrap12(ActivityThread.java)
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
     at android.os.Handler.dispatchMessage(Handler.java:102)
     at android.os.Looper.loop(Looper.java:154)
     at android.app.ActivityThread.main(ActivityThread.java:6119)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
        Caused by: java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
     at java.util.ArrayList.add(ArrayList.java:457)
     at cs4326.cook4me.RecipeInstructActivity.onCreate(RecipeInstructActivity.java:45)
     at android.app.Activity.performCreate(Activity.java:6679)
     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) 
     at android.app.ActivityThread.-wrap12(ActivityThread.java) 
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) 
     at android.os.Handler.dispatchMessage(Handler.java:102) 
     at android.os.Looper.loop(Looper.java:154) 
     at android.app.ActivityThread.main(ActivityThread.java:6119) 
     at java.lang.reflect.Method.invoke(Native Method) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 

Here is the corresponding activity code (error says at line 45): 这是相应的活动代码(错误显示在第45行):

package cs4326.cook4me;

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

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;

public class RecipeInstructActivity extends FragmentActivity {

    private static final String TAG = "RecipeInstructActivity";
    /**
     * Identifier for the example fragment.
     */
    public static final int FRAGMENT_COMPLETE = 1;
    public static final int FRAGMENT_STEPPED = 2;

    /**
     * The adapter definition of the fragments.
     */
    private FragmentPagerAdapter _fragmentPagerAdapter;

    /**
     * The ViewPager that hosts the section contents.
     */
    private ViewPager _viewPager;

    /**
     * List of fragments.
     */
    private List<Fragment> _fragments = new ArrayList<>();

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        Log.d(TAG, "onCreate:");
        super.onCreate(savedInstanceState);

        this.setContentView(R.layout.activity_main);

        // Each fragment to our list.
        this._fragments.add(FRAGMENT_COMPLETE, new CompleteInstructionFragment());
        this._fragments.add(FRAGMENT_STEPPED, new SteppedInstructionFragment());

        // Setup the fragments, defining the number of fragments, the screens and titles.
        this._fragmentPagerAdapter = new FragmentPagerAdapter(this.getSupportFragmentManager()){
            @Override
            public int getCount() {
                return RecipeInstructActivity.this._fragments.size();
            }
            @Override
            public Fragment getItem(final int position) {
                return RecipeInstructActivity.this._fragments.get(position);
            }
            @Override
            public CharSequence getPageTitle(final int position) {
                // Define titles for each fragment.
                switch (position) {
                    case FRAGMENT_COMPLETE:
                        return "Complete Recipe";
                    case FRAGMENT_STEPPED:
                        return "Step-by-Step";
                    default:
                        return null;
                }
            }
        };

        this._viewPager = (ViewPager) this.findViewById(R.id.pager);
        this._viewPager.setAdapter(this._fragmentPagerAdapter);

        // Set the default fragment.
        this.openFragment(FRAGMENT_COMPLETE);
    }

    /**
     * Open the specified fragment.
     * @param fragment
     */
    public void openFragment(final int fragment) {
        this._viewPager.setCurrentItem(fragment);
    }

    /**
     * Get the fragment object for the specified fragment.
     * @param fragment
     * @return
     */
    public Fragment getFragment(final int fragment) {
        return this._fragments.get(fragment);
    }
}

Here is the code from the parent viewList activity: 这是父viewList活动的代码:

package cs4326.cook4me;

import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;

import java.util.Comparator;
import java.util.TreeSet;

public class RecipesActivity extends AppCompatActivity implements AdapterView.OnItemClickListener{
    private static final String TAG = "RecipesActivity";
    private DatabaseReference databaseReference;
    private ListView mainListView ;
    private ArrayAdapter<String> listAdapter ;
    private TreeSet<Recipe> allRecipeData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recipes);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        //Initialize reference to database
        databaseReference = FirebaseDatabase.getInstance().getReference();
        //Initialize recipe data set
        allRecipeData = new TreeSet<Recipe>(new Comparator<Recipe>() {
            @Override
            public int compare(Recipe o1, Recipe o2) {
                return o1.getTitle().compareToIgnoreCase(o2.getTitle());
            }
        });
        // Create ArrayAdapter
        listAdapter = new ArrayAdapter<String>(this, R.layout.row_layout);
        //Create query for recipes
        Query recipesReference = databaseReference.child("recipes").orderByChild("title");
        recipesReference.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                // Get Recipe object and use the values to update the UI
                Recipe recipe = dataSnapshot.getValue(Recipe.class);
                listAdapter.add(recipe.getTitle());
                allRecipeData.add(recipe);
                Log.d(TAG, "loadRecipe:onChildAdded");
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String previousName) {
                // Get Recipe object and use the values to update the UI
                Recipe recipe = dataSnapshot.getValue(Recipe.class);
                listAdapter.remove(previousName);
                listAdapter.add(recipe.getTitle());
                Log.d(TAG, "loadRecipe:onChildChanged");
            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
                // Get Recipe object and use the values to update the UI
                Recipe recipe = dataSnapshot.getValue(Recipe.class);
                listAdapter.remove(recipe.getTitle());
                allRecipeData.remove(recipe);
                Log.d(TAG, "loadRecipe:onRemoved");
            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String olden) {
                // Get Recipe object and use the values to update the UI
                Recipe recipe = dataSnapshot.getValue(Recipe.class);
                listAdapter.remove(olden);
                listAdapter.add(recipe.getTitle());
                Log.d(TAG, "loadRecipe:onChildMoved");
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                // Getting Recipe failed, log a message
                Log.w(TAG, "loadRecipe:onCancelled", databaseError.toException());
            }
        });

        // Find the ListView resource.
        mainListView = (ListView) findViewById( R.id.listViewRecipes );
        //Add list items!
        mainListView.setAdapter( listAdapter );

        //TODO: Make it so clicking / tapping on each item redirects to Recipe
        mainListView.setOnItemClickListener(this);


        //Floating login button
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent transfer = new Intent(RecipesActivity.this, LoginActivity.class);
                startActivity(transfer);
            }
        });

        //If you type, it will automatically start searching
        setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
        //Floating search button
        FloatingActionButton floatingSearch = (FloatingActionButton) findViewById(R.id.search_recipes);
        floatingSearch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onSearchRequested();
            }
        });

        //Redirects back to Main Menu if press up button
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    public void onItemClick(AdapterView<?> l, View v, int position, long id) {
        Log.d(TAG, "You clicked " + listAdapter.getItem(position));
        String nameOf = listAdapter.getItem(position);
        Recipe selectedRecipe = new Recipe();
        // Then you start a new Activity via Intent
        Intent specialTransfer = new Intent(RecipesActivity.this, RecipeInstructActivity.class);
        for (Recipe r : allRecipeData) {
            if (r.getTitle().equals(nameOf)) {
                selectedRecipe = r;
            }
        }
        //Pass selected recipe 
        specialTransfer.putExtra("recipe_object", selectedRecipe);
        startActivity(specialTransfer);

    }

}

Here is the AndroidManifest.XML: 这是AndroidManifest.XML:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cs4326.cook4me">

    <uses-permission android:name="android.permission.INTERNET" />

    <!-- To auto-complete the email text field in the login form with the user's emails -->
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.READ_PROFILE" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.Light">
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".LoginActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="cs4326.cook4me.MainActivity" />
        </activity>

        <activity
            android:name=".RegisterActivity"
            android:label="Register User"
            android:parentActivityName=".LoginActivity" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="cs4326.cook4me.LoginActivity" />
        </activity>

        <activity
            android:name=".ProfileActivity"
            android:label="User profile"
            android:parentActivityName=".LoginActivity" />
        <activity
            android:name=".SettingsActivity"
            android:label="@string/title_activity_settings"
            android:parentActivityName=".MainActivity" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="cs4326.cook4me.MainActivity" />
        </activity>
        <!--
        <activity
            android:name=".RecipeFragment"
            android:label="@string/title_activity_recipe_fragment"
            android:theme="@style/AppTheme.NoActionBar" />
        <activity
            android:name=".ProfileFragment"
            android:label="@string/title_activity_profile_fragment"
            android:theme="@style/AppTheme.NoActionBar"></activity>
        -->
        <activity
            android:name=".RecipesActivity"
            android:label="@string/title_activity_recipes"
            android:parentActivityName=".MainActivity"
            android:theme="@style/AppTheme.NoActionBar">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="cs4326.cook4me.MainActivity" />
            <meta-data android:name="android.app.default_searchable"
                android:value=".SearchRecipeActivity" />
        </activity>
        <activity
            android:name=".CookingTerminologyActivity"
            android:label="@string/title_activity_cooking_terminology"
            android:parentActivityName=".MainActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="cs4326.cook4me.MainActivity" />
        </activity>
        <activity
            android:name=".TermActivity"
            android:label="@string/title_activity_term"
            android:parentActivityName=".CookingTerminologyActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="cs4326.cook4me.CookingTerminologyActivity" />
        </activity>

        <activity
            android:name=".SearchRecipeActivity"
            android:label="@string/title_activity_search_recipe"
            android:parentActivityName=".RecipesActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="cs4326.cook4me.RecipesActivity" />
            <intent-filter>
                <action android:name="android.intent.action.SEARCH" />
            </intent-filter>
            <meta-data android:name="android.app.searchable"
                android:resource="@xml/searchable"/>
        </activity>

        <activity
            android:name=".RecipeInstructActivity"
            android:parentActivityName=".RecipesActivity">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="cs4326.cook4me.RecipeInstructActivity" />

        </activity>
    </application>

</manifest>

Problem 1: Static initialisation 问题1:静态初始化

private List<Fragment> _fragments = new ArrayList<>(); //be careful doing this!

Field initialisation doesn't work well in Android Activities and Fragments because their lifecycles are controlled. 字段初始化在Android活动和片段中无法很好地发挥作用,因为它们的生命周期受到控制。 While in this case it's not causing the problem, you can run into trouble if you use findViewById(int id) or other such methods in field initialization. 虽然在这种情况下这不会引起问题,但是如果在字段初始化中使用findViewById(int id)或其他类似方法,则可能会遇到麻烦。 Until the lifecycles of Activities and Fragments are really clear, it may be better just to avoid and to put the code inside the onCreate() or onResume() callbacks as necessary. 在真正确定“活动”和“片段”的生命周期之前,最好避免并根据需要将代码放入onCreate()onResume()回调中。

Problem 2: Rolling our own FragmentManager 问题2:滚动我们自己的FragmentManager

In this code, Fragments are being cached inside a list. 在这段代码中,片段被缓存在列表中。 There is no need for this - it's the job of the FragmentManager to cache fragments. 不需FragmentManager的工作是缓存片段。

Also, the method FragmentPagerAdapter#getItem() should be used for instantiation, not retrieving from a list. 另外,应该使用FragmentPagerAdapter#getItem()方法进行实例化,而不是从列表中检索。 It's not really your fault - I think the method is poorly named. 这不是您的错-我认为该方法的名称不正确。 It really means something more like "createItem()" and it should look something more like this: 实际上,它的意思更像是“ createItem()”,它看起来应该像这样:

    this._fragmentPagerAdapter = new FragmentPagerAdapter(this.getSupportFragmentManager()){
        @Override
        public int getCount() {
            return RecipeInstructActivity.this._fragments.size();
        }
        @Override
        public Fragment getItem(final int position) {
            switch (position) {
                case FRAGMENT_COMPLETE:
                    return new CompleteInstructionFragment();
                case FRAGMENT_STEPPED:
                    return new StepByStepFramgment();
        }

It's best to leave everything to the ViewPager if possible. 如果可能的话,最好将所有内容留给ViewPager。 If you can't and you need to manipulate Fragments yourself, then when you are adding Fragments use the overload that lets you add a tag to the Fragment when you complete a transaction and then when you need a handle on the Fragment you can use findFragmentByTag to retrieve it. 如果不能,则需要自己操作Fragment,那么在添加Fragment时,请使用重载,该重载可让您在完成事务时向Fragment添加标签,然后在需要Fragment的句柄时,可以使用findFragmentByTag检索它。

Thanks to suggestions, I changed directions and went a different route with the initialization and adapter. 多亏了建议,我改变了方向,并通过初始化和适配器走了一条不同的路线。 This is the resulting code that worked for me to create an activity that encompasses a tabbed layout. 这是为我创建的包含选项卡式布局活动的代码。

Main Activity: 主要活动:

package cs4326.cook4me;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.net.Uri;
import android.support.design.widget.TabLayout;
import android.support.v4.app.FragmentManager;


public class RecipeInstructActivity extends AppCompatActivity implements
        CompleteInstructionFragment.OnFragmentInteractionListener,
        SteppedInstructionFragment.OnFragmentInteractionListener {

    private static final String TAG = "RecipesActivity";
    private SectionsPagerAdapter mSectionsPagerAdapter;

    /**
     * The ViewPager that hosts the section contents.
     */
    private ViewPager mViewPager;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        this.setContentView(R.layout.activity_recipe_instruct);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        //setActionBar();
        setSupportActionBar(toolbar);

        // Create the adapter that will return a fragment for each of the three
        // primary sections of the activity.
        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(mViewPager);
    }

    @Override
    public void onFragmentInteraction(Uri uri) {

    }

    /**
     * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
     * one of the sections/tabs/pages.
     */
    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            Fragment fragment = null;
            switch (position) {
                case 0: {
                    fragment = new CompleteInstructionFragment();
                    break;
                }
                case 1: {
                    fragment = new SteppedInstructionFragment();
                    break;
                }
            }

            return fragment;
        }

        @Override
        public int getCount() {
            // Show 2 total pages.
            return 2;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            switch (position) {
                case 0:
                    return "Full Recipe";
                case 1:
                    return "Step-by-Step";
            }
            return null;
        }
    }
}

Fragment #1: 片段1:

package cs4326.cook4me;

import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by nathan1324 on 4/16/17.
 */

public class CompleteInstructionFragment extends Fragment {

    private OnFragmentInteractionListener mListener;

    public CompleteInstructionFragment() {
        // required empty constructor
    }

    //Recipe robj= getIntent().getParcelableExtra("recipe_object");

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {

        }
    }

    public static CompleteInstructionFragment newInstance() {
        CompleteInstructionFragment fragment = new CompleteInstructionFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {

        // view created from XML layout
        View view = inflater.inflate(R.layout.fragment_completeinstruction, container, false);

//        Create
//                View
//                        Here

        // could add other customization here for loyout components later
        return view;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    public void onButtonPressed(Uri uri) {
        if (mListener != null) {
            mListener.onFragmentInteraction(uri);
        }
    }

    public interface OnFragmentInteractionListener {
        void onFragmentInteraction(Uri uri);
    }

}

Fragment #2: 片段#2:

package cs4326.cook4me;

import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by nathan1324 on 4/16/17.
 */

public class SteppedInstructionFragment extends Fragment {

    private OnFragmentInteractionListener mListener;

    public SteppedInstructionFragment() {
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    public static SteppedInstructionFragment newInstance() {
        SteppedInstructionFragment fragment = new SteppedInstructionFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
        }
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {

        // view created from XML layout
        View view = inflater.inflate(R.layout.fragment_steppedinstruction,container, false);



        // could add other customization here for layout components later


        return view;
    }

    public void onButtonPressed(Uri uri) {
        if (mListener != null) {
            mListener.onFragmentInteraction(uri);
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }


    public interface OnFragmentInteractionListener {
        void onFragmentInteraction(Uri uri);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM