java.lang.IllegalStateException:创建自定义适配器时,系统服务在 onCreate() 之前对活动不可用

Posted

技术标签:

【中文标题】java.lang.IllegalStateException:创建自定义适配器时,系统服务在 onCreate() 之前对活动不可用【英文标题】:java.lang.IllegalStateException: System services not available to Activities before onCreate() when creating custom-adapter 【发布时间】:2021-12-21 20:22:17 【问题描述】:

我收到一条错误消息:

java.lang.IllegalStateException:系统服务在 onCreate() 之前对活动不可用

虽然我做的每一个动作都是在onCreate()之后。

我有一个自定义适配器,它有 4 个按钮。单击其中一个按钮时,它最终会调用updateList() 函数,该函数应该使用新的详细信息更新列表。

代码如下: MainActivity.java

public class MainActivity extends Activity 
    static int accountsCount = 0;
    static FileWorker fileWorker;

    static File directory;
    ListView ledgerListView;
    TextView noAccountsTextView;
    TextView accountHierarchy;
    EditText accountName;
    EditText accountLimit;

    AlertDialog.Builder accountDialogBuilderChild;
    AlertDialog accountDialogChild;

    static ArrayList<AccountsView> ledgerList;

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

        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        boolean introDone = preferences.getBoolean("intro_done", false);
        boolean howToDone = preferences.getBoolean("howto_done", false);
        boolean prefFilesCreated = preferences.getBoolean("files_created", false);

       if(!introDone || !howToDone) 
            Intent introActivity = new Intent(this, IntroActivity.class);
            startActivity(introActivity);
        

        noAccountsTextView = findViewById(R.id.noAccountsTextView);
        ledgerListView = findViewById(R.id.mainListView);

        fileWorker = new FileWorker();
        directory = getFilesDir();

        if(!prefFilesCreated) 
            boolean filesCreated = fileWorker.createFiles(directory);
            if(filesCreated) 
                SharedPreferences.Editor prefEditor = preferences.edit();
                prefEditor.putBoolean("files_created", true);
                prefEditor.apply();
            
        
        accountsCount = fileWorker.countAccounts(directory);
        setMainActivityView();
    

    public void addChildAccountDialog(Context context, int pos) 
        String hierarchy = ledgerList.get(pos).getAccountName();
        String renewalType = ledgerList.get(pos).getRenewalType();
        accountDialogBuilderChild = new AlertDialog.Builder(context);
        accountDialogBuilderChild.setTitle(R.string.add_child_account_dialog_title);
        accountDialogBuilderChild.setPositiveButton("Ok",
                (dialogInterface, i) -> addChildAccount(hierarchy, renewalType));
        accountDialogBuilderChild.setNegativeButton("Cancel",
                (dialogInterface, i) -> dialogInterface.cancel());
        accountDialogBuilderChild.setView(R.layout.dialog_add_child_account);
        accountDialogChild = accountDialogBuilderChild.create();
        accountDialogChild.show();

        accountHierarchy = accountDialogChild.findViewById(R.id.accountHierarchyValueTV);
        accountHierarchy.setText(hierarchy);
        accountName = accountDialogChild.findViewById(R.id.accountNameDialogET);
        accountLimit = accountDialogChild.findViewById(R.id.accountLimitDialogET);
    

    private void addChildAccount(String hierarchy, String renewalType) 
        String accName = hierarchy.concat(formatAccountName(accountName
                .getText().toString()));
        double accLimit = Double.parseDouble(accountLimit.getText().toString());
        fileWorker.addChildAccount(directory,
                accName,
                renewalType,
                accLimit);
        setMainActivityView();
    

    private void setMainActivityView() 
        accountsCount = fileWorker.countAccounts(directory);
        if(accountsCount <= 0) 
            ledgerListView.setVisibility(View.GONE);
            noAccountsTextView.setVisibility(View.VISIBLE);
         else 
            updateList();
            ledgerListView.setVisibility(View.VISIBLE);
            noAccountsTextView.setVisibility(View.GONE);
        
    

    public void updateList() 
        fileWorker.sortAccounts(directory);
        ledgerList = fileWorker.getAccountsList(directory);
        AccountsViewAdapter ledgerAdapter = new
                AccountsViewAdapter(this, ledgerList);
        ledgerListView.setAdapter(ledgerAdapter);
    

    public String formatAccountName(String accName) 
        accName = accName.trim().toLowerCase();
        accName = accName.replace(' ', '_');
        accName = accName.replace('/', '_');
        if(accName.charAt(0) != '/') 
            accName = "/".concat(accName);
        
        return accName;
    

    public void onBackPressed() 
        new AlertDialog.Builder(this)
                .setTitle("Exit")
                .setMessage("Are you sure?")
                .setPositiveButton("Yes", (dialog, which) -> this.finishAffinity())
                .setNegativeButton("No", null)
                .show();
    

这里是cutomAdapter代码:

public class AccountsViewAdapter extends ArrayAdapter<AccountsView> 

    TextView accountName;
    TextView renewalType;
    TextView limitValue;
    TextView balanceValue;

    Button buttonAddAccount;
    Button buttonEditAccount;
    Button buttonIncreaseBalance;
    Button buttonDecreaseBalance;

    MainActivity mainActivity;

    public AccountsViewAdapter(Context context, ArrayList<AccountsView> arrayList) 
        super(context, 0, arrayList);
    

    public View getView(int position, View convertView, ViewGroup parent) 
        View currentItemView  = convertView;

        if(currentItemView == null) 
            currentItemView = LayoutInflater.from(getContext())
                    .inflate(R.layout.listview_row, parent, false);
        

        AccountsView currentAccount = getItem(position);

        assert currentAccount != null;

        accountName = currentItemView.findViewById(R.id.accountNameValueTextView);
        renewalType = currentItemView.findViewById(R.id.textViewRenewalTypeValue);
        limitValue = currentItemView.findViewById(R.id.limitValueTextView);
        balanceValue = currentItemView.findViewById(R.id.balanceValueTextView);

        buttonAddAccount = currentItemView.findViewById(R.id.addAccountButton);
        buttonEditAccount = currentItemView.findViewById(R.id.editAccountButton);
        buttonIncreaseBalance = currentItemView.findViewById(R.id.increaseBalanceButton);
        buttonDecreaseBalance = currentItemView.findViewById(R.id.decreaseBalanceButton);

        accountName.setText(currentAccount.getAccountName());
        renewalType.setText(currentAccount.getRenewalType());
        limitValue.setText(currentAccount.getAmountLimit());
        balanceValue.setText(currentAccount.getBalanceValue());

        mainActivity = new MainActivity();

        buttonAddAccount.setOnClickListener(v -> 
            mainActivity.addChildAccountDialog(buttonAddAccount.getContext(), position);
        );
        return currentItemView;
    

据我了解,当我单击“buttonAddAccount”按钮时会发生错误。我尝试用 MainActivity.this 替换 MainActivity 中的上下文,但这没有帮助。

这是错误日志:

E/androidRuntime: FATAL EXCEPTION: main
    Process: org.biotstoiq.seshat, PID: 18232
    java.lang.IllegalStateException: System services not available to Activities before onCreate()
        at android.app.Activity.getSystemService(Activity.java:6715)
        at android.view.LayoutInflater.from(LayoutInflater.java:299)
        at android.widget.ArrayAdapter.<init>(ArrayAdapter.java:216)
        at android.widget.ArrayAdapter.<init>(ArrayAdapter.java:210)
        at android.widget.ArrayAdapter.<init>(ArrayAdapter.java:196)
        at org.biotstoiq.seshat.AccountsViewAdapter.<init>(AccountsViewAdapter.java:28)
        at org.biotstoiq.seshat.MainActivity.updateList(MainActivity.java:179)
        at org.biotstoiq.seshat.MainActivity.setMainActivityView(MainActivity.java:170)
        at org.biotstoiq.seshat.MainActivity.addChildAccount(MainActivity.java:161)
        at org.biotstoiq.seshat.MainActivity.lambda$addChildAccountDialog$2$org-biotstoiq-seshat-MainActivity(MainActivity.java:140)
        at org.biotstoiq.seshat.MainActivity$$ExternalSyntheticLambda2.onClick(Unknown Source:6)
        at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:201)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:230)
        at android.app.ActivityThread.main(ActivityThread.java:7875)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:526)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)
I/Process: Sending signal. PID: 18232 SIG: 9

fileWorker 代码不在此处,因为我认为此处不需要它。

【问题讨论】:

这个答案可能会对您有所帮助***.com/a/32133034/17333641 @MuhammadRiaz 我试过这个。不起作用。谢谢你试图帮助我。 【参考方案1】:

    永远不要使用new ActivityClass 实例化 Activity。这没有正确初始化它。只有 Android 框架可以正确初始化 Activity,而您可以通过 Intent 来完成。

    即使你可以像这样初始化一个 Activity,那也是错误的。您不想在新实例上调用该函数,而是想在正在运行的实例上调用它。

    无论如何,您不应该有任何视图或适配器类需要特定的 Activity。您应该使用将处理程序传递给适配器的接口。这种方法更容易测试,也更容易正确。即使您的代码有效,也几乎不可能进行单元测试。

【讨论】:

以上是关于java.lang.IllegalStateException:创建自定义适配器时,系统服务在 onCreate() 之前对活动不可用的主要内容,如果未能解决你的问题,请参考以下文章