【问题标题】:Why does my Activity get destroyed on adding a fragment?为什么我的 Activity 在添加片段时会被破坏?
【发布时间】:2016-03-30 21:28:05
【问题描述】:

所以在我的 MainAcivity 中编辑了一个方法后,我得到了一个 RuntimeException。

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tim.timapp
    /com.example.tim.timapp.MainActivity}: java.lang.IllegalStateException: 
    Activity has been destroyed

老实说,我不知道这是从哪里来的。在线搜索表明 ChildFragmentManager 很大,但没有给我一个适合我的修复程序。

知道我可以做些什么来修复这个异常吗?

PS。如果您需要更多代码或信息,请告诉我。我的脑子被这个错误弄得很慌张,所以我可能在这里忽略了一些东西。

完整日志:

03-30 21:19:47.910 24785-24785/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.tim.timapp, PID: 24785
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tim.timapp/com.example.tim.timapp.MainActivity}: java.lang.IllegalStateException: Activity has been destroyed
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
        at android.app.ActivityThread.-wrap11(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5417)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    Caused by: java.lang.IllegalStateException: Activity has been destroyed
        at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1433)
        at android.app.BackStackRecord.commitInternal(BackStackRecord.java:687)
        at android.app.BackStackRecord.commit(BackStackRecord.java:663)
        at com.example.tim.timapp.MainActivity.DrawVariableFragments(MainActivity.java:271)
        at com.example.fragments.Settings.GeneralSettingsFragment.onCreateView(GeneralSettingsFragment.java:57)
        at android.app.Fragment.performCreateView(Fragment.java:2220)
        at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:973)
        at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1148)
        at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1130)
        at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1953)
        at android.app.FragmentController.dispatchActivityCreated(FragmentController.java:152)
        at android.app.Activity.performCreateCommon(Activity.java:6232)
        at android.app.Activity.performCreate(Activity.java:6239)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
        at android.app.ActivityThread.-wrap11(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:148) 
        at android.app.ActivityThread.main(ActivityThread.java:5417) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

MainActivity(对不起,这是一个在制品):

对此很抱歉,但我超出了整个文件的 30.000 个字符的限制。
http://pastebin.com/XZ9k995G

DBHandler(之前让我很伤心,所以可能与它有关):

package com.example.tim.timapp;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;

import java.util.ArrayList;

public class DBHandler extends SQLiteOpenHelper {

    private static String tag = "TEST DBHandler";
    private static DBHandler sInstance;

    // Database Stuff
    private static final int DATABASE_VERSION = 6;
    private static final String DATABASE_NAME = "LinkDatabase.db";

    // Table Stuff
    private static final String TABLE_LinkTable = "LinkTable";
    private static final String TABLE_SettingsTable = "SettingsTable";

    // LinkTable Stuff
    private static final String LT_COLUMN_ID = "_id";
    private static final String LT_COLUMN_NAME = "name";
    private static final String LT_COLUMN_TAG = "tag";

    // SettingsTable Stuff
    private static final String ST_COLUMN_ID = "_id";
    private static final String ST_COLUMN_NAME = "name";
    private static final String ST_COLUMN_IP = "ip";
    private static final String ST_COLUMN_PORT = "port";
    private static final String ST_COLUMN_USERNAME = "username";
    private static final String ST_COLUMN_PASS = "pass";

    // Table Create Statements
    // LinkTable Create Statement
    private static final String CREATE_TABLE_LINKS =
            "CREATE TABLE " + TABLE_LinkTable + "(" +
            LT_COLUMN_ID + " INTEGER PRIMARY KEY, " +
            LT_COLUMN_NAME + " TEXT, " +
            LT_COLUMN_TAG + " TEXT" + ");";

    // SettingsTable Create Statement
    private static final String CREATE_TABLE_SETTINGS =
            "CREATE TABLE " + TABLE_SettingsTable + "(" +
            ST_COLUMN_ID + " INTEGER PRIMARY KEY, " +
            ST_COLUMN_NAME + " TEXT, " +
            ST_COLUMN_IP + " TEXT, " +
            ST_COLUMN_PORT + " TEXT, " +
            ST_COLUMN_USERNAME + " TEXT, " +
            ST_COLUMN_PASS + " TEXT" + ");";

    // TODO: 28-Mar-16 DON"T FORGET TO UPDATE
    // Don't forget to update this when adding a new table.
    private static final ArrayList<String> createTablesArray = new ArrayList<String>() {{add(CREATE_TABLE_LINKS); add(CREATE_TABLE_SETTINGS);}};
    private static final ArrayList<String> tableNamesArray = new ArrayList<String>() {{add(TABLE_LinkTable); add(TABLE_SettingsTable);}};




    public ArrayList<String> tagArray;

    public static synchronized DBHandler getInstance(Context context) {
        if (sInstance == null) {
            Log.d(tag, "sInstance == null");
            sInstance = new DBHandler(context.getApplicationContext());
        }
        return sInstance;
    }

    private DBHandler(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        for (String s : createTablesArray) {
            db.execSQL(s);
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        for (String s : tableNamesArray) {
            db.execSQL("DROP TABLE IF EXISTS " + s);
        }
        onCreate(db);
    }

    public ArrayList<String> returnArray(String base, String column) {
        SQLiteDatabase db;
        db = getWritableDatabase();
        String TABLENAME;
        if (base.equalsIgnoreCase("StuffManager")) {
            TABLENAME = TABLE_LinkTable;
        } else if (base.equalsIgnoreCase("GeneralSettings")) {
            TABLENAME = TABLE_SettingsTable;
        } else {
            Log.e(tag, "String Base not recognised");
            return null;
        }

        String query = "SELECT * FROM " + TABLENAME + " WHERE 1";

        Cursor c = db.rawQuery(query, null);
        c.moveToFirst();

        ArrayList<String> tempArray = new ArrayList<>();

        int i = 0;
        while(!c.isAfterLast()){
            if(c.getString(c.getColumnIndex(column)) != null){
                tempArray.add(i, c.getString(c.getColumnIndex(column)));
            } else {
                Log.e(tag, "String Column not recognised");
                return null;
            }
            c.moveToNext();
            i++;
        }
        c.close();
        if (db != null && db.isOpen()) {
            db.close();
        }
        return tempArray;
    }

    // *** --------- ***
    //
    // All methods for the SETTINGS_TABLES
    //
    // *** --------- ***

    public void addSettings(String name, String ip, String port, String username, String pass) {
        ContentValues values = new ContentValues();
        values.put(ST_COLUMN_NAME, name);
        values.put(ST_COLUMN_IP, ip);
        values.put(ST_COLUMN_PORT, port);
        values.put(ST_COLUMN_USERNAME, username);
        values.put(ST_COLUMN_PASS, pass);
        SQLiteDatabase db;
        db = getWritableDatabase();
        db.insert(TABLE_SettingsTable, null, values);
        db.close();
    }

    public void updateSettings(int id, String name, String ip, String port, String username, String pass) {
        ContentValues values = new ContentValues();
        values.put(ST_COLUMN_NAME, name);
        values.put(ST_COLUMN_IP, ip);
        values.put(ST_COLUMN_PORT, port);
        values.put(ST_COLUMN_USERNAME, username);
        values.put(ST_COLUMN_PASS, pass);
        SQLiteDatabase db;
        db = getWritableDatabase();
        db.update(TABLE_SettingsTable, values, "_id=" + id, null);
        db.close();
    }

    public void deleteSettings(String name) {
        SQLiteDatabase db;
        db = getWritableDatabase();
        db.execSQL("DELETE FROM " + TABLE_SettingsTable + " WHERE " + ST_COLUMN_NAME + "=\"" + name + "\";");
        db.close();
    }

    public void deleteAllSettings() {
        SQLiteDatabase db;
        db = getWritableDatabase();
        db.execSQL("DELETE FROM " + TABLE_SettingsTable + " WHERE 1");
        db.close();
    }

    public float settingsTableSize() {
        SQLiteDatabase db;
        db = getReadableDatabase();
        float  amount = DatabaseUtils.queryNumEntries(db, TABLE_SettingsTable);
        db.close();
        return amount;
    }

    public ArrayList<String> settingsNameArrayMethod() {
        SQLiteDatabase db;
        db = getWritableDatabase();
        String query = "SELECT * FROM " + TABLE_SettingsTable + " WHERE 1";

        Cursor c = db.rawQuery(query, null);
        c.moveToFirst();

        int i = 0;

        ArrayList<String> nameArray = new ArrayList<>();

        while (!c.isAfterLast()) {
            if (c.getString(c.getColumnIndex("name")) != null) {
                nameArray.add(i, c.getString(c.getColumnIndex("name")));
            }
            c.moveToNext();
            i++;
        }
        c.close();
        db.close();
        return nameArray;
    }


    // *** --------- ***
    //
    // All methods for the LINK_TABLES
    //
    // *** --------- ***

    public void addStuffLink(String name, String tag) {
        ContentValues values = new ContentValues();
        values.put(LT_COLUMN_NAME, name);
        values.put(LT_COLUMN_TAG, tag);
        SQLiteDatabase db;
        db = getWritableDatabase();
        db.insert(TABLE_LinkTable, null, values);
        db.close();
    }

    public Bundle updateStuffLink(int id, String name, String tag) {
        ContentValues values = new ContentValues();
        values.put(LT_COLUMN_NAME, name);
        values.put(LT_COLUMN_TAG, tag);
        SQLiteDatabase db;
        db = getWritableDatabase();
        db.update(TABLE_LinkTable, values, "_id=" + id, null);

        db.close();
        ArrayList<String> nameArray = stuffLinksNameArrayMethod();
        ArrayList<String> tagArray = tagArrayMethod();

        Bundle bundle = new Bundle();
        bundle.putStringArrayList("nameArray", nameArray);
        bundle.putStringArrayList("tagArray", tagArray);
        return bundle;
    }

    public void deleteStuffLink(String name) {
        SQLiteDatabase db;
        db = getWritableDatabase();
        db.execSQL("DELETE FROM " + TABLE_LinkTable + " WHERE " + LT_COLUMN_NAME + "=\"" + name + "\";");
        db.close();
    }

    public void deleteAllStuffLinks() {
        SQLiteDatabase db;
        db = getWritableDatabase();
        db.execSQL("DELETE FROM " + TABLE_LinkTable + " WHERE 1");
        db.close();
    }

    public ArrayList<String> stuffLinksNameArrayMethod(){
        SQLiteDatabase db;
        db = getWritableDatabase();
        String query = "SELECT * FROM " + TABLE_LinkTable + " WHERE 1";

        Cursor c = db.rawQuery(query, null);
        c.moveToFirst();

        int i = 0;

        ArrayList<String> nameArray = new ArrayList<>();
        tagArray = new ArrayList<>();

        while(!c.isAfterLast()){
            if(c.getString(c.getColumnIndex("name")) != null){
                nameArray.add(i, c.getString(c.getColumnIndex("name")));
                tagArray.add(i, c.getString(c.getColumnIndex("tag")));
            }
            c.moveToNext();
            i++;
        }
        c.close();
        db.close();
        return nameArray;
    }

    public ArrayList<String> tagArrayMethod() {
        stuffLinksNameArrayMethod();
        return tagArray;
    }

    public float stuffTableSize(){
        SQLiteDatabase db;
        db = getReadableDatabase();
        float  amount = DatabaseUtils.queryNumEntries(db, TABLE_LinkTable);
        db.close();
        return amount;
    }

}

GeneralSettingsFragment

package com.example.fragments.Settings;

import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.example.fragments.MainFragments.DialogFragments.GeneralSettingsInitialInputDialog;
import com.example.fragments.MainFragments.VariableFragments.GeneralSettingsEmptyFragment;
import com.example.fragments.MainFragments.VariableFragments.GeneralSettingsVariableFragment;
import com.example.fragments.MainFragments.VariableFragments.StuffManagerVariableFragment;
import com.example.tim.timapp.DBHandler;
import com.example.tim.timapp.MainActivity;
import com.example.tim.timapp.R;

import java.util.ArrayList;

public class GeneralSettingsFragment extends Fragment {

    DBHandler dbHandler;
    MainActivity ma = new MainActivity();
    private static Menu optionsMenu;
    public static boolean hideDeleteAllButton = false;
    LinearLayout linearLayout;
    View rootView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        setHasOptionsMenu(true);
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_generalsettings, container, false);
        linearLayout = (LinearLayout) rootView.findViewById(R.id.FragmentContainerGeneralSettings);

        if (linearLayout == null) {
            Log.e("GMF", "Layout is null");
        } else if (linearLayout.getChildCount() == 0) {
            GeneralSettingsInitialInputDialog GSIID = new GeneralSettingsInitialInputDialog();
            GSIID.show(getFragmentManager(), "dialog");
            hideDeleteAllButton = true;
        } else {
            hideDeleteAllButton = false;
        }
        ma.DrawVariableFragments("GeneralSettings", "draw");
        return rootView;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.stuffmanager_actionbuttons, menu);
        optionsMenu = menu;
    }

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        optionsMenu.findItem(R.id.removeAllButton).setVisible(!hideDeleteAllButton);
        super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.addButton:
                GeneralSettingsInitialInputDialog GSIID = new GeneralSettingsInitialInputDialog();
                GSIID.show(getFragmentManager(), "dialog");
                return true;
            case R.id.removeAllButton:
                dbHandler = DBHandler.getInstance(getActivity());
                final ArrayList<String> nameArray = dbHandler.settingsNameArrayMethod();
                final FragmentManager fm = getFragmentManager();
                AlertDialog.Builder removeAllDialog = new AlertDialog.Builder(getActivity())
                        .setTitle("Delete all?")
                        .setMessage("Are you sure you want to delete all your devices? This is irreversible.")
                        .setIcon(R.drawable.ic_delete_black)
                        .setPositiveButton("Delete", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dbHandler.deleteAllSettings();
                                for (String name : nameArray){
                                    fm.beginTransaction().remove(fm.findFragmentByTag(name)).commit();
                                }
                                fm.executePendingTransactions();
                                // TODO: 30-Mar-16 Add "No devices created" screen like stuffmanager
                                hideDeleteAllButton = true;
                                getActivity().invalidateOptionsMenu();
                            }
                        })
                        .setNegativeButton("Cancel", null);
                removeAllDialog.show();
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }
}

【问题讨论】:

  • GeneralSettingsFragment.onCreateView() 内部回拨MainActivity.DrawVariableFragments() 看起来很可疑。该片段或任何其他片段是否对 Activity 的状态做任何奇怪的事情,例如在其上调用 finish()?
  • 当您的 Fragments 保留对已销毁活动的旧引用时,往往会发生这种情况。例如,如果您创建 Activity,则创建并附加 Fragment,然后旋转设备。 Activity 被重新创建,但 Fragments 已为您保存,现在具有对旧 Activity 的引用。我想看看你在MainFragment做什么。
  • 请发布 GeneralSettingsFragment.onCreateView()
  • @GeorgeMulligan 据我所知。我只用它来调用DrawVariableFragments() 方法。 @NoChinDeluxe 我注意到其他人也这么说,但我没有旋转或类似的东西。我将更改MainFragment 位以包含整个文件。 @ShadabAnsari 会的。

标签: java android android-fragments android-activity


【解决方案1】:

MainActivity ma = new MainActivity();

这在 Android 中无效。您不能像这样创建 Activity 的实例,因为它实际上并未附加到 Android 进程。 MainActivity 的这个实例不会单步执行任何生命周期方法,这就是为什么您会看到活动已停止的错误。它从未真正开始。

相反,删除对MainActivity 的引用,因为在片段中保留这样的引用是不好的做法。任何时候您需要在片段中使用MainActivity 的实例,请使用以下示例:

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

    // ...

    MainActivity ma = (MainActivity) getActivity();
    ma.DrawVariableFragments("GeneralSettings", "draw");

    // ...

}

【讨论】:

  • 是的,我发现有些人在网上提到了同样的事情,但它一直有效,我也无法快速想出替代方案。我明天会测试一下(当前时间 0:30)。
  • 我试过了,基本可以,但是又出现了新的错误。修复该错误后,返回“活动已被破坏”错误。我已经用更多信息更新了主要问题。
  • 接受了您的回答,因为它确实解决了我遇到的错误。我将就我的新问题提出一个新问题,因为这个答案无法解决。
  • @Timmiej93 抱歉,我没有机会回复您的第二条评论,我忘了!很高兴看到您的其他问题已得到解答。
  • 绝对没问题,我们还有更多工作要做,然后继续关注 SO 对吧? :)
猜你喜欢
  • 2016-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-24
  • 2018-01-06
  • 2017-01-31
  • 2017-12-04
  • 1970-01-01
相关资源
最近更新 更多