我很难让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是上面片段的活动。
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,它使用一个意图来启动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()));
}
}
}
最佳答案
你的问题是你没有在你的活动中实现接口…public class AddEditCharacterActivity extends SingleFragmentActivity {
这不会implement OnCharacterSave
。
这就是我刚才的意思。
更新:
你是误解的碎片。// Get the container for the character list
->这不是真的。你没有得到“容器”,而是试图得到一个片段的实际实例。
InitiativeListFragment initiativeListFragment = (InitiativeListFragment)
fm.findFragmentById(R.id.fragmentContainer);
如果那块碎片在那就好了。
让我用一种更形象的方式来表达,这就是你正在做的…(给予或接受)
开始活动xxx(
SingleFragmentActivity
)。在某些时候,
InitiativeListFragment
中的R.id.fragmentContainer
被AddEditCharacterActivity / AddEditCharacterFragment
组合替换。此时,
R.id.fragmentContainer
包含AddEditCharacterFragment
类型的片段。既然你的活动实现了
OnCharacterSave
,到目前为止还不错。仍然在相同的activity/fragment组合框中,调用实现的
onCharacterSave()
(参见4),因此一切都很好。然后告诉片段管理器在
R.id.fragmentContainer
中获取片段,并明确地说(aka:cast)片段的类型是InitiativeListFragment
,但是…您的活动应该知道情况并非如此…因为当前片段是AddEditCharacterFragment
。你应该做的是:
重新阅读FragmentManager和FragmentTransactions。
如果要将信息传递给另一个当前不可见/已启动/附加的片段,则必须获取引用(如果有引用,则通过标记)。
然后,如果可能的话,在通过捆绑包传递“数据”的同时将其添加到容器中。
完全不清楚你想做什么,它是什么顺序的,因为你的代码没有真正的关注点的分离,所以你可以看到你的活动和片段正在成为充满代码和业务逻辑的单一怪物。有一些解决方案和替代方案(阅读模型-视图-演示者或类似的模式)可以在提供更容易测试代码的环境的同时缓解混乱。
也就是说,不管你的代码多么复杂,我相信你需要理解为什么你会得到这个例外,我觉得你需要练习一下。
简而言之,当你做
findFragmentById
时,你确实得到了片段(如果存在的话),但是你不能把它扔到你想要的任何东西上。旧评论:
newInstance()
静态方法通常应该存在于片段中并返回new YourFragment();
我的意思是片段的创建通常是通过片段中的静态方法完成的。
说你有
MyFragment extends Fragment {
public static MyFragment newInstance() {
return new MyFragment();
}
public MyFragment() {
// empty constructor is most of the time needed to restore.
}
}
然后从活动开始,你通常做你正在做的事情,但是片段实例是通过调用
MyFragment.newInstance();
创建的(这就是google的做法)。我建议你也按标签添加片段(这样更快)。你也是
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片段吗?如果是这样,您需要将
getFragmentManager()
更改为getSupportFragmentManager()
(看起来您是,因为您已经AppCompatActivity
。此外,片段事务应该由
if (savedInstaceState == null) { // do it here }
包围。