我有三个片段。
Fragment1:显示数据列表的列表片段,Fragment2:显示数据源列表 Fragment3:显示数据源的详细信息。
要切换到 Fragment1 中的新数据显示,我使用 startActivityForResult 调出 Fragment2,我通过单击选择一个新的数据源,它返回一个包含字符串的意图的结果,这成功了,Fragment1 打开新数据源并显示它。
但是,如果我从 fragment1 转到 fragment2 并且在选择新数据源之前,我导航到 fragment3 以查看数据源的详细信息,然后导航回 fragment2,当 fragment2 返回其结果时,我收到以下错误:
01-28 10:29:38.818: E/AndroidRuntime(1409): FATAL EXCEPTION: main
01-28 10:29:38.818: E/AndroidRuntime(1409): Process: aston.cs3040.rssitemfragment, PID: 1409
01-28 10:29:38.818: E/AndroidRuntime(1409): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=65537, result=0, data=null} to activity {aston.cs3040.rssitemfragment/aston.cs3040.rssfeedfragment.RssListActivity}: java.lang.NullPointerException
01-28 10:29:38.818: E/AndroidRuntime(1409): at android.app.ActivityThread.deliverResults(ActivityThread.java:3346)
01-28 10:29:38.818: E/AndroidRuntime(1409): at android.app.ActivityThread.handleSendResult(ActivityThread.java:3389)
01-28 10:29:38.818: E/AndroidRuntime(1409): at android.app.ActivityThread.access$1200(ActivityThread.java:135)
01-28 10:29:38.818: E/AndroidRuntime(1409): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1445)
01-28 10:29:38.818: E/AndroidRuntime(1409): at android.os.Handler.dispatchMessage(Handler.java:102)
01-28 10:29:38.818: E/AndroidRuntime(1409): at android.os.Looper.loop(Looper.java:137)
01-28 10:29:38.818: E/AndroidRuntime(1409): at android.app.ActivityThread.main(ActivityThread.java:4998)
01-28 10:29:38.818: E/AndroidRuntime(1409): at java.lang.reflect.Method.invokeNative(Native Method)
01-28 10:29:38.818: E/AndroidRuntime(1409): at java.lang.reflect.Method.invoke(Method.java:515)
01-28 10:29:38.818: E/AndroidRuntime(1409): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
01-28 10:29:38.818: E/AndroidRuntime(1409): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
01-28 10:29:38.818: E/AndroidRuntime(1409): at dalvik.system.NativeStart.main(Native Method)
01-28 10:29:38.818: E/AndroidRuntime(1409): Caused by: java.lang.NullPointerException
01-28 10:29:38.818: E/AndroidRuntime(1409): at aston.cs3040.rssfeedfragment.RssListFragment.onActivityResult(RssListFragment.java:71)
01-28 10:29:38.818: E/AndroidRuntime(1409): at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:166)
01-28 10:29:38.818: E/AndroidRuntime(1409): at android.app.Activity.dispatchActivityResult(Activity.java:5435)
01-28 10:29:38.818: E/AndroidRuntime(1409): at android.app.ActivityThread.deliverResults(ActivityThread.java:3342)
01-28 10:29:38.818: E/AndroidRuntime(1409): ... 11 more
这是我的代码:
为了在 Fragment1 和 Fragment2(一个名为 RssFeedManagerActivity 的类中的一个片段)之间移动,我在 Fragment1 中有:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_add_feed:
Intent intent = new Intent(getActivity(),
RssFeedManagerActivity.class);
startActivityForResult(intent, MANAGE_FEED);
// see end of chapter 10 for how to wire this up
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MANAGE_FEED && data != null) {
// handle the result
String link = data.getStringExtra("URL"); // this is RssListFragment.java:71
Log.i(RssItemActivity.TAG, "Load: " + link);
loadFeed(link);
}
}
在 Fragment2 我有以下代码返回到 Fragment1
Intent i = new Intent();
i.putExtra("URL", command[1]);
Log.i(RssItemActivity.TAG, "finish and load..." + command[1]);
// load the feed finish this fragment
getActivity().setResult(Activity.RESULT_OK, i);
getActivity().finish();
如果我想从 Fragment2 到 Fragment3,代码是:
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
FeedDetails details = ((FeedMgrListAdapter)getListAdapter()).getItem(position); // (FeedDetails) l.getItemAtPosition(position);
Log.i(RssItemActivity.TAG, "Clicked " + details.getTitle());
Intent intent = new Intent(getActivity(), FeedDetailsFormActivity.class);
intent.putExtra("POSITION", position);
Log.i(RssItemActivity.TAG, "Click tag: " + ((String)v.getTag()));
if (position == TheNews.getInstance().getFeeds().size()-1) {
TheNews.getInstance().getFeeds().add(position, new FeedDetails("http://","category", "Feed Title"));
}
startActivity(intent);
}
从 Fragment3 回到 Fragment2 我有:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (NavUtils.getParentActivityName(getActivity()) != null) {
NavUtils.navigateUpFromSameTask(getActivity());
}
return true;
为什么 Fragment1 到 Fragment2 和 Back 正常工作,但 Fragment1 到 Fragment2 到 Fragment3 并再次返回 1 不起作用?从 Fragment2 返回到 Fragment1 时打印的 Log 消息表明 Intent 在其 extras 中添加了正确的字符串。我在 onActivityResult 中的 if 语句检查数据是否不等于 null,但在下一行似乎有一个空指针异常。
这是完整的代码:
片段1是这样的:
public class RssListFragment extends ListFragment {
private TheNews theNews;
public static final int MANAGE_FEED = 1;
public boolean reportingBack=false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
theNews = TheNews.getInstance();
this.setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.feed_list_mgr, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_add_feed:
Intent intent = new Intent(getActivity(),
RssFeedManagerActivity.class);
startActivityForResult(intent, MANAGE_FEED);
// see end of chapter 10 for how to wire this up
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MANAGE_FEED && data != null) {
// handle the result
String link = data.getStringExtra("URL");
Log.i(RssItemActivity.TAG, "Load: " + link);
/* TheNews.getTheNews(getActivity(), this).*/ loadFeed(link);
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
RssItem item = (RssItem) l.getItemAtPosition(position);
CheckBox c = (CheckBox) v.findViewById(R.id.read_or_not);
Log.i(RssItemActivity.TAG,
"Click id " + id + " title " + item.getTitle()
+ " checkbox is " + (c.isChecked() ? "" : " not ")
+ "checked");
Intent intent = new Intent(getActivity(), RssItemPagerActivity.class);
intent.putExtra("POSITION", position);
startActivity(intent);
}
@Override
public void onResume() {
super.onResume();
if (theNews == null) {
Log.i(RssItemActivity.TAG, "OnResume: Get the news");
// create the news singleton and wait for callback
theNews = TheNews.getTheNews(getActivity(), this);
loadFeed(theNews.getFeeds().get(0).getUri());
} else {
// singleton previously constructed so we have the data already
if (!reportingBack) {
Log.i(RssItemActivity.TAG, "Report Back onResume ");
if (getListAdapter() == null) {
Log.i(RssItemActivity.TAG, "Creating list adapter");
setListAdapter(new RssItemListAdapter(this.getActivity(), theNews.getFeed().getItems()));
}
//((RssItemListAdapter) getListAdapter()).notifyDataSetChanged();
//reportBack(theNews.getFeed());
} else {
reportingBack = false;
Log.i(RssItemActivity.TAG, "OnResume: I reported back");
//((RssItemListAdapter) getListAdapter()).notifyDataSetChanged();
//Log.i(RssItemActivity.TAG, "Report Back Invalidate View ");
//this.getView().invalidate();
}
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//reportingBack = false;
}
public void reportBack(RssFeed completeFeed) {
reportingBack = true;
//Log.i(RssItemActivity.TAG, "Report Back: " + completeFeed);
if (completeFeed != null) {
// if (getListAdapter() == null) {
Log.i(RssItemActivity.TAG, "Creating list adapter");
setListAdapter(new RssItemListAdapter(this.getActivity(), completeFeed.getItems()));
/*
} else {
Log.i(RssItemActivity.TAG, "Finished AsyncTask: list changed");
this.getView().invalidate();
((RssItemListAdapter) getListAdapter()).notifyDataSetChanged();
// this.getView().invalidate();
}
*/
} else {
// No Network? No Feed?
Toast.makeText(this.getActivity(),
"Could not connect to feed. Is your network connected?",
Toast.LENGTH_LONG).show();
getActivity().finish();
}
}
private class RssItemListAdapter extends ArrayAdapter<RssItem> {
public RssItemListAdapter(Activity a, List<RssItem> items) {
super(a, 0, items);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getActivity().getLayoutInflater().inflate(
R.layout.list_layout_rss_item, null);
}
RssItem item = theNews.getItem(position);
Log.i(RssItemActivity.TAG, "Get View in List Adapter, ITEM: "
+ item.getTitle());
TextView titleTextView = (TextView) convertView
.findViewById(R.id.rss_item_titleTextView);
titleTextView.setText(item.getTitle());
TextView dateTextView = (TextView) convertView
.findViewById(R.id.rss_item_date);
dateTextView.setText(item.getDate());
CheckBox readCheckBox = (CheckBox) convertView
.findViewById(R.id.read_or_not);
readCheckBox.setChecked(item.isRead());
return convertView;
}
}
private class RssReadFeed extends AsyncTask<String, Void, RssFeed> {
//private final ProgressDialog dialog = new ProgressDialog(mAppContext);
@Override
protected RssFeed doInBackground(String... urls) {
SAXParserFactory factory = SAXParserFactory.newInstance();
SaxRssHandler handler = new SaxRssHandler();
try {
URL url = new URL(urls[0]);
SAXParser parser = factory.newSAXParser();
Log.i(RssItemActivity.TAG, "loading new feed... " + url);
InputStream is = url.openConnection().getInputStream();
Log.i(RssItemActivity.TAG, "Now parse the input");
parser.parse(is, handler);
Log.i(RssItemActivity.TAG, "Parsing done");
return handler.getFeed();
} catch (Exception e) {
Log.i(RssItemActivity.TAG, e.getMessage());
return null;
}
}
@Override
protected void onPreExecute() {
//this.dialog.setMessage("Processing...");
//this.dialog.show();
}
@Override
protected void onPostExecute(RssFeed completeFeed) {
// may report back null if is wasn't possible to download the data
//theFeed = completeFeed;
theNews.setFeed(completeFeed);
Log.i(RssItemActivity.TAG, "Updated new feed with " + completeFeed.getItems().size() + " items");
reportBack(completeFeed);
//this.dialog.dismiss();
}
}
public void loadFeed(String uri) {
String[] urlToRssFeed = { uri };
RssReadFeed process = new RssReadFeed();
process.execute(urlToRssFeed);
}
}
片段2是:
public class RssFeedManagerFragment extends ListFragment implements OnClickListener {
private TheNews theNews;
@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
theNews = TheNews.getInstance();
Log.i(RssItemActivity.TAG, "Setting list adapter for a list of length "
+ theNews.getFeeds().size());
FeedMgrListAdapter adapter = new FeedMgrListAdapter(theNews.getFeeds(), this);
this.setListAdapter(adapter);
this.setHasOptionsMenu(true);
getActivity().setTitle(R.string.feed_mgr_title);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (NavUtils.getParentActivityName(getActivity()) != null) {
NavUtils.navigateUpFromSameTask(getActivity());
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
FeedDetails details = ((FeedMgrListAdapter)getListAdapter()).getItem(position); // (FeedDetails) l.getItemAtPosition(position);
Log.i(RssItemActivity.TAG, "Clicked " + details.getTitle());
Intent intent = new Intent(getActivity(), FeedDetailsFormActivity.class);
intent.putExtra("POSITION", position);
Log.i(RssItemActivity.TAG, "Click tag: " + ((String)v.getTag()));
if (position == TheNews.getInstance().getFeeds().size()-1) {
TheNews.getInstance().getFeeds().add(position, new FeedDetails("http://","category", "Feed Title"));
}
startActivity(intent);
}
@Override
public void onResume() {
super.onResume();
if (getListAdapter() != null) {
FeedMgrListAdapter arrayAdapter = (FeedMgrListAdapter) getListAdapter();
arrayAdapter.notifyDataSetChanged();
}
}
private class FeedMgrListAdapter extends ArrayAdapter<FeedDetails> {
private List<FeedDetails> items;
private RssFeedManagerFragment fragment;
public FeedMgrListAdapter(List<FeedDetails> items, RssFeedManagerFragment fragment) {
super(getActivity(), 0, items);
this.items = items;
this.fragment = fragment;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView titleTextView = null;
if (convertView == null) {
convertView = getActivity().getLayoutInflater().inflate(
// R.layout.normal_list_item, null);
R.layout.feed_list_layout, null);
}
titleTextView = (TextView) convertView
.findViewById(R.id.title_text_view);
FeedDetails item = items.get(position);
if (position == items.size() - 1) {
titleTextView.setTextColor(0xffcccccc);
((ImageButton)convertView.findViewById(R.id.load_button)).setClickable(false);
((ImageButton)convertView.findViewById(R.id.delete_button)).setClickable(false);
} else {
titleTextView.setTextColor(0xff0000ff);
((ImageButton)convertView.findViewById(R.id.load_button)).setTag("Load!" + items.get(position).getUri());
((ImageButton)convertView.findViewById(R.id.load_button)).setOnClickListener(fragment);
((ImageButton)convertView.findViewById(R.id.delete_button)).setTag("Delete!" + position);
((ImageButton)convertView.findViewById(R.id.delete_button)).setOnClickListener(fragment);
}
Log.i(RssItemActivity.TAG, "Pos " + position + " title: " + item.getTitle());
titleTextView.setText(item.getTitle());
return convertView;
}
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i(RssItemActivity.TAG, "Click tag: " + ((String)v.getTag()));
String[] command = ((String)v.getTag()).split("!");
if (command.length == 2) {
if (command[0].equalsIgnoreCase("delete")) {
TheNews.getInstance().deleteFeed(Integer.parseInt(command[1]));
((FeedMgrListAdapter)this.getListAdapter()).notifyDataSetChanged();
}
if (command[0].equalsIgnoreCase("load")) {
Intent i = new Intent();
i.putExtra("URL", command[1]);
Log.i(RssItemActivity.TAG, "finish and load..." + command[1]);
// load the feed finish this fragment
//theNews.getFeed().clear();
getActivity().setResult(Activity.RESULT_OK, i);
getActivity().finish();
}
}
}
}
片段3是:
public class FeedDetailsFormFragment extends Fragment {
private FeedDetails feed;
private static final String DIALOG_DATE = "date";
private static final int REQUEST_DATE = 0;
private Button dateButton;
public FeedDetailsFormFragment() {
super();
}
@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int position = getArguments().getInt("POSITION");
feed = TheNews.getInstance().getFeeds().get(position);
this.setHasOptionsMenu(true);
getActivity().setTitle(R.string.new_feed_title);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (NavUtils.getParentActivityName(getActivity()) != null) {
NavUtils.navigateUpFromSameTask(getActivity());
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public static FeedDetailsFormFragment newInstance(int position) {
Bundle args = new Bundle();
args.putInt("POSITION", position);
FeedDetailsFormFragment fragment = new FeedDetailsFormFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.feed_details_form, parent, false);
getActivity().setTitle(R.string.new_feed_title);
EditText title = (EditText) v.findViewById(R.id.feedTitle);
title.setText(feed.getTitle());
title.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
feed.setTitle(s.toString());
}
});
EditText uri = (EditText) v.findViewById(R.id.feedUri);
uri.setText(feed.getUri());
uri.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
feed.setUri(s.toString());
}
});
EditText cat = (EditText) v.findViewById(R.id.feedCategory);
cat.setText(feed.getCategory());
cat.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
feed.setCategory(s.toString());
}
});
dateButton = (Button) v.findViewById(R.id.feedDate);
updateDate();
dateButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
FragmentManager fm = getActivity().getSupportFragmentManager();
DatePickerFragment dialog = DatePickerFragment.newInstance(feed
.getDate());
dialog.setTargetFragment(FeedDetailsFormFragment.this,
REQUEST_DATE);
dialog.show(fm, DIALOG_DATE);
}
});
return v;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_DATE) {
Date date = (Date) data
.getSerializableExtra(DatePickerFragment.EXTRA_DATE);
Log.i(RssItemActivity.TAG,
"Setting date of feed " + date.toString());
feed.setDate(date);
updateDate();
}
}
private void updateDate() {
Log.i(RssItemActivity.TAG,
"Setting date button " + feed.getDateAsString());
dateButton.setText(feed.getDateAsString());
}
}