从活动调用Fragment类时出错

时间:2018-03-16 17:20:05

标签: java android api android-studio location

我目前正在开发一款应用,其中一项功能是找到最近的药店。然而,其中一个类PharmacyMapFragment是一个Fragment类,当我尝试调用它时,应用程序崩溃,我收到此错误消息:

  

' android.content.ActivityNotFoundException:无法找到显式内容   活动课   {com.example.junai.testapp2 / com.example.junai.testapp2.PharmacyMapFragment};   你有没有在AndroidManifest.xml中声明这个活动?'

我认为你不应该在清单中声明一个Fragment类? 我已经包含了与此问题相关的3个部分的代码。有人可以帮忙吗?

主要活动:

package com.example.junai.testapp2;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends FragmentActivity {

    private Button btn_nearest_pharmacy;

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

        btn_nearest_pharmacy = (Button) findViewById(R.id.btn_nearest_pharmacy);


        btn_nearest_pharmacy.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this, PharmacyMapFragment.class));
            }
        });

    }
}

PharmacyMapFragment类:

package com.example.junai.testapp2;

import android.app.DialogFragment;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.places.Places;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

import org.json.JSONArray;
import org.json.JSONObject;

import java.util.ArrayList;

/**
 * Fragment used to display a map of the current location with the nearest pharmacies and other
 * nearby pharmacies
 *
 * References -------------------------------------------------------------------------------------/
 *  https://github.com/googlemaps/android-samples/blob/master/tutorials/CurrentPlaceDetailsOnMap/app
 *  /src/main/java/com/example/currentplacedetailsonmap/MapsActivityCurrentPlace.java#
 *  https://developers.google.com/maps/documentation/android-api/current-place-tutorial
 *  https://developers.google.com/maps/documentation/android-api/hiding-features
 */
public class PharmacyMapFragment extends Fragment implements OnMapReadyCallback,
        GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {

    //static/default values for settings
    private static final String TAG = LogTag.pharmacyLogFragment;
    private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
    private static final int DEFAULT_ZOOM = 15;
    private static final String KEY_CAMERA_POSITION = "camera_position";
    private static final String KEY_LOCATION = "location";
    private final LatLng mDefaultLocation = new LatLng(56.463190, -3.038596 );

    //used objects
    private GoogleMap mMap;
    private CameraPosition mCameraPosition;
    private GoogleApiClient mGoogleApiClient;
    private boolean mLocationPermissionGranted;
    private Location mLastKnownLocation;

    private ArrayList<Pharmacy> pharmacies = new ArrayList<>();

    public PharmacyMapFragment() {}

    @Override //generates layout
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_pharmacy_map, container, false);
    }

    @Override //setup method
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //used for smoother transitions if this is not the first state
        if (savedInstanceState != null) {
            mLastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION);
            mCameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
        }

        //set up api client for api calls
        mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                .enableAutoManage((FragmentActivity) getActivity(), this)
                .addConnectionCallbacks(this)
                .addApi(LocationServices.API)
                .addApi(Places.GEO_DATA_API)
                .addApi(Places.PLACE_DETECTION_API)
                .build();
        mGoogleApiClient.connect();
    }


    @Override
    public void onMapReady(GoogleMap map) {
        mMap = map;

        updateLocationUI(); //updates the UI, called first in case of previous sessions
        getDeviceLocation(); //get current device location
        getPharmaciesFromAPI(); //gets pharmacies from google places search api

    }

    //Used to update the UI
    private void updateLocationUI() {
        if (mMap == null) {  //if map is null exit method
            return;
        }

        //if we have locations permission set permission to true
        if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(),
                android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mLocationPermissionGranted = true;
        } else {
            ActivityCompat.requestPermissions(getActivity(),
                    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
        }

        //if we have location permissions update the ui
        if (mLocationPermissionGranted) {
            mMap.setMyLocationEnabled(true);
            mMap.getUiSettings().setMyLocationButtonEnabled(true);
        } else {
            mMap.setMyLocationEnabled(false);
            mMap.getUiSettings().setMyLocationButtonEnabled(false);
            mLastKnownLocation = null;
        }
    }

    private void getDeviceLocation() {
        //Get location permissions and try to locate current position
        if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(),
                android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mLocationPermissionGranted = true;
        } else {
            ActivityCompat.requestPermissions(getActivity(),
                    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
        }

        if (mLocationPermissionGranted) {
            mLastKnownLocation = LocationServices.FusedLocationApi
                    .getLastLocation(mGoogleApiClient);
        }

        // Set the map's camera position to the current location of the device.
        if (mCameraPosition != null) {
            mMap.moveCamera(CameraUpdateFactory.newCameraPosition(mCameraPosition));
        } else if (mLastKnownLocation != null) {
            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                    new LatLng(mLastKnownLocation.getLatitude(),
                            mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
        } else {
            Toast.makeText(getActivity(), "Cannot get location", Toast.LENGTH_SHORT).show();
            Log.d(TAG, "Current location is null. Using defaults.");
            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
            mMap.getUiSettings().setMyLocationButtonEnabled(false);
        }
    }

    @Override //used when the premission result comes back
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
                                           @NonNull int[] grantResults) {
        mLocationPermissionGranted = false;
        switch (requestCode) {
            case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    mLocationPermissionGranted = true;
                }
            }
        }
        updateLocationUI();
    }

    //gets list of pharmacies as a json object from the api
    public void getPharmaciesFromAPI(){
        double lat,lng;

        if(mLastKnownLocation != null) {
            lat = mLastKnownLocation.getLatitude();
            lng = mLastKnownLocation.getLongitude();
        } else {
            lat = mDefaultLocation.latitude;
            lng = mDefaultLocation.longitude;
        }

        // Instantiate the RequestQueue.
        RequestQueue queue = Volley.newRequestQueue(getActivity().getApplicationContext());
        String API_KEY = getString(R.string.API_KEY);
        String url ="https://maps.googleapis.com/maps/api/place/nearbysearch/json?"
                + "location=" + lat + "," + lng + "&rankby=distance&type=pharmacy&key=" + API_KEY;

        // Request a string response from the provided URL.
        JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, url, null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        parseJSON(response); //parse the json response into pharmacy objects
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.d(TAG, error.toString());
                Toast.makeText(getActivity(), "Cannot connect to the internet", Toast.LENGTH_SHORT)
                        .show();
            }
        });
        // Add the request to the RequestQueue.
        queue.add(jsObjRequest);
    }

    //parses the json
    private void parseJSON(JSONObject response){
        try {
            JSONArray results = response.getJSONArray("results");
            pharmacies.clear();

            for(int i=0; i<results.length();i++) {
                Pharmacy pharmacy = new Pharmacy();
                JSONObject current = results.getJSONObject(i);
                JSONObject location = current.getJSONObject("geometry").getJSONObject("location");

                pharmacy.setLat(location.getDouble("lat"));
                pharmacy.setLng(location.getDouble("lng"));
                pharmacy.setName(current.getString("name"));
                pharmacy.setInfo(current.getString("vicinity"));
                pharmacies.add(pharmacy);
            }
            addMapMarkers(pharmacies);
        }catch(Exception e) {
            Log.d(TAG, e.toString());
        }
    }

    //adds markers for pharmacies onto the map
    private void addMapMarkers(ArrayList<Pharmacy> pharmacies) {
        for(int i=0;i<pharmacies.size();i++) {
            double lat = pharmacies.get(i).getLat();
            double lng = pharmacies.get(i).getLng();
            String title = pharmacies.get(i).getName();

            if(i==0) {
                mMap.addMarker(new MarkerOptions().position(new LatLng(lat,lng)).title(title)
                        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.
                                HUE_AZURE)));
            } else {
                mMap.addMarker(new MarkerOptions().position(new LatLng(lat,lng)).title(title));
            }
        }
        showDialog(pharmacies.get(0));
    }

    private void showDialog(Pharmacy pharmacy) {
        // Supply num input as an argument.
        Bundle args = new Bundle();
        args.putString("name", pharmacy.getName());
        args.putString("info", pharmacy.getInfo());

        DialogFragment nearestPharmacy = new NearestPharmacyFragment();
        nearestPharmacy.setArguments(args);
        nearestPharmacy.show(getFragmentManager().beginTransaction(), "dialog");
    }

    /*
    *  API and connection call methods
    */
    @Override
    public void onSaveInstanceState(Bundle outState) {
        if (mMap != null) {
            outState.putParcelable(KEY_CAMERA_POSITION, mMap.getCameraPosition());
            outState.putParcelable(KEY_LOCATION, mLastKnownLocation);
            super.onSaveInstanceState(outState);
        }
    }

    @Override // Build the map.
    public void onConnected(Bundle connectionHint) {
        FragmentManager manager = getFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        MapFragment fragment = new MapFragment();
        transaction.add(R.id.map, fragment);
        transaction.commit();
        fragment.getMapAsync(this);
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult result) {
        Log.d(TAG, "Play services connection failed: ConnectionResult.getErrorCode() = "
                + result.getErrorCode());
    }

    @Override
    public void onConnectionSuspended(int cause) {
        Log.d(TAG, "Play services connection suspended. Error code: " + cause);
    }

}

fragment_pharmacy_map.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.junai.testapp2.PharmacyMapFragment"
    android:name="com.google.android.gms.maps.MapFragment" >

    <com.google.android.gms.maps.MapView
        class="com.google.android.gms.maps.MapFragment"
        android:id="@+id/map"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</FrameLayout>

的AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.junai.testapp2">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <user-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="TestApp2"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="AIzaSyAFK4WLnnx-G4RIV5-3wr2-Pp5LnrkmQhw" />


        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
<activity
    android:name=".Test">
</activity>

        <uses-library android:name="com.google.android.maps" />
    </application>

</manifest>

3 个答案:

答案 0 :(得分:2)

Intent用于启动新的 activity ,但您正在使用它来启动 Fragment ,这样是错误。

但别担心,不是什么大不了的事。

MainActivity.java 中,

替换此代码

startActivity(new Intent(MainActivity.this, PharmacyMapFragment.class));

这一个

getSupportFragmentManager().beginTransaction().replace(R.id.container, new PharmacyMapFragment()).commit();

确保auto-import已启用。

这样就可以了。

答案 1 :(得分:1)

老兄,你试图通过使用意图开始片段作为活动。那是错的。您应该按照here所述使用FragmentManager。

答案 2 :(得分:1)

活动可以表示为单个屏幕,片段可以表示为其中的子视图。

您不能直接显示片段,您需要主持人将其附加,也就是说,您需要一个活动来托管您的片段。您可以在活动中放置单个或多个片段,片段将显示在其中。

这里你调用了startActivity,这个方法用于启动一个活动,你传递了一个PharmacyMapFragment,它是一个片段而不是一个活动。因此,它无法查看具有该类型的活动并抛出该错误。

TL; DR

创建一个活动,将PharmacyMapFragment放入其中,将其置于活动的布局中或使用Fragment事务,然后使用该活动的类名调用startActivity

教程:https://developer.android.com/guide/components/fragments.html#Adding