【问题标题】:Data loss in onConfigrationChanged for Fragement on androidandroid中片段的onConfigurationChanged中的数据丢失
【发布时间】:2014-05-30 07:29:01
【问题描述】:

我正在开发带有操作栏选项卡的导航抽屉的应用程序。如果方向发生了变化,内容不应丢失。

我尝试在清单文件中添加一个条目:

android:configChanges="orientation|screenSize|keyboard|screenLayout"

它适用于 TextView 值,但不适用于 ImageViews。
我在 ListView 中有图像,它将从 Web 服务加载,如果方向已更改,则图像不应从 Web 服务重新加载。

我试图重写这个方法,但我不知道如何持久化数据。

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
}

谁能指导我找到解决方案?

我的适配器完整代码在这里

private ArrayList<Blog> blogs = new ArrayList<Blog>();
private ListView listView;
private ReadingsAdapter adapter;
private ProgressBar progressBar;
private TextView empty;

public static ReadingsTab newInstance(Category category) {
    ReadingsTab fragment = new ReadingsTab();
    Bundle args = new Bundle();
    args.putSerializable("Category", category);
    fragment.setArguments(args);
    return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        final Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.tab_readings, container,
            false);
    setRetainInstance(true);
    listView = (ListView) rootView.findViewById(R.id.listView);
    progressBar = (ProgressBar) rootView
            .findViewById(R.id.reading_tab_progressbar);
    empty = (TextView) rootView.findViewById(R.id.empty);
    progressBar.setVisibility(View.VISIBLE);
    loadBlog(getActivity());
    return rootView;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setRetainInstance(true);
}

public void loadBlog(final Activity activity) {
    progressBar.setVisibility(View.VISIBLE);
    MultipartEntity parms = new MultipartEntity();
    try {
        parms.addPart("catid", new StringBody(((Category) getArguments()
                .getSerializable("Category")).getId()));
        Log.d("Category Id",
                ((Category) getArguments().getSerializable("Category"))
                        .getId());
        new JSONParser(getActivity(), Server.FUNC_GET_LOAD_READING,
                new RequestListener() {
                    @Override
                    public void onRequestSuccess(JSONObject jsonObject) {
                        progressBar.setVisibility(View.GONE);
                        try {
                            if ("success".equalsIgnoreCase(jsonObject
                                    .getString("status"))) {
                                JSONArray data = jsonObject
                                        .getJSONArray("data");
                                for (int i = 0; i < data.length(); i++) {
                                    blogs.add(Blog.fromJson(data
                                            .getJSONObject(i)));
                                }
                                adapter = new ReadingsAdapter(activity,
                                        blogs);
                                listView.setAdapter(adapter);
                            } else {
                                listView.setEmptyView(empty);
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onRequestFailure(Error error) {
                        progressBar.setVisibility(View.GONE);
                        Helper.failureErrorMessage(getActivity(), error);
                    }
                }).execute(parms);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

}

}

博客是一个类

package com.griffin.android.schoolapp.adapter;

导入 org.json.JSONException; 导入 org.json.JSONObject;

公开课博客{

private String id;
private String title;
private String image;
private String url;

public Blog(String id, String title, String image,String url) {
    super();
    this.id = id;
    this.title = title;
    this.image = image;
    this.url = url;
}

public static Blog fromJson(JSONObject object) throws JSONException {
    return new Blog(object.getString("id"), object.getString("title"),object.getString("image"),
            object.getString("url"));
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public String getImage() {
    return image;
}

public void setImage(String image) {
    this.image = image;
}

public String getUrl() {
    return url;
}

public void setUrl(String url) {
    this.url = url;
}

@Override
public String toString() {
    return title;
}

}

适配器是 公共类 ReadingsAdapter 扩展 ArrayAdapter { 私人最终 LayoutInflater mInflater; 受保护的 ImageLoader imageLoader;

public ReadingsAdapter(Context context, List<Blog> data) {
    super(context, R.layout.readings_list_item, data);
    mInflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    imageLoader = ImageLoader.getInstance();
    imageLoader.init(ImageLoaderConfiguration.createDefault(context));
}

/**
 * Populate new items in the list.
 */
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view;

    if (convertView == null) {
        view = mInflater.inflate(R.layout.readings_list_item,
                parent, false);
    } else {
        view = convertView;
    }

    final Blog item = getItem(position);
    final ImageView contentimage = (ImageView)view.findViewById(R.id.contentImage);
    ((TextView) view.findViewById(R.id.title)).setText(item.getTitle());
    final ProgressBar imageloading = (ProgressBar)view.findViewById(R.id.imageloading);

    ImageLoader.getInstance().displayImage(item.getImage(), contentimage, new ImageLoadingListener() {

        @Override
        public void onLoadingStarted(String imageUri, View view) {
            imageloading.setVisibility(View.VISIBLE);
            contentimage.setVisibility(View.GONE);
        }

        @Override
        public void onLoadingFailed(String imageUri, View view,
                FailReason failReason) {
            imageloading.setVisibility(View.GONE);
            contentimage.setVisibility(View.VISIBLE);
        }

        @Override
        public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
            imageloading.setVisibility(View.GONE);  
            contentimage.setVisibility(View.VISIBLE);
            contentimage.setImageBitmap(loadedImage);
        }

        @Override
        public void onLoadingCancelled(String imageUri, View view) {
            imageloading.setVisibility(View.GONE);  
            contentimage.setVisibility(View.VISIBLE);

        }
    });
    contentimage.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            String txt = item.getUrl();
            Intent intent = new Intent(getContext(),WebPage.class);
            intent.putExtra("url", txt);
            getContext().startActivity(intent);
        }
    });
    return view;
}

}

【问题讨论】:

  • 你已经阻止它改变方向了..

标签: android configuration screen-orientation


【解决方案1】:

您应该尝试 Volley:https://github.com/mcxiaoke/android-volley 这是一款适用于 Android 的网络应用。您可以使用它来缓存加载的图像。

可以在此处找到一些示例:https://github.com/PareshMayani/Android-Volley-Example

【讨论】:

  • 补充一点:第一次使用 Volley 时,缓存中不存在图像,Volley 将从您的服务器下载图像。然后,当用户旋转手机时,图像存在,Volley 将使用现有副本。另一个(更简单)的选择是毕加索github.com/square/picasso
【解决方案2】:
android:configChanges="orientation|screenSize|keyboard|screenLayout"

您所做的只是阻止 Android 重新调用 onCreate(),方法是调用

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
}

可悲的是,你什么都不做:)。 如果您使用的是片段,您可以将 setReinstance 设置为 true 以保存状态,请记住删除 AndroidManifest.xml 中的 android:configChanges。这是一个不好的做法 或者您可以将状态保存在 onDestroyView() 并将它们保存回 onCreateView() - 应该检查 savedInstance 是否为空...... 对于任务,我认为最好在活动中保留弱引用。

【讨论】:

  • 我必须在哪里给 setRetainInstance(true);在 onCreateView()??
  • 是的,在onCreateView中,你可以设置这个。这将防止再次创建片段。但一个副作用是,方向布局将不会更新(如果您将布局保存在 layout-land/layout-port-... 因为据我所知,android 会在 onCreate() 中自动加载)
  • 我给出了这样的结果,但它不起作用 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, final Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.tab_readings, container, false) ;设置保留实例(真); listView = (ListView) rootView.findViewById(R.id.listView); progressBar = (ProgressBar) rootView .findViewById(R.id.reading_tab_progressbar); empty = (TextView) rootView.findViewById(R.id.empty); progressBar.setVisibility(View.VISIBLE); loadBlog(getActivity());返回根视图; }
  • @John 有什么例外。 loadBlog() 函数会填充空文本视图吗?如果你不介意,你能分享一些代码sn-p吗?
  • 这里的图片是:您有一个导航抽屉,其中包含一些项目 ReadingAdapter 并且数据将被加载到 ReadingTabs 中。如果旋转屏幕,ReadingTabs 中的内容会丢失。 1.我建议你写下流程图,找出哪个变量保存了页面内容。我看到了,您在单击某个项目时调用 WebPage 活动来开始浏览数据。 2.在onDestroyView中,将内容视图保存到bunndle中,你可能需要覆盖onSaveInstanceState(Bundle)和onCreateView()你从saveInstanceState中获取数据(请检查null)
【解决方案3】:

让我建议一种不同的方法:

  1. 创建一个ContentProvider 来保存您的数据(用于图像存储 网址)
  2. 使用IntentService 下载数据并插入 进入 ContentProvider
  3. 使用CursorLoader 显示数据 在你的片段/活动中
  4. 要显示图像,请使用Picasso(在ViewBinder 内)

  • 您的数据将保存在本地数据库中,当您旋转 手机不会丢失。
  • IntentService 在后台线程中运行 独立于 Activity,因此旋转手机不会停止它
  • CursorLoader 将在后台线程中加载数据,以便您的 UI 不会被屏蔽
  • Picasso 将在第一次缓存图像时 已加载,因此旋转后不会有网络调用

你可以在这里找到一个工作代码:https://github.com/twitter-university/LearningAndroidYamba/tree/master/Yamba-8

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多