android: getFragmentManager() returns null

放肆的年华 提交于 2019-12-12 16:09:55

问题


Edit: The problem is that the fragment is getting detached from the Activity. However, I don't know how to prevent this.

I have an application that uses a tab bar. When one of the tabs is clicked it loads a list of topics in the space below the tab bar. One of the topics is 'Directions'. Upon clicking this the space is now replaced with a layout that has another bar at the top (below the tab bar) that includes a 'Back' button and a 'Get Directions' button. Below that bar is a google map of the location. If I click 'Back' I am returned to the list as expected. Then if I click 'Directions' in the list I go back to the map as expected. Then if I click 'Back' again instead of returning me to the list again it crashes the app. It shows a NullPointerException that points to the line FragmentTransaction ft = getFragmentManager().beginTransaction(); inside the Back Button's setOnClickListener. Not sure why it's losing track of the fragmentManager.

Here is the file for tab that initially loads the list:

package org.childrensmuseum.visittcmindy;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable.Orientation;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class InfoTab extends Fragment {
    private ArrayList<InfoPage> pages;
    private TCMSQLiteHelper sqliteHelper;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sqliteHelper = new TCMSQLiteHelper(this.getActivity());
        pages = sqliteHelper.getAllPages();
        InfoPage directions = new InfoPage();
        directions.setPage_id(101);
        directions.setTitle("Directions");
        InfoPage calendar = new InfoPage();
        calendar.setPage_id(102);
        calendar.setTitle("Calendar");
        pages.add(1, directions);
        pages.add(2, calendar);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.infolist, container, false);
        ListView infoList = (ListView)v.findViewById(R.id.infolistview);
        int[] colors = {0xFFCFE8FF,0xFFCFE8FF};
        infoList.setDivider(new GradientDrawable(Orientation.RIGHT_LEFT, colors));
        infoList.setDividerHeight(2);

        ArrayList<String> valueList = new ArrayList<String>();
        for(InfoPage page : pages){
            valueList.add(page.getTitle());
        }
        String[] values = new String[valueList.size()];
        values = valueList.toArray(values);

        infoList.setAdapter(new InfoAdapter(getActivity(), values));

        infoList.setOnItemClickListener(new OnItemClickListener(){

            @Override
            public void onItemClick(AdapterView<?> parent, View v, int p,
                    long id) {
                long page_id = pages.get(p).getPage_id();
                // If Directions
                if(page_id==101){
                    DirectionsView directions = new DirectionsView();
                    FragmentTransaction ft = getFragmentManager().beginTransaction();
                    ft.replace(R.id.realtabcontent, directions);
                    ft.commit();
                } else {
                    PageDetails details = PageDetails.newInstance(pages.get(p).getPage_id()); 
                    FragmentTransaction ft = getFragmentManager().beginTransaction();
                    ft.replace(R.id.realtabcontent, details);
                    ft.commit();
                }

            }

        });
        return v;
    }

    private class InfoAdapter extends ArrayAdapter<String> {

        public InfoAdapter(Context context, String[] values) {
            super(context, R.layout.explorecell, values);
            // TODO Auto-generated constructor stub
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View row = inflater.inflate(R.layout.infocell,parent,false);

            InfoPage page = pages.get(position);

            if(position % 2 != 0){
                row.setBackgroundColor(getResources().getColor(R.color.listblue));
            } else {
                row.setBackgroundColor(getResources().getColor(R.color.white));
            }

            String page_icon = "page_" + page.getPage_id();
            ImageView iv = (ImageView)row.findViewById(R.id.infoImage);
            TextView tv = (TextView)row.findViewById(R.id.infoText);

            String title = page.getTitle();

            String[] titleParts = title.split("[ ]");
            String newTitle = "";
            for(int i=0;i<titleParts.length;i++){
                titleParts[i] = titleParts[i].substring(0,1).toUpperCase() + titleParts[i].substring(1);
                newTitle += titleParts[i];
                if(i<titleParts.length-1){
                    newTitle += " ";
                }
            }

            iv.setImageResource(getActivity().getResources().getIdentifier(page_icon, "drawable","org.childrensmuseum.visittcmindy"));
            tv.setText(newTitle);
            return row;
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(sqliteHelper != null) {
            sqliteHelper.close();
        }
    }

}

Here is the file for the DirectionsView that is called when you click that item in the list:

package org.childrensmuseum.visittcmindy;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;

import android.app.Dialog;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class DirectionsView extends Fragment implements 
GooglePlayServicesClient.ConnectionCallbacks, 
GooglePlayServicesClient.OnConnectionFailedListener {
    private static View v;
    private MainApplication main;
    private LocationClient mLocationClient;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        main = MainApplication.getInstance();
        mLocationClient = new LocationClient(getActivity(), this, this);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if(v != null){
            ViewGroup parent = (ViewGroup) v.getParent();
            if(parent != null){
                parent.removeView(v);
            }
        }
        try {
            mLocationClient.connect();
            v = inflater.inflate(R.layout.directions, container, false);
            GoogleMap mMap;
            mMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.directionsmap)).getMap();
            Geocoder coder = new Geocoder(getActivity());
            List<Address> address;

            try {
                Log.d("DEBUG","2");
                String museumAddress = "The Children's Museum of Indianapolis, 3000 North Meridian St, Indianapolis, IN 46208";
                address = coder.getFromLocationName(museumAddress, 1);
                Address museumLocation = address.get(0);
                mMap.addMarker(new MarkerOptions()
                        .position(new LatLng(museumLocation.getLatitude(), museumLocation.getLongitude()))
                        .title(getResources().getString(R.string.museumTitle)));
            } catch(Exception e) {
                Log.d("DEBUG","Error Adding Marker: "+e.getLocalizedMessage());
            }
            Button backButton = (Button)v.findViewById(R.id.backtoexhibits);
            backButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    FragmentTransaction ft = getFragmentManager().beginTransaction();
                    InfoTab infoTab = new InfoTab();
                    ft.replace(R.id.realtabcontent, infoTab);
                    ft.commit();
                }
            });

            Button directionsButton = (Button)v.findViewById(R.id.getdirections);
            directionsButton.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    try {
                        openDirectionsDialog();
                    } catch (UnsupportedEncodingException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            });
        } catch (InflateException e){
            /* map is already there, just return view as it is */
            e.printStackTrace();
        }

        return v;
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onConnected(Bundle connectionHint) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onDisconnected() {
        // TODO Auto-generated method stub

    }

    private void openDirectionsDialog() throws UnsupportedEncodingException{
        final Dialog dialog = new Dialog(getActivity());
        dialog.setContentView(R.layout.getdirections);
        dialog.setTitle("Get Directions");
        Button useAddressBtn = (Button)dialog.findViewById(R.id.useAddress);
        Button useLocationBtn = (Button)dialog.findViewById(R.id.useLocationBtn);
        final EditText addressText = (EditText)dialog.findViewById(R.id.addressText);
        final String museumAddress = URLEncoder.encode("The Children's Museum of Indianapolis, 3000 North Meridian St, Indianapolis, IN 46208","UTF-8");

        useAddressBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                String address;
                try {
                    address = URLEncoder.encode(addressText.getText().toString(),"UTF-8");
                    String url = "http://maps.google.com/maps?saddr="+address+"&daddr="+museumAddress;
                    Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(url));
                    intent.setClassName("com.google.android.apps.maps", "com.google.android.maps.MapsActivity");
                    startActivity(intent);
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        });

        useLocationBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Location mCurrentLocation = mLocationClient.getLastLocation();
                double lat = mCurrentLocation.getLatitude();
                double lng = mCurrentLocation.getLongitude();

                String url = "http://maps.google.com/maps?saddr="+lat+","+lng+"&daddr="+museumAddress;
                Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(url));
                intent.setClassName("com.google.android.apps.maps", "com.google.android.maps.MapsActivity");
                startActivity(intent);

            }
        });
        dialog.show();
    }

}

Edit:

Here's the stack trace

12-11 14:07:03.547: E/AndroidRuntime(1846): FATAL EXCEPTION: main
12-11 14:07:03.547: E/AndroidRuntime(1846): Process: org.childrensmuseum.visittcmindy, PID: 1846
12-11 14:07:03.547: E/AndroidRuntime(1846): java.lang.NullPointerException
12-11 14:07:03.547: E/AndroidRuntime(1846):     at org.childrensmuseum.visittcmindy.DirectionsView$1.onClick(DirectionsView.java:80)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at android.view.View.performClick(View.java:4424)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at android.view.View$PerformClick.run(View.java:18383)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at android.os.Handler.handleCallback(Handler.java:733)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at android.os.Handler.dispatchMessage(Handler.java:95)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at android.os.Looper.loop(Looper.java:137)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at android.app.ActivityThread.main(ActivityThread.java:4998)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at java.lang.reflect.Method.invokeNative(Native Method)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at java.lang.reflect.Method.invoke(Method.java:515)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
12-11 14:07:03.547: E/AndroidRuntime(1846):     at dalvik.system.NativeStart.main(Native Method)

Edit 2:

Per suggestions, I tried replacing

FragmentTransaction ft = getFragmentManager().beginTransaction();

with

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();

There was no change in the error.


回答1:


I recommend this: http://developer.android.com/training/implementing-navigation/lateral.html

It's a tutorial on using a viewPager and fragmentPagerAdapter with navigation tabs, so that you don't have to manually set up an onClickListener to change fragments. This should prevent fragments from being detached.




回答2:


You have mixed up support fragment and fragment. You must be using ActionBarSherlock library for this. So you need to extend SherlockFragment and not Fragment.

After that, you need to use the edit that you gave:

 FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();

This should make it work.



来源:https://stackoverflow.com/questions/20527417/android-getfragmentmanager-returns-null

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!