java - Android onSaveInstanceState 未获取类变量

标签 java android android-fragments

我正在尝试将 ListView 数据保存在 onSaveInstanceState 中。由于某种原因,当我在 onSaveInstanceState 中调用类变量时,它没有填充正确的数据。

public class ArtistTopTen extends Fragment {

    private ListView artistTopTen;

    private String artistId;

    private Tracks listTracks;

    private exposed.coding.android_nano.Adapters.ArtistTopTen topTenListAdapter;

    private SpotifyApi spotifyApi;
    private SpotifyService spotifyService;

    private MusicPlayerDialogFragment musicPlayerDialogFragment;


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

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

        if(getActivity().findViewById(R.id.topten_container) == null) {
            getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }

        // Start the service
        getActivity().startService(new Intent(getActivity(), Music.class));

        if(savedInstanceState == null) {
            try {
                if (getActivity().getIntent().hasExtra("id")) {
                    artistId = getActivity().getIntent().getStringExtra("id");
                } else {
                    artistId = getArguments().getString("artistid");
                }
            } catch (Exception e) {
                Log.e("ERROR", e.toString());
            }
        }else {
            Log.e("NOTICE", "SavedInstanceState has data");
        }

        if(artistId != null) {

            artistTopTen = (ListView) view.findViewById(R.id.artist_top_ten);
            topTenListAdapter = new exposed.coding.android_nano.Adapters.ArtistTopTen(getActivity(), listTracks);

            spotifyApi = new SpotifyApi();
            spotifyService = spotifyApi.getService();

            SharedPreferences sharedPreferences = getActivity().getPreferences(Context.MODE_PRIVATE);

            HashMap country = new HashMap<String, Object>();

            if (sharedPreferences.getString("country", "us").length() != 0) {
                country.put("country", sharedPreferences.getString("country", "us").toString());
            } else {
                country.put("country", "us");
            }

            spotifyService.getArtistTopTrack(artistId, country, new Callback<Tracks>() {
                @Override
                public void success(Tracks tracks, Response response) {
                    listTracks = tracks;
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            notifyAdapter();
                        }
                    });
                }

                @Override
                public void failure(RetrofitError error) {
                    Toast.makeText(view.getContext(), "Somthing went wrong", Toast.LENGTH_LONG).show();
                }
            });

            artistTopTen.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Intent intent = new Intent(":MediaPlayerUpdateList");
                intent.putExtra("tracks", new ParcelablesTracks(listTracks, position));
                getActivity().sendBroadcast(intent);

                if(getActivity().findViewById(R.id.topten_container) != null) {
                    musicPlayerDialogFragment = new MusicPlayerDialogFragment();
                    musicPlayerDialogFragment.setCancelable(false);
                    musicPlayerDialogFragment.show(getFragmentManager(), "fragment_music_player");
                }else {
                    intent = new Intent(getActivity(), MusicPlayerActivity.class);
                    intent.putExtra("returning", false);
                    startActivity(intent);
                }
                }
            });
        }
    if(savedInstanceState != null) {

    }

    return view;
}

private void notifyAdapter() {
    Log.e("First Track Name - SHOWING", listTracks.tracks.get(0).name);
    topTenListAdapter.setListTracks(listTracks);

    if(artistTopTen.getAdapter() == null) {
        artistTopTen.setAdapter(topTenListAdapter);
    }else {
        topTenListAdapter.notifyDataSetChanged();
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    Log.e("First Track Name - NOT SHOWING", listTracks.tracks.get(0).name);
    //outState.putParcelable("list", new ParcelablesTracks(listTracks, 0));
    super.onSaveInstanceState(outState);
}
}

如果您查看函数 notifiyAdapter(),您可以看到我正在打印歌曲的名称:

Log.e("First Track Name - SHOWING", listTracks.tracks.get(0).name);

但是,当调用 onSaveInstanceState 时,每当我尝试访问轨道时都会出错:

Log.e("First Track Name - NOT SHOWING", listTracks.tracks.get(0).name);

错误:

07-16 10:12:07.759  29091-29091/exposed.coding.android_nano E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: exposed.coding.android_nano, PID: 29091
    java.lang.NullPointerException: Attempt to read from field 'java.util.List kaaes.spotify.webapi.android.models.Tracks.tracks' on a null object reference
            at exposed.coding.android_nano.Fragments.ArtistTopTen.onSaveInstanceState(ArtistTopTen.java:162)
            at android.app.Fragment.performSaveInstanceState(Fragment.java:2198)
            at android.app.FragmentManagerImpl.saveFragmentBasicState(FragmentManager.java:1605)
            at android.app.FragmentManagerImpl.saveAllState(FragmentManager.java:1662)
            at android.app.Activity.onSaveInstanceState(Activity.java:1367)
            at android.app.Activity.performSaveInstanceState(Activity.java:1298)
            at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1288)
            at android.app.ActivityThread.callCallActivityOnSaveInstanceState(ActivityThread.java:3961)
            at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3924)
            at android.app.ActivityThread.access$900(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1309)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5257)
            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:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

我对 Android 开发还很陌生,但我正在使用相同的过程将数据保存在另一个 fragment 中,并且它工作得很好。我不确定这里发生了什么。

仓库:https://github.com/Bioto/Android-Nano-Degree-Project1.2

编辑:

设置列表轨道:

E/Setting listTracks﹕ ArtistTopTen{98c918d #2 id=0x7f0c0051}

onSaveInstanceState:

E/onSaveInstanceState()﹕ ArtistTopTen{3b7de284 #1 id=0x7f0c0051}

最佳答案

编辑:所以似乎发生的情况是接收响应的 Fragment 实例与保存其状态的 Fragment 实例不同。这可能是由于您处理 Spotify 请求的回调的方式所致。

我认为正在发生的事情的总体思路是:

  1. fragment 98c918d 已创建
  2. 使用回调的匿名实现将请求发送到请求轨道,该回调保存对 fragment 98c918d 的引用。
  3. 发生配置更改(屏幕旋转),并且 fragment 98c918d 被破坏。
  4. 已创建 fragment (3b7de284) 的新实例。
  5. 请求完成, fragment 98c918d 收到结果。
  6. 发生另一次配置更改,3b7de284 尝试保存其状态,但实际上没有数据。

因此,您实际上看到的是内存泄漏(旧的 Fragment 一直保留到请求完成为止)。我建议研究 Loader 框架来处理跨配置更改的网络请求。或者,将该工作放入 IntentService 中,在加载后保留轨道,然后广播该事件。如果 Fragment 仍然存在并接收到广播,则它可以加载新结果。否则,当接下来调用 onStart() 或 onResume() 时,它可以查找任何现有结果(可能在 fragment 未监听时已加载)。

<小时/>

Attempt to read from field 'java.util.List kaaes.spotify.webapi.android.models.Tracks.tracks' on a null object reference

listTracks 为空。因此调用listTracks.tracks将导致NullPointerException。似乎在某些情况下,listTracks 从未被分配(它仅在 getArtistTopTracks()success() 方法中分配,所以如果由于任何原因失败,它永远不会被分配。在这种情况下,将该行包装在空检查中可能就足够了;即:

if (listTracks != null) {
    // do stuff with listTracks
}

关于java - Android onSaveInstanceState 未获取类变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31460567/

相关文章:

java - 将 int[] 转换为 char[] 无法正常工作

java - Android ClassCastException 与 TreeMap 比较

android - 何时以及如何防止 Android 中的上帝 Activity

Android - 从 Activity 向上导航到 Fragment

Android:根据所选 fragment 更改菜单

java - 更改 slider 刻度的颜色

java - 只需要一些关于 .equals 的启示

java - 犀牛怎么了?它仍在积极开发中吗?

android - 如何改变KeyPreview的高度

android - 如果用户有相机设置来存储位置数据,但手机位置已关闭,是否会存储位置?