0

Я пробовал Android: How to restore the state of a stopped chronometer after rotation? и Fragments restore state on orientation changed, но они не применяются ко мне, потому что они либо не работают, либо я использую фрагменты.Хронометр и фрагмент, состояние восстановления после ротации

Также кажется, что любая ссылка на хронометр, кажется, бросает краху приложения.

Ошибка:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.elliot_labs.timetracker/com.elliot_labs.timetracker.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Chronometer.setBase(long)' on a null object reference 
         at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665) 
         at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) 
         at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4519) 
         at android.app.ActivityThread.-wrap19(ActivityThread.java) 
         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1483) 
         at android.os.Handler.dispatchMessage(Handler.java:102) 
         at android.os.Looper.loop(Looper.java:154) 
         at android.app.ActivityThread.main(ActivityThread.java:6119) 
         at java.lang.reflect.Method.invoke(Native Method) 
         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 
        Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Chronometer.setBase(long)' on a null object reference 
         at com.elliot_labs.timetracker.MainFragment.onCreate(MainFragment.java:95) 
         at android.support.v4.app.Fragment.performCreate(Fragment.java:2172) 
         at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1243) 
         at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1523) 
         at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1585) 
         at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:2827) 
         at android.support.v4.app.FragmentController.dispatchCreate(FragmentController.java:190) 
         at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:353) 
         at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:88) 
         at com.elliot_labs.timetracker.MainActivity.onCreate(MainActivity.java:30) 
         at android.app.Activity.performCreate(Activity.java:6679) 
         at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) 
         at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618) 
         at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)  
         at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4519)  
         at android.app.ActivityThread.-wrap19(ActivityThread.java)  
         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1483)  
         at android.os.Handler.dispatchMessage(Handler.java:102)  
         at android.os.Looper.loop(Looper.java:154)  
         at android.app.ActivityThread.main(ActivityThread.java:6119)  
         at java.lang.reflect.Method.invoke(Native Method)  
         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)  
         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)  
Application terminated. 

Код (fragment.java):

package com.elliot_labs.timetracker; 


import android.content.Context; 
import android.os.Bundle; 
import android.os.SystemClock; 
import android.support.v4.app.Fragment; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.Chronometer; 
import android.widget.Toast; 


/** 
* A simple {@link Fragment} subclass. 
*/ 
public class MainFragment extends Fragment implements OnClickListener { 

    Button toggleButton; 
    Button resetButton; 
    Chronometer chronometer; 
    long timeWhenStopped = 0; 
    boolean currentlyTiming = false; 

    public MainFragment() { 
     // Required empty public constructor 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     // Inflate the layout for this fragment 
     View v = inflater.inflate(R.layout.fragment_main, container, false); 

     toggleButton = (Button) v.findViewById(R.id.buttonToggleChronometer); 
     resetButton = (Button) v.findViewById(R.id.buttonReset); 
     chronometer = (Chronometer) v.findViewById(R.id.mainChronometer); 

     toggleButton.setOnClickListener(this); 
     resetButton.setOnClickListener(this); 

     return v; 
    } 

    public void toggleChronometer(){ 
     if(!currentlyTiming){ 
      chronometer.setBase(SystemClock.elapsedRealtime() + timeWhenStopped); 
      chronometer.start(); 
      toggleButton.setText("Stop"); 
      currentlyTiming = true; 
     } else { 
      timeWhenStopped = chronometer.getBase() - SystemClock.elapsedRealtime(); 
      chronometer.stop(); 
      toggleButton.setText("Start"); 
      currentlyTiming = false; 
     } 
    } 
    public void resetChronometer(){ 
     timeWhenStopped = 0; 
     chronometer.setBase(SystemClock.elapsedRealtime()); 
    } 


    @Override 
    public void onClick(View v) { 
     switch (v.getId()) { 
      case R.id.buttonToggleChronometer: 
       toggleChronometer(); 
       break; 
      case R.id.buttonReset: 
       resetChronometer(); 
       break; 
     } 
    } 


    @Override 
    public void onSaveInstanceState(Bundle outState) { 
     // Save myVar's value in saveInstanceState bundle 
     outState.putLong("time", chronometer.getBase()); 
     outState.putBoolean("isTiming", currentlyTiming); 

     super.onSaveInstanceState(outState); 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     // savedInstanceState is the bundle in which we stored myVar in onSaveInstanceState() method above 
     // savedInstanceState == null means that activity is being created a first time 
     if (savedInstanceState != null) { 
      chronometer.setBase(savedInstanceState.getLong("time")); 
      if (savedInstanceState.getBoolean("isTiming")) { 
       chronometer.start(); 
       currentlyTiming = savedInstanceState.getBoolean("isTiming"); 
      } 
     } 
    } 
} 

Код (mainActivity.java):

package com.elliot_labs.timetracker; 

import android.os.Bundle; 
import android.support.design.widget.NavigationView; 
import android.support.v4.view.GravityCompat; 
import android.support.v4.widget.DrawerLayout; 
import android.support.v7.app.ActionBarDrawerToggle; 
import android.support.v7.app.AppCompatActivity; 
import android.support.v7.widget.Toolbar; 
import android.view.MenuItem; 

public class MainActivity extends AppCompatActivity 
     implements NavigationView.OnNavigationItemSelectedListener { 

    NavigationView navigationView = null; 
    Toolbar toolbar = null; 

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

     // Starts the main fragment 
     MainFragment fragment = new MainFragment(); 
     android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 
     fragmentTransaction.replace(R.id.fragment_container, fragment); 
     fragmentTransaction.commit(); 

     toolbar = (Toolbar) findViewById(R.id.toolbar); 
     setSupportActionBar(toolbar); 

     navigationView = (NavigationView) findViewById(R.id.nav_view); 
     navigationView.setNavigationItemSelectedListener(this); 

     DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 
     ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
       this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); 
     drawer.setDrawerListener(toggle); 
     toggle.syncState(); 
    } 

    @Override 
    public void onBackPressed() { 
     DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 
     if (drawer.isDrawerOpen(GravityCompat.START)) { 
      drawer.closeDrawer(GravityCompat.START); 
     } else { 
      super.onBackPressed(); 
     } 
    } 


    @SuppressWarnings("StatementWithEmptyBody") 
    @Override 
    public boolean onNavigationItemSelected(MenuItem item) { 
     // Handle navigation view item clicks here. 
     int id = item.getItemId(); 

     if (id == R.id.nav_timer) { 
      MainFragment fragment = new MainFragment(); 
      android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 
      fragmentTransaction.replace(R.id.fragment_container, fragment); 
      fragmentTransaction.commit(); 
     } else if (id == R.id.nav_categories) { 
      CategoryFragment fragment = new CategoryFragment(); 
      android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 
      fragmentTransaction.replace(R.id.fragment_container, fragment); 
      fragmentTransaction.commit(); 
     } else if (id == R.id.nav_slideshow) { 

     } else if (id == R.id.nav_manage) { 

     } else if (id == R.id.nav_settings) { 
      SettingsFragment fragment = new SettingsFragment(); 
      android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 
      fragmentTransaction.replace(R.id.fragment_container, fragment); 
      fragmentTransaction.commit(); 
     } else if (id == R.id.nav_feedback) { 

     } else if (id == R.id.nav_help) { 

     } 

     DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 
     drawer.closeDrawer(GravityCompat.START); 
     return true; 
    } 
} 

Как я могу получить свое состояние после восстановления Я поворачиваю экран?

Спасибо!

ответ

1

onCreate вызывается перед onCreateView, поэтому поле chonometer равно null, просто восстановите хронометр в onCreateView и удалите код в onCreate.

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 
    // Inflate the layout for this fragment 
    View v = inflater.inflate(R.layout.fragment_main, container, false); 

    toggleButton = (Button) v.findViewById(R.id.buttonToggleChronometer); 
    resetButton = (Button) v.findViewById(R.id.buttonReset); 
    chronometer = (Chronometer) v.findViewById(R.id.mainChronometer); 

    toggleButton.setOnClickListener(this); 
    resetButton.setOnClickListener(this); 

    if (savedInstanceState != null) { 
     chronometer.setBase(savedInstanceState.getLong("time")); 
     if (savedInstanceState.getBoolean("isTiming")) { 
      chronometer.start(); 
      currentlyTiming = savedInstanceState.getBoolean("isTiming"); 
     } 
    } 

    return v; 
} 

Тогда в вашей деятельности conditionalize фрагмент заменить как:

if (savedInstanceState == null) { 
    MainFragment fragment = new MainFragment(); 
    FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 
    fragmentTransaction.replace(R.id.fragment_container, fragment); 
    fragmentTransaction.commit(); 
} 
+0

, к сожалению, это не работает. Система работает нормально: хронометр сбрасывается без сохранения значения при вращении или возобновления операции подсчета, если хронометр был запущен ранее. –

+0

Я проверил, что данные сохраняются должным образом (с использованием тостов). так что это проблема восстановления. –

+0

Я не уверен, где вы помещаете свои тосты, но я бы подтвердил, что вы на самом деле пытаетесь восстановить фрагмент и не заменять фрагмент через свою активность. Мы можем принять это в чате, если хотите. –