【问题标题】:Oreo - issue when rotating a device within a fragment with a listView (plus an asyncTask)Oreo - 使用 listView(加上 asyncTask)在片段中旋转设备时出现问题
【发布时间】:2023-03-19 22:05:02
【问题描述】:

我正在片段中创建一个列表视图并旋转设备。除了奥利奥外,它都很好用。

在运行时它不会抱怨,我会看到我的列表。然后我旋转,我再也看不到列表了。在 Oreo 之前,以下代码按原样工作:旋转设备后,我仍然可以正确看到我的列表。

为了让这个小例子有效,我必须在 onResume 中添加重新创建列表(代码注释掉,以便您可以使用低于 O 的版本进行测试)。

似乎我在旋转时错过了刷新视图的调用。我的 ListView 出现了一个空白屏幕。

我找不到一些解释如何在设备旋转时处理列表视图的 oreo 文档?或教程/示例?我使用列表/适配器机制。

奥利奥有什么变化?

片段代码:

public class ListFragment extends Fragment {
    private ListView listView;
    private List<ListItems> listItems;
    private ListAdapter listAdapter;


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

    @Override
    public void onResume() {
        Log.i("ROT","onResume");
/*
        String[] name = {"linux","win","android" };

        listItems = new ArrayList<>();
        listAdapter = new ListAdapter(getActivity().getApplicationContext(), listItems);
        listView = getActivity().findViewById(R.id.listview);

        for(int i=0;i<name.length;i++){
            ListItems items = new ListItems();
            items.setOsName(name[i]);
            listItems.add(items);
            listView.setAdapter(listAdapter);
        }
*/
        super.onResume();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        Log.i("ROT","onCreateView");
        super.onCreateView(inflater, container, savedInstanceState);
        return inflater.inflate(R.layout.layout_fragment, null);
    }

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

        Log.i("ROT","onActivityCreated");

        String[] name = {"linux","win","android" };

        listItems = new ArrayList<>();
        listAdapter = new ListAdapter(getActivity().getApplicationContext(), listItems);
        listView = getActivity().findViewById(R.id.listview);

        for(int i=0;i<name.length;i++){
            ListItems items = new ListItems();
            items.setOsName(name[i]);
            listItems.add(items);
            listView.setAdapter(listAdapter);
        }

    }

}

这是我的主要内容:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ListFragment listFragment = new ListFragment();
        ft.replace(R.id.content_frame, listFragment);
        ft.addToBackStack(null);
        ft.commit();
    }
}

项目创建:

    public class ListItems {
        private String osName;

        String getOsName(){
            return osName;
        }

        void setOsName(String s){
            osName = s;
        }
    }

适配器:

public class ListAdapter extends BaseAdapter {
    private static List<ListItems> listItems;
    private LayoutInflater layoutInflater;

    ListAdapter(Context context, List<ListItems> objects) {
        listItems = objects;
        layoutInflater = LayoutInflater.from(context);
    }

    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return listItems.size();
    }

    @Override
    public Object getItem(int position) {
        return listItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    private class ViewIPHolder {
        TextView os;
    }

    @SuppressLint("InflateParams")
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewIPHolder viewHolder;

        if(convertView == null) {
            viewHolder = new ViewIPHolder();

            convertView = layoutInflater.inflate(R.layout.layout_list, null);

            viewHolder.os = convertView.findViewById(R.id.osname);

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewIPHolder) convertView.getTag();
        }

        viewHolder.os.setText(listItems.get(position).getOsName());

        return convertView;
    }


}

最后是 xml 布局。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</LinearLayout>

layout_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/listview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="32dp"
        android:layout_marginEnd="32dp"
        android:layout_marginStart="32dp"
        android:layout_marginTop="32dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

layout_list.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/osname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="TextView"
        android:textColor="@color/colorPrimary"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

【问题讨论】:

  • logcat 中是否有一些警告/错误?
  • @rushi 我重温了...有一些。我将编辑 Q
  • 另外,如果listViewState为null或为空,是否可以记录,一般情况下,您可以按照developer.android.com/studio/debug/#startdebug进行逐步调试,然后准确提供oreo和其他行为不同的地方.
  • listViewstate 有一个值。如果没有,它会在 listTest.onRestoreInstanceState(listViewState); 上崩溃;并且相同的代码在其他 android 版本上运行良好。对于奥利奥,它的顺序与前 M 相同。
  • 你能一步步调试并找出差异吗?

标签: android listview android-8.0-oreo screen-rotation


【解决方案1】:

我不知道否决票背后的原因,但我已经在这个问题上努力工作,如果有人提出更好的解决方案,我愿意接受!

我的解决方案现在有效,并且依赖于在旋转后重置带有 setAdapter 在 onResume 中的列表视图。这是在 O 中发生变化的部分。除此之外,我在片段中使用 asyncTask 来构建列表。因此,当设备旋转时,setRetainInstance(true) 使其从 asyncTask 运行保存。棘手的部分是处理 onResume 中重绘/重新初始化的不同情况。

解决方法确实不如我的实际(O 之前)解决方案。我有一个简单/愚蠢的解决方案,效果很好,现在我需要实现一个复杂的代码(重新绘制列表视图很简单,但不处理异步任务)。

如果有 Android 人阅读这些行:

-O 确实是一项很棒的工作,但是要适应 api 更改的升级非常困难(例如:startforeground 服务、轮换)

-保持简单:当你有一个像我这样使用多个异步任务、线程的应用程序并且你想处理轮换时,这真的很不容易。

【讨论】:

  • 投反对票,因为您问题中的代码不完整,任何人都无法回答您。在这里你又说你做了一些事情并要求一个更好的解决方案,但没有人可以看到你的代码来了解问题所在,甚至为什么这个解决方案对你有用。您的片段或活动中的任何事件都可能包含一些代码,这些代码可能是回答您的关键。但是没有人可以看到因此没有人可以回答您。此外,您已经发送了布局,但是如果您的纵向和横向布局相同,则您的问题与任何布局都不相关。
  • 您需要发送所有涉及适配器的代码,并为listviewAsyncTask 的所有代码设置或更改适配器,如果您希望有人回答您。您正在搜索的旋转奥利奥没有特殊问题。
  • 当您使用多个线程出错并且运行代码 N 次时,您可能会得到正确的答案,但在 N+1 次您会看到该错误。您可能在 Pre Oreo Android 上遇到同样的错误,但不幸的是您没有看到它。
猜你喜欢
  • 1970-01-01
  • 2021-08-27
  • 2016-10-02
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多