在SwipeRefreshLayout上设置setRefreshing(boolean)时偶尔会出现NullPointerExceptions

时间:2015-12-29 21:59:42

标签: android nullpointerexception null swiperefreshlayout

我有一个简单的应用程序,包含一个主要活动和3个带有ViewPager和Sliding选项卡布局的片段。在每个片段中我都有SwipeRefreshLayouts。 enter image description here

问题有时是Android操作系统决定杀死我的应用程序并且它因该异常而崩溃。但是,每次都不会发生这种情况。我假设有时在调用setRefreshing方法时不会创建片段,这就是导致错误的原因。有人建议如何避免这种NPE?

这是日志:

12-29 23:31:41.770 29982-29982/koemdzhiev.com.stormy E/AndroidRuntime: FATAL EXCEPTION: main
                                                                   Process: koemdzhiev.com.stormy, PID: 29982
                                                                   java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v4.widget.SwipeRefreshLayout.setRefreshing(boolean)' on a null object reference
                                                                       at koemdzhiev.com.stormy.ui.MainActivity.toggleSwipeRefreshLayoutsOff(MainActivity.java:268)
                                                                       at koemdzhiev.com.stormy.ui.MainActivity$3$2.run(MainActivity.java:224)
                                                                       at android.os.Handler.handleCallback(Handler.java:739)
                                                                       at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                       at android.os.Looper.loop(Looper.java:135)
                                                                       at android.app.ActivityThread.main(ActivityThread.java:5292)
                                                                       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:904)
                                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)

MainActivity onCreate:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //-----------MY CODE STARTS HERE-----------------
    //check if the user previously has seen the whats new message...
    sharedPref = getPreferences(Context.MODE_PRIVATE);
    editor = sharedPref.edit();
    if (sharedPref.getInt(getString(R.string.saved_if_whats_new_seen), 1) != 0){
        WhatsNewDialogCreator dialogCreator = new WhatsNewDialogCreator(this, sharedPref);
        dialogCreator.show();
    }

    request = LocationRequest.create()
            .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
            .setSmallestDisplacement(800)
            .setFastestInterval(5 * 60 * 1000)
            .setInterval(60 * 60 * 1000);
    locationProvider = new ReactiveLocationProvider(this);
    //subscribe for background location updates...
    if(isNetworkAvailable()) {
        startBackgroundUpdates();
    }
    mainActivityLayout = (LinearLayout)findViewById(R.id.main_activity_layout);
    changeWindowTopColor();
    this.mCurrent_forecast_fragment = new Current_forecast_fragment();
    this.mHourly_forecast_fragment = new Hourly_forecast_fragment();
    this.mDaily_forecast_fragment = new Daily_forecast_fragment();

    // Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the Tabs and Number Of Tabs.
    adapter = new ViewPagerAdapter(getSupportFragmentManager(), Titles, Numboftabs, mCurrent_forecast_fragment,
            mHourly_forecast_fragment, mDaily_forecast_fragment);

    // Assigning ViewPager View and setting the adapter
    pager = (ViewPager) findViewById(R.id.pager);
    pager.setOffscreenPageLimit(3);
    pager.setAdapter(adapter);

    // Assiging the Sliding Tab Layout View
    tabs = (SlidingTabLayout) findViewById(R.id.tabs);
    tabs.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This makes the tabs Space Evenly in Available width

    // Setting Custom Color for the Scroll bar indicator of the Tab View
    tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
        @Override
        public int getIndicatorColor(int position) {
            return ContextCompat.getColor(MainActivity.this, R.color.tabsScrollColor);
        }
    });

    // Setting the ViewPager For the SlidingTabsLayout
    tabs.setViewPager(pager);

    if(isFirstTimeLaunchingTheApp) {
        Log.d(TAG, "onCreate getLocation");
        getLocation();
    }
}

ViewPagerAdapter:

public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private Current_forecast_fragment mCurrent_forecast_fragment;
private Hourly_forecast_fragment mHourly_forecast_fragment;
private Daily_forecast_fragment mDaily_forecast_fragment;
CharSequence Titles[]; // This will Store the Titles of the Tabs which are Going to be passed when ViewPagerAdapter is created
int NumbOfTabs; // Store the number of tabs, this will also be passed when the ViewPagerAdapter is created


// Build a Constructor and assign the passed Values to appropriate values in the class
public ViewPagerAdapter(FragmentManager fm,CharSequence mTitles[], int mNumbOfTabsumb,Current_forecast_fragment current_fragment,
                        Hourly_forecast_fragment hourly_fragment,
                        Daily_forecast_fragment daily_fragment) {
    super(fm);
    this.mCurrent_forecast_fragment = current_fragment;
    this.mHourly_forecast_fragment = hourly_fragment;
    this.mDaily_forecast_fragment = daily_fragment;
    this.Titles = mTitles;
    this.NumbOfTabs = mNumbOfTabsumb;

}

//This method return the fragment for the every position in the View Pager
@Override
public Fragment getItem(int position) {

    if(position == 0) // if the position is 0 we are returning the First tab
    {
        return this.mCurrent_forecast_fragment;
    }
    else if (position == 1)            // As we are having 2 tabs if the position is now 0 it must be 1 so we are returning second tab
    {
        return this.mHourly_forecast_fragment;
    }else {
        return this.mDaily_forecast_fragment;
    }

}

// This method return the titles for the Tabs in the Tab Strip

@Override
public CharSequence getPageTitle(int position) {
    return Titles[position];
}

// This method return the Number of tabs for the tabs Strip

@Override
public int getCount() {
    return NumbOfTabs;
}
}

getLocation方法:

public void getLocation() {
    Log.d(TAG,"getLocation initiated...");
    locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
    if (isNetworkAvailable()) {
        //check if the if the location services are enabled
        if( !isLocationServicesEnabled()) {
            alertForNoLocationEnabled();
        }else {
              LocationRequest oneTimeOnStartRequest = LocationRequest.create()
                    .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                    .setNumUpdates(1)
                    .setInterval(0);
             onlyFirstTimeSubscription = locationProvider.getUpdatedLocation(oneTimeOnStartRequest)
            .subscribe(new Action1<Location>() {
                @Override
                public void call(Location location) {
                    Log.d(TAG, "Getting first location updates...");
                    MainActivity.this.latitude = location.getLatitude();
                    MainActivity.this.longitude = location.getLongitude();

                    reverseGeocodeObservable = locationProvider
                            .getReverseGeocodeObservable(location.getLatitude(), location.getLongitude(), 1);
                    getLocationName();
                    //check, only on create get location calls getForecast...
                    if (isFirstTimeLaunchingTheApp) {
                        getForecast(latitude, longitude);
                    }

                    onlyFirstTimeSubscription.unsubscribe();

                }
            });

        }

    } else {
        alertForNoInternet();
        Log.d(TAG, "Alert No Internet" + 366);
    }
}

getForecastmethod(这是抛出NPE的方法)

public void getForecast(double latitude, double longitude) {
    //scedule no response from the server task...
    mScheduledFuture = exec.schedule(mNotAbleToGetWeatherDataTask,12, TimeUnit.SECONDS);

    Log.d(TAG, "getForecast initiated...");
    String API_KEY = "API_KEY";
    String forecast = "https://api.forecast.io/forecast/" + API_KEY + "/" + latitude + "," + longitude + "?units=auto";

    if (isNetworkAvailable()) {

        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(forecast)
                .build();

        Call call = client.newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        toggleSwipeRefreshLayoutsOff();
                    }
                });
                //on response from the server cansel the noResponseFromServer task
//on response from the server cansel the noResponseFromServer task
                Log.d(TAG,"OnFailure_ scheduledFuture is CANCELED");
                mScheduledFuture.cancel(true);
                alertUserAboutError();
            }

            //when the call to the Okhttp library finishes, than calls this method:
            @Override
            public void onResponse(Response response) throws IOException {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        toggleSwipeRefreshLayoutsOff();
                    }
                });
                try {
                    String jsonData = response.body().string();
                    if (response.isSuccessful()) {
                        mForecast = parseForecastDetails(jsonData);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Log.d(TAG, "isSuccessful - run on UNI threth (update display)...");
                              mCurrent_forecast_fragment.updateDisplay();
                                mHourly_forecast_fragment.setUpHourlyFragment();
                                mDaily_forecast_fragment.setUpDailyFragment();
                                toggleSwipeRefreshLayoutsOff();
                                //set the isFirstTime to true so that the next refresh wont get location
                                isFirstTimeLaunchingTheApp = false;

                            }
                        });


                    } else {
                        alertUserAboutError();
                    }
                } catch (IOException | JSONException e) {
                    Log.e(TAG, "Exception caught:", e);
                }
                //on response from the server cansel the noResponseFromServer task
                Log.d(TAG,"OnResponse_ scheduledFuture is CANCELED");
                mScheduledFuture.cancel(true);
            }
        });
    } else {
        toggleSwipeRefreshLayoutsOff();
        alertForNoInternet();
        Log.d(TAG, "Alert No Internet" + 220);
        //is there is no internet cancel the noResponseFromServer task
        Log.d(TAG, "No internet _ scheduledFuture is CANCELED");
        mScheduledFuture.cancel(true);
    }
}

1 个答案:

答案 0 :(得分:2)

当我使用Fragment&amp; ViewPager时,我和你的情况相同...... 这是我弄清楚的方式:

 if (swipeRefreshLayout != null) {
     swipeRefreshLayout.setRefreshing(false);
 }

PS: 当我使用SwipeRefreshLayout它一个活动时,这个异常不会发生。有人可以提供更好的答案吗?