Android 应用程序在扩展到 FragmentActivity 时崩溃

Android App Crashes while extending to FragmentActivity

所以我对 Android 开发还很陌生。我一直在开发 Android Prayer Times 应用程序,在我想集成 Google Play Services for Location 之前它一直运行良好。因为我正在关注 Accessing Location Guide I was instructed to first set up (which I have already done) and then connect to Google Play Services。这就是问题所在。我浏览了关于如何连接到 Google API 的整个页面,并正确地按照说明进行操作。然后我意识到我必须改变我的

public class MainActivity extends Activity

进入

public class MainAcitvity extends FragmentActivity

根据 developer.android.com 上的指南。之后,当我在 phone.

上尝试时,我的应用程序不再运行

我对 Android 中的 Fragment 完全不熟悉。我需要在 xml 文件中放入 Fragment 吗?

这是我的 MainActivity.java 文件:

package com.ahmed.omar.tawheed;

import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;

import android.support.v4.app.FragmentActivity;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

public class MainActivity extends FragmentActivity
        implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

    private TextView txtPrayerNames;
    private TextView txtPrayerTimes;

    private GoogleApiClient mGoogleApiClient;

    // Request code to use when launching the resolution activity
    private static final int REQUEST_RESOLVE_ERROR = 1001;
    // Unique tag for the error dialog fragment
    private static final String DIALOG_ERROR = "dialog_error";
    // Bool to track whether the app is already resolving an error
    private boolean mResolvingError = false;

    private static final String STATE_RESOLVING_ERROR = "resolving_error";

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        txtPrayerNames = (TextView) findViewById(R.id.txtPrayerNames);
        txtPrayerTimes = (TextView) findViewById(R.id.txtPrayerTimes);

        getTimes();

        GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) //used to connect
                .addConnectionCallbacks(this)                               // to Google Play Services
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

        mResolvingError = savedInstanceState != null
                && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) { //Used to Create App Bar

        // Inflate the menu items for use in the action bar
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_activity_actions, menu);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) { //Used to Handle Presses on App Bar Items
        // Handle presses on the action bar items
        switch (item.getItemId()) {
            case R.id.action_refresh:
                getTimes();
                return true;
            case R.id.action_settings:
                openSettings();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private void openSettings() { //misc
        Toast.makeText(this, "Settings button pressed", Toast.LENGTH_SHORT).show();
    }

    /********************************************************************/

    @Override
    public void onConnected(Bundle connectionHint) {
        // Connected to Google Play services!
        // The good stuff goes here.
    }

    @Override
    public void onConnectionSuspended(int cause) {
        // The connection has been interrupted.
        // Disable any UI components that depend on Google APIs
        // until onConnected() is called.
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        // This callback is important for handling errors that
        // may occur while attempting to connect with Google.
        //
        if (mResolvingError) {
            // Already attempting to resolve an error.
            return;
        } else if (result.hasResolution()) {
            try {
                mResolvingError = true;
                result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
            } catch (IntentSender.SendIntentException e) {
                // There was an error with the resolution intent. Try again.
                mGoogleApiClient.connect();
            }
        } else {
            // Show dialog using GooglePlayServicesUtil.getErrorDialog()
            showErrorDialog(result.getErrorCode());
            mResolvingError = true;
        }

    }

    /**----------------------------------------------------------------**/

    /* Creates a dialog for an error message */
    private void showErrorDialog(int errorCode) {
        // Create a fragment for the error dialog
        ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
        // Pass the error that should be displayed
        Bundle args = new Bundle();
        args.putInt(DIALOG_ERROR, errorCode);
        dialogFragment.setArguments(args);
        dialogFragment.show(getSupportFragmentManager(), "errordialog");
    }

    /* Called from ErrorDialogFragment when the dialog is dismissed. */
    public void onDialogDismissed() {
        mResolvingError = false;
    }

    /* A fragment to display an error dialog */
    public static class ErrorDialogFragment extends DialogFragment {
        public ErrorDialogFragment() { }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            // Get the error code and retrieve the appropriate dialog
            int errorCode = this.getArguments().getInt(DIALOG_ERROR);
            return GooglePlayServicesUtil.getErrorDialog(errorCode,
                    this.getActivity(), REQUEST_RESOLVE_ERROR);
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            ((MainActivity)getActivity()).onDialogDismissed();
        }
    }

    /**----------------------------------------------------------------**/

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_RESOLVE_ERROR) {
            mResolvingError = false;
            if (resultCode == RESULT_OK) {
                // Make sure the app is not already connected or attempting to connect
                if (!mGoogleApiClient.isConnecting() &&
                        !mGoogleApiClient.isConnected()) {
                    mGoogleApiClient.connect();
                }
            }
        }
    }

    /**----------------------------------------------------------------**/

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError);
    }

    /**----------------------------------------------------------------**/

    @Override
    protected void onStart() {
        super.onStart();
        if (!mResolvingError) {  // more about this later
            mGoogleApiClient.connect();
        }
    }

    @Override
    protected void onStop() {
        mGoogleApiClient.disconnect();
        super.onStop();
    }

    /********************************************************************/


    // method to append Updated prayer times into TextView in activity_main
    public void getTimes() {

        // Retrieve LATITUDE, LONGITUDE, and TIMEZONE using location API. Currently set for Detroit
        double latitude = 42.3314;
        double longitude = -83.0458;
        double timezone = -5;

        String sFajr, sSunrise, sDhuhr, sAsr, sSunset, sMaghrib, sIsha;

        PrayTime prayers = new PrayTime();

        prayers.setTimeFormat(prayers.Time12);
        prayers.setCalcMethod(prayers.ISNA);
        prayers.setAsrJuristic(prayers.Hanafi);
        prayers.setAdjustHighLats(prayers.None);
        int[] offsets = { 0, 0, 0, 0, 0, 0, 0 }; // {Fajr,Sunrise,Dhuhr,Asr,Sunset,Maghrib,Isha}
        prayers.tune(offsets);

        Date now = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(now);

        ArrayList prayerTimes = prayers.getPrayerTimes(cal, latitude,
                longitude, timezone);
        ArrayList prayerNames = prayers.getTimeNames();


        sFajr = ""+prayerTimes.get(0);
        sSunrise = ""+prayerTimes.get(1);
        sDhuhr = ""+prayerTimes.get(2);
        sAsr = ""+prayerTimes.get(3);
        sSunset = ""+prayerTimes.get(4);
        sMaghrib = ""+prayerTimes.get(5);
        sIsha = ""+prayerTimes.get(6);

        txtPrayerNames.setText("");
        txtPrayerTimes.setText("");

        for (int i = 0; i < 7; i++) {
            txtPrayerNames.append("\n"+prayerNames.get(i));
            txtPrayerTimes.append("\n"+prayerTimes.get(i));
        }

        Toast.makeText(this, "Prayer Times Updated", Toast.LENGTH_SHORT).show();

    }
}

这是我的 activity_main.xml 文件:

<RelativeLayout

    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"
    android:orientation="horizontal" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Detroit, MI"
        android:gravity="center"
        android:layout_centerHorizontal="true"
        android:textSize="40sp"
        android:layout_margin="32dp"/>

    <TextView
        android:id="@+id/txtPrayerNames"
        android:gravity="left"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:textSize="35sp"
        android:layout_margin="32dp"/>

    <TextView
        android:id="@+id/txtPrayerTimes"
        android:gravity="right"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:textSize="35sp"
        android:layout_margin="32dp"/>


</RelativeLayout>

最后 logcat:

01-16 23:16:18.457    2030-2030/com.ahmed.omar.tawheed I/art﹕ Late-enabling -Xcheck:jni
01-16 23:16:18.643    2030-2030/com.ahmed.omar.tawheed D/AndroidRuntime﹕ Shutting down VM
01-16 23:16:18.644    2030-2030/com.ahmed.omar.tawheed E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.ahmed.omar.tawheed, PID: 2030
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ahmed.omar.tawheed/com.ahmed.omar.tawheed.MainActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'void com.google.android.gms.common.api.GoogleApiClient.connect()' on a null object reference
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
            at android.app.ActivityThread.access0(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
     Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void com.google.android.gms.common.api.GoogleApiClient.connect()' on a null object reference
            at com.ahmed.omar.tawheed.MainActivity.onStart(MainActivity.java:201)
            at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1220)
            at android.app.Activity.performStart(Activity.java:5949)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2261)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
            at android.app.ActivityThread.access0(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

如果您需要任何其他文件,请告诉我。提前致谢。

NullPointerException: Attempt to invoke interface method 'void com.google.android.gms.common.api.GoogleApiClient.connect()' on a null object reference

因为当你调用connect()方法时mGoogleApiClient对象是null

您正在 onCreate 中创建 mGoogleApiClient 的单独对象,并使用未初始化的对象调用连接方法。所以使用您在 onCreate 方法之前声明并在 onStart 方法中使用的相同对象:

  mGoogleApiClient = new GoogleApiClient.Builder(this)  
                .addConnectionCallbacks(this)   
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

你已经在声明部分创建了一个 GoogleApiClient 的实例,尽管你已经在 onCreate() 方法中新初始化了同名对象。

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) //used to connect
            .addConnectionCallbacks(this)                               // to Google Play Services
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();

所以你需要像

一样改变上面的代码
mGoogleApiClient = new GoogleApiClient.Builder(this) //used to connect
            .addConnectionCallbacks(this)                               // to Google Play Services
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();

您的全局变量 mGoogleApiClient 未定义。 oncreate() 调用后它仍然为空。所以 mGoogleApiClient.connect(); 会抛出 nullpointerexception.

改变这个

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) //used to connect
                .addConnectionCallbacks(this)                               // to Google Play Services
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

mGoogleApiClient = new GoogleApiClient.Builder(this) //used to connect
                .addConnectionCallbacks(this)                               // to Google Play Services
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();