android異常描述 make sure class name exists, is public, and has an empty constructor that is public

異常信息

 Unable to start activity          Unable to instantiate fragment 

原因:

GameDiag 必須被public修飾   必須有默認構造函數   必須是靜態類 總而言之能通過反射創建對象

當app在後臺因內存不足被殺後 在最近任務中打開該app會重建被殺前的頁面  由於是反射創建而這時被創建的組件如果沒有默認構造函數或不是靜態的就會拋該異常

有時候需要把this傳入到Dialog中  可以利用onAttachedToWindow 和 onDetachedFromWindow 把this傳到dialog中 當然也可以使用其他回調  如果只需要傳入一些intent能夠傳遞的數據可以使用setArguments方式

//顯示dialog
public void showGameDialog(){
    mGameDialogFragment = new GameDialogFragment();
                Bundle b = new Bundle();
                b.putString("title", gameRuleTitle);
                b.putString("rule", gameRule);
                mGameDialogFragment.setArguments(b);
                mGameDialogFragment.show(getFragmentManager(),"GameDialogFragment");

}



//Dialog
@Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    String title = getArguments().getString("title");
    String rule = getArguments().getString("rule");
}
//Activity或View
@Override
protected void onAttachedToWindow() {
    if(dialog!=null){
        dialog.attached(this);
    }
super.onAttachedToWindow();
}

@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    if(dialog!=null){
        dialog.detached();
    }
}


public void showGameDialog(){
    GameView.HomeworkingDialog preDialog = dialog;
    dialog = new HomeworkingDialog();
    dialog.attached(this);
    dialog.show(((FragmentActivity) getContext()).getSupportFragmentManager(), "gameDialog");

    if(preDialog!=null){
        preDialog.detached();
    }
}



//Dialog
public void attached(MoveGameView gameView){
    mGameView = gameView;
}

public void detached() {
    mGameView = null;
}

 

源碼分析

首先ActivityThread啓動  收到恢復activity消息  嘗試恢復activity 嘗試恢復fragment  遇到異常恢復失敗

android 應用啓動

//ActivityThread
public static void main(String[] args) {
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        Security.addProvider(new AndroidKeyStoreProvider());

        Process.setArgV0("<pre-initialized>");

        //創建綁定主線程的Looper和MessageQueue對象,用於處理主線程的消息
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        //AsyncTask根主線程綁定
        AsyncTask.init();

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        
        //讓主線程的消息循環工作
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

收到恢復消息恢復activity

//ActivityThread
public void handleMessage(Message msg) {
        if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                ......
            }
        }
        if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));

}

恢復Activity

ActivityThread
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ......
    Activity a = performLaunchActivity(r, customIntent);
    ......
}


private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
            if (localLOGV) Slog.v(
                    TAG, r + ": app=" + app
                    + ", appName=" + app.getPackageName()
                    + ", pkg=" + r.packageInfo.getPackageName()
                    + ", comp=" + r.intent.getComponent().toShortString()
                    + ", dir=" + r.packageInfo.getAppDir());

            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                調用activity的onCreate方法 在這裏拋了異常
                mInstrumentation.callActivityOnCreate(activity, r.state);
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                r.activity = activity;
                r.stopped = true;
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                if (!r.activity.mFinished) {
                    if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                    }
                }
                if (!r.activity.mFinished) {
                    activity.mCalled = false;
                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onPostCreate()");
                    }
                }
            }
            r.paused = true;

            mActivities.put(r.token, r);

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            //拋了咱們看到的的異常
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }

        return activity;
}

activity啓動  嘗試恢復fragment

//FragmentActivity
protected void onCreate(@Nullable Bundle savedInstanceState) {
    ......
    if (savedInstanceState != null) {
        Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
        //恢復狀態時拋異常了
        mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
        ......
    }
    ......
    mFragments.dispatchCreate();
}


//FragmentController
public void restoreAllState(Parcelable state, List<Fragment> nonConfigList) {
    mHost.mFragmentManager.restoreAllState(state, nonConfigList);
}


//FragmentManager
void restoreAllState(Parcelable state, List<Fragment> nonConfig) {
        ......
        for (int i=0; i<fms.mActive.length; i++) {
            FragmentState fs = fms.mActive[i];
            if (fs != null) {
                //創建fragment時拋異常
                Fragment f = fs.instantiate(mHost, mParent);
                if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
                mActive.add(f);
                // Now that the fragment is instantiated (or came from being
                // retained above), clear mInstance in case we end up re-restoring
                // from this FragmentState again.
                fs.mInstance = null;
            }else{
                ......
            }
            
        }
        ......        
}

恢復fragment

//Fragment
public Fragment instantiate(FragmentHostCallback host, Fragment parent) {
        if (mInstance != null) {
            return mInstance;
        }

        final Context context = host.getContext();
        if (mArguments != null) {
            mArguments.setClassLoader(context.getClassLoader());
        }

        mInstance = Fragment.instantiate(context, mClassName, mArguments);
        ......
        return mInstance;
}

//Fragment
public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
        //通過下面代碼發現  fragment必須public 有默認構造方法 且fragment必須是靜態類
        try {
            Class<?> clazz = sClassMap.get(fname);
            if (clazz == null) {
                // Class not found in the cache, see if it's real, and try to add it
                clazz = context.getClassLoader().loadClass(fname);
                sClassMap.put(fname, clazz);
            }
            Fragment f = (Fragment)clazz.newInstance();
            if (args != null) {
                args.setClassLoader(f.getClass().getClassLoader());
                f.mArguments = args;
            }
            return f;
        } catch (ClassNotFoundException e) {
            throw new InstantiationException("Unable to instantiate fragment " + fname
                    + ": make sure class name exists, is public, and has an"
                    + " empty constructor that is public", e);
        } catch (java.lang.InstantiationException e) {
            throw new InstantiationException("Unable to instantiate fragment " + fname
                    + ": make sure class name exists, is public, and has an"
                    + " empty constructor that is public", e);
        } catch (IllegalAccessException e) {
            throw new InstantiationException("Unable to instantiate fragment " + fname
                    + ": make sure class name exists, is public, and has an"
                    + " empty constructor that is public", e);
        }
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章