gpt4 book ai didi

java - 为什么 onAttach 不能识别正确的 instanceof 上下文?

转载 作者:搜寻专家 更新时间:2023-11-01 09:36:56 25 4
gpt4 key购买 nike

我无法让 Android 设置我的听众。不知何故,上下文不是我期望的那种类型。我不确定我哪里出错了。

下面是 AddEditCharacterFragment.java,它抛出异常,因为上下文不是我期望的类型。

public class AddEditCharacterFragment extends Fragment {

public static final String ARG_PARAM1 = "param1";

private InitiativeTrackerDBHelper mHelper;

private String mParam1;

private Character mCharacter;

public AddEditCharacterFragment() {
// Required empty public constructor
}

/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @return A new instance of fragment AddEditCharacterFragment.
*/
// TODO: Rename and change types and number of parameters
public static AddEditCharacterFragment newInstance() {
AddEditCharacterFragment fragment = new AddEditCharacterFragment();
Bundle args = new Bundle();
//args.putInt(ARG_PARAM1, id);
fragment.setArguments(args);
return fragment;
}

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_add_character, container, false);

mHelper = new InitiativeTrackerDBHelper(getActivity());

mCharacter = mHelper.addCharacter();

EditText characterNameEditText = (EditText) v.findViewById(R.id.character_name_text_edit);
characterNameEditText.setText(mCharacter.getName());
characterNameEditText.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence c, int start, int before, int count) {
mCharacter.setName(c.toString());
}

public void beforeTextChanged(CharSequence c, int start, int before, int after) {
}

public void afterTextChanged(Editable c) {
}
});

EditText modifierPicker =
(EditText) v.findViewById(R.id.modEditText);

modifierPicker.setText(Integer.toString(mCharacter.getModifier()));

modifierPicker.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence c, int start, int before, int count) {
mCharacter.setModifier(Integer.parseInt(c.toString()));
}

public void beforeTextChanged(CharSequence c, int start, int before, int after) {
}

public void afterTextChanged(Editable c) {
}
});

Button saveButton = (Button) v.findViewById(R.id.saveButton);
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mHelper != null)
{
mHelper.updateCharacter(mCharacter);
Toast.makeText(getActivity(), "Update complete!", Toast.LENGTH_LONG).show();
mListener.onCharacterSave();
}

}
});

return v;
}

private OnCharacterSave mListener;

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

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

public interface OnCharacterSave {
public void onCharacterSave();
}
}

AddEditCharacterActivity 是上面 fragment 的 Activity 。
public class AddEditCharacterActivity extends SingleFragmentActivity
implements AddEditCharacterFragment.OnCharacterSave {

@Override
protected Fragment createFragment() {
return AddEditCharacterFragment.newInstance();
}

@Override
public void onCharacterSave() {
FragmentManager fm = getFragmentManager();

// Get the container for the character list
InitiativeListFragment initiativeListFragment = (InitiativeListFragment)
fm.findFragmentById(R.id.fragmentContainer);

// Update the UI
initiativeListFragment.updateInitiativeList();
}
}

InitiativeTrackerActivity 使用 Intent 启动 AddEditCharacterActivity 和随后的 AddEditCharacterFragment。
    public class InitiativeTrackerActivity extends SingleFragmentActivity
implements InitiativeListFragment.OnCharacterListListener, AddEditCharacterFragment.OnCharacterSave {

@Override
protected Fragment createFragment() {
return InitiativeListFragment.newInstance();
}

@Override
public void onAddCharacter() {
Intent intent = new Intent(this, AddEditCharacterActivity.class);
startActivity(intent);
}

@Override
public void onCharacterSave() {
FragmentManager fm = getFragmentManager();

// Get the container for the character list
InitiativeListFragment initiativeListFragment = (InitiativeListFragment)
fm.findFragmentById(R.id.fragmentContainer);

// Update the UI
initiativeListFragment.updateInitiativeList();
}
}

以及 SingleFragmentActivity 的基类供引用:
    public abstract class SingleFragmentActivity extends AppCompatActivity {

protected abstract Fragment createFragment();

protected int getLayoutId() {
return R.layout.activity_single_fragment;
}

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

FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);

if (fragment == null) {
fragment = createFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
}
}

和 InitiativeListFragment.java
package com.example.twistedpurpose.finalproject;

import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.app.Fragment;
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.Button;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link InitiativeListFragment.OnCharacterListListener} interface
* to handle interaction events.
* Use the {@link InitiativeListFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class InitiativeListFragment extends Fragment {

private InitiativeTrackerDBHelper.CharacterCursor mCursor;

private CharacterCursorAdapter adapter;

private OnCharacterListListener mListener;

public InitiativeListFragment() {
// Required empty public constructor
}

/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @return A new instance of fragment InitiativeListFragment.
*/
public static InitiativeListFragment newInstance() {
return new InitiativeListFragment();
}

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_initiative_list, container, false);

//getActivity().deleteDatabase("characters.db");

Context context = getActivity();

// 1. Create a new InitiativeTrackerDBHelper
InitiativeTrackerDBHelper dbHelper = new InitiativeTrackerDBHelper(context);


// 2. Query the characters and obtain a cursor (store in mCursor).
mCursor = dbHelper.queryCharacters();

// Find ListView to populate
ListView characterListView = (ListView) v.findViewById(R.id.character_listView);
// Setup cursor adapter using cursor from last step
adapter = new CharacterCursorAdapter(context, mCursor);
// Attach cursor adapter to the ListView
characterListView.setAdapter(adapter);

Button rollButton = (Button) v.findViewById(R.id.rollBtn);
rollButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
InitiativeTrackerDBHelper dbHelper = new InitiativeTrackerDBHelper(getContext());
List<Character> characterList = dbHelper.getCharacters();

InitiativeRoller.rollInitiative(characterList);

for (Character c : characterList) {
dbHelper.updateCharacter(c);
}

updateInitiativeList();
Toast.makeText(getContext(), "Roll initiative!", Toast.LENGTH_SHORT).show();
}
});

Button addButton = (Button) v.findViewById(R.id.addBtn);
addButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mListener != null) {
mListener.onAddCharacter();
}
}
});

return v;
}

public void updateInitiativeList(){
if(mCursor != null && adapter != null){
mCursor.requery();
adapter.notifyDataSetChanged();
}

}

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

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

/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnCharacterListListener {
public void onAddCharacter();
}

/**
* A character cursor adaptor for adding characters
* to a list
*/
private static class CharacterCursorAdapter extends CursorAdapter {

private InitiativeTrackerDBHelper.CharacterCursor mCharacterCursor;

public CharacterCursorAdapter(Context context, InitiativeTrackerDBHelper.CharacterCursor cursor) {
super(context, cursor, 0);
mCharacterCursor = cursor;
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Use a layout inflater to get a row view
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return inflater.inflate(R.layout.character_listview, parent, false);
}

@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView characterName = (TextView) view.findViewById(R.id.name);
TextView characterMod = (TextView) view.findViewById(R.id.mod);
TextView characterInit = (TextView) view.findViewById(R.id.init);

characterName.setText(mCharacterCursor.getCharacter().getName());
characterMod.setText(Integer.toString(mCharacterCursor.getCharacter().getModifier()));
characterInit.setText(Integer.toString(mCharacterCursor.getCharacter().getTotalInitiative()));
}
}
}

最佳答案

你的问题是你没有在你的 Activity 中实现接口(interface)......
public class AddEditCharacterActivity extends SingleFragmentActivity {
这不是 implement OnCharacterSave .

这就是我之前评论的意思。

更新 :

你误解了 fragment 。
// Get the container for the character list -> 这不是真的。您没有得到“容器”,而是试图获取 fragment 的实际实例。

    InitiativeListFragment initiativeListFragment = (InitiativeListFragment)
fm.findFragmentById(R.id.fragmentContainer);

如果那个 fragment 在那里,那就太好了。

让我用更形象的方式说,这就是你正在做的……(给予或接受)
  • 开始 Activity XXX (SingleFragmentActivity)。
  • 在某个时候,InitiativeListFragmentR.id.fragmentContainer替换为 AddEditCharacterActivity / AddEditCharacterFragment组合。
  • 此时,R.id.fragmentContainer包含 AddEditCharacterFragment 类型的 fragment .
  • 由于您的 Activity 实现了 OnCharacterSave , 到目前为止,一切都很好。
  • 仍然在相同的 Activity/fragment 组合中,您调用 onCharacterSave()这是实现的(见#4),所以一切都很好。
  • 然后你告诉 fragment 管理器给你 R.id.fragmentContainer 中的 fragment 。并且您明确地说(又名:类型转换) fragment 的类型为 InitiativeListFragment ,但是……您的 Activity 应该知道情况并非如此……因为当前 fragment 是 AddEditCharacterFragment .

  • 你应该做的是:
  • 重新阅读 FragmentManager 和 FragmentTransactions。
  • 如果您要将信息传递给当前不可见/启动/附加/等的另一个 fragment 。那么你必须获得一个引用(如果你有的话,通过 TAG)。
  • 然后如果可能的话,可以将它添加到容器中,同时通过 Bundle 传递“数据”。

  • 完全不清楚您要做什么以及顺序是什么,因为您的代码实际上并没有很多关注点分离,因此您可以看到您的 Activity 和 fragment 正在成为充满代码和业务逻辑的单体怪物。有一些解决方案和替代方案(阅读有关 Model-View-Presenter 或类似模式的信息)可以缓解困惑,同时提供更轻松的环境来测试您的代码。

    话虽如此,不管您的代码有多复杂,我相信您需要了解为什么会出现异常,并且我觉得您需要稍微练习一下。

    简而言之……当你这样做时 findFragmentById ,你确实得到了 fragment (如果存在的话),但你不能把它转换成你想要的任何东西。

    旧评论 :
    newInstance()静态方法通常应该存在于 Fragments 中并返回 new YourFragment();
    我的意思是 fragment 创建通常是通过 fragment 中的静态方法完成的。

    说你有
    MyFragment extends Fragment {
    public static MyFragment newInstance() {
    return new MyFragment();
    }

    public MyFragment() {
    // empty constructor is most of the time needed to restore.
    }
    }

    然后从 Activity 中你通常做你正在做的事情,但是 fragment 实例是通过调用 MyFragment.newInstance(); 创建的(这就是谷歌的做法)。

    我建议您也通过标签添加您的 fragment (它更快)。所以你也是
    final Fragment existing = getSupportFragmentManager().findFragmentByTag(tag);

    if (existing == null) {
    final Fragment newInstance = MyFragment.newInstance();
    getSupportFragmentManager()
    .beginTransaction()
    .add(R.id.fragmentContainer, newInstance, tag)
    .commit();
    }

    标签是 String您可以将其保存在常量中(例如 final static String MYFRAGMENT_TAG = "MYFRAGMENT_TAG";)。

    你在使用 Support.V4 fragment 吗?如果是这样,您需要更改 getFragmentManager()getSupportFragmentManager() (看起来你是,因为你有 AppCompatActivity

    此外, fragment 事务应由 if (savedInstaceState == null) { // do it here } 包围。

    关于java - 为什么 onAttach 不能识别正确的 instanceof 上下文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42358146/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com