onCreateLoader不叫时,方向更改 [英] onCreateLoader not called when orientation changes

查看:152
本文介绍了onCreateLoader不叫时,方向更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是基本相同的这一个:<一href="http://stackoverflow.com/questions/7810019/sometimes-dont-get-oncreateloader-callback-after-calling-initloader">Sometimes不要onCreateLoader调用回调后initLoader

我有2 ListFragments 包含在一个 ViewPager 。他们首先被装入好的,但是当我改变方向, initLoader 方法不叫 onCreateLoader 。 不过,如果我恢复到初始取向,一切又是罚款。

下面是我的code为 FragmentActivity

 进口java.util.Locale中;

进口com.d.camera.R;
进口com.d.camera.R.id;
进口com.d.camera.R.layout;
进口com.d.camera.R.menu;
进口com.d.camera.R.string;

进口android.app.ActionBar;
进口android.app.FragmentTransaction;
进口android.os.Bundle;
进口android.support.v4.app.Fragment;
进口android.support.v4.app.FragmentActivity;
进口android.support.v4.app.FragmentManager;
进口android.support.v4.app.FragmentPagerAdapter;
进口android.support.v4.app.NavUtils;
进口android.support.v4.view.ViewPager;
进口android.view.Gravity;
进口android.view.LayoutInflater;
进口android.view.Menu;
进口android.view.MenuItem;
进口android.view.View;
进口android.view.ViewGroup;
进口android.widget.TextView;

公共类HistoryFragments扩展FragmentActivity工具
    ActionBar.TabListener {

/ **
 *在{@link android.support.v4.view.PagerAdapter},将提供
 *对于每个部分的片段。我们使用
 * {@link android.support.v4.app.FragmentPagerAdapter}衍生物,它
 *将让每一个加载的片段记忆。如果这成为过记忆
 *密集,它可能是最好切换到
 * {@link android.support.v4.app.FragmentStatePagerAdapter}。
 * /
SectionsPagerAdapter mSectionsPagerAdapter;

/ **
 *在{@link ViewPager}将承载部分内容。
 * /
ViewPager mViewPager;

@覆盖
保护无效的onCreate(包savedInstanceState){
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.activity_history_fragments);

    //设置操作栏。
    最后的动作条动作条= getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    actionBar.setDisplayShowTitleEnabled(假);
    actionBar.setDisplayShowHomeEnabled(假);

    //创建将返回一个片段为三个的适配器
    //应用程序的主要部分。
    mSectionsPagerAdapter =新SectionsPagerAdapter(
            getSupportFragmentManager());

    //设置的ViewPager与部分适配器。
    mViewPager =(ViewPager)findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);

    //当不同部分之间的刷卡,选择相应的
    //标签。我们也可以使用ActionBar.Tab#选择()要做到这一点,如果我们有
    //引用的标签。
    mViewPager
            .setOnPageChangeListener(新ViewPager.SimpleOnPageChangeListener(){
                @覆盖
                公共无效onPageSelected(INT位置){
                    actionBar.setSelectedNavigationItem(位置);
                }
            });

    //对于每个应用程序的章节中,添加一个标签,操作栏。
    的for(int i = 0; I&LT; mSectionsPagerAdapter.getCount();我++){
        //创建与对应于由所定义的页标题文本标签
        //适配器。同时,指定此活动的对象,它实现
        //该TabListener界面,回调(监听程序)进行时
        //这个选项卡中选择。
        actionBar.addTab(actionBar.newTab()
                .setText(mSectionsPagerAdapter.getPageTitle(I))
                .setTabListener(本));
    }
}

@覆盖
公共布尔onCreateOptionsMenu(功能菜单){
    //充气菜单;这增加了项目操作栏,如果它是present。
    。getMenuInflater()膨胀(R.menu.history,菜单);
    返回true;
}

@覆盖
公共无效onTabSelected(ActionBar.Tab选项卡,
        FragmentTransaction fragmentTransaction){
    //当选择给定的标签,切换到对应页面
    //该ViewPager。
    mViewPager.setCurrentItem(tab.getPosition());
}

@覆盖
公共无效onTabUnselected(ActionBar.Tab选项卡,
        FragmentTransaction fragmentTransaction){
}

@覆盖
公共无效onTabReselected(ActionBar.Tab选项卡,
        FragmentTransaction fragmentTransaction){
}

/ **
 * A {@link FragmentPagerAdapter}返回对应的片段
 *章节/标签/页之一。
 * /
公共类SectionsPagerAdapter扩展FragmentPagerAdapter {

    公共SectionsPagerAdapter(FragmentManager FM){
        超(FM);
    }

    @覆盖
    公共片段的getItem(INT位置){
        //的getItem被称为实例化片段给定的页面。
        //返回一个DummySectionFragment(定义为静态内部类
        下图)与页面数量作为其唯一的参数//。

        片段片段= NULL;

        如果(位置== 0){
            片段=新HistoryListFragment();
        } 其他{
            片段=新HistoryElemListFragment();

        }
        返回片段;
    }

    @覆盖
    公众诠释getCount将(){
        //显示2总页数。
        返回2;
    }

    @覆盖
    公共CharSequence的getPageTitle(INT位置){
        区域设置L = Locale.getDefault();
        开关(位置){
        情况下0:
            返回的getString(R.string.title_section1).toUpperCase(升);
        情况1:
            返回的getString(R.string.title_section2).toUpperCase(升);
        案例2:
            返回的getString(R.string.title_section3).toUpperCase(升);
        }
        返回null;
    }
}


}
 

和这里是之一code中的 ListFragments

 进口的java.io.File;
进口java.text.SimpleDateFormat的;
进口java.util.Date;
进口java.util.Locale中;

进口com.d.camera.HistoryContentProvider;
进口com.d.camera.HistoryDatabase;
进口com.d.camera.HistoryEntry;
进口com.d.camera.R;

进口android.app.LoaderManager;
进口android.content.Context;
进口android.content.CursorLoader;
进口android.content.Intent;
进口android.content.Loader;
进口android.database.Cursor;
进口android.net.Uri;
进口android.os.Bundle;
进口android.support.v4.app.ListFragment;
进口android.util.Log;
进口android.view.ContextMenu;
进口android.view.LayoutInflater;
进口android.view.Menu;
进口android.view.MenuItem;
进口android.view.View;
进口android.view.ContextMenu.ContextMenuInfo;
进口android.view.ViewGroup;
进口android.widget.FilterQueryProvider;
进口android.widget.ListView;
进口android.widget.SimpleCursorAdapter;
进口android.widget.TextView;
进口android.widget.AdapterView.AdapterContextMenuInfo;
进口android.widget.SimpleCursorAdapter.ViewBinder;

公共类HistoryListFragment扩展ListFragment实现LoaderManager.LoaderCallbacks&LT;光标&GT; {

    私有静态最终诠释LOADER_ID = 0×01;
    私有静态最终诠释DELETE_ID = Menu.FIRST + 1;
    公共静态最后弦乐SECTION_NUMBER =section_number标;
    私人SimpleCursorAdapter适配器;
    私人上下文的背景下;

    公共HistoryListFragment(){
    }


    @覆盖
    公共无效onActivityCreated(包savedInstanceState){
        super.onActivityCreated(savedInstanceState);
        上下文= getActivity();
        fillData();
        registerForContextMenu(getListView());
    }

    @覆盖
    公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,
            捆绑savedInstanceState){
        查看rootView = inflater.inflate(R.layout.list_fragment,集装箱,假);
        返回rootView;
    }




    私人无效fillData(){
        。getActivity()getLoaderManager()initLoader(LOADER_ID,空,这一点)。
        的String []从=新的String [] {
                HistoryDatabase.MOBILE_RESULT,
                HistoryDatabase.FP_TIMESTAMP,
                HistoryDatabase.PRODUCT_IMAGE,};

        INT []到=新INT [] {
                R.id.resultImage,
                R.id.time,
                R.id.productImage,};

        适配器=新SimpleCursorAdapter(背景下,R.layout.history_element,空,从到,0);


        //我们要监视列表的设置和时间变化毫秒到可读的格式。*******
        adapter.setViewBinder(新ViewBinder(){
            公共布尔setViewValue(视图V,光标C中,int参数:columnIndex){

                如果(参数:columnIndex == c.getColumnIndex(HistoryDatabase.FP_TIMESTAMP))
                {
                    龙timeInMilli = c.getLong(c.getColumnIndex(HistoryDatabase.FP_TIMESTAMP));
                    SimpleDateFormat的SDF =新的SimpleDateFormat(EEE MMM DD HH:MM:SSžYYYY,Locale.ENGLISH);
                    字符串formatedTime = sdf.format(新日期(timeInMilli));
                    TextView的电视=(TextView中)V;
                    tv.setText(formatedTime);
                    返回true;
                }
                返回false;
            }
        });
        // ********** *********************************************

        setListAdapter(适配器);

  }


    @覆盖
    公共无效onCreateContextMenu(文本菜单菜单,视图V,
            ContextMenuInfo menuInfo){
        super.onCreateContextMenu(菜单,V,menuInfo);
        menu.add(0,DELETE_ID,0,R.string.menu_delete);
    }

    @覆盖
    公共布尔onContextItemSelected(菜单项项){
        // ...
        返回super.onContextItemSelected(项目);
    }



    //反应到菜单选择
    @覆盖
    公共布尔onOptionsItemSelected(菜单项项){
        // ...
        返回super.onOptionsItemSelected(项目);
    }


    @覆盖
    公共装载机&LT;光标&GT; onCreateLoader(INT ID,捆绑参数){
        的String []投影=新的String [] {HistoryDatabase.ID,HistoryDatabase.MOBILE_RESULT,HistoryDatabase.MOBILE_SCORE,HistoryDatabase.FP_TIMESTAMP,HistoryDatabase.PRODUCT_IMAGE,HistoryDatabase.QR_MESSAGE};
        返回新CursorLoader(背景下,HistoryContentProvider.CONTENT_URI,投影,NULL,NULL,HistoryDatabase.ID +降序);
    }

    @覆盖
    公共无效onLoadFinished(装载机&LT;光标&GT; cursorLoader,光标光标){
        adapter.swapCursor(光标);
    }

    @覆盖
    公共无效onLoaderReset(装载机&LT;光标&GT; cursorLoader){
        adapter.swapCursor(空);
    }

    公共无效onListItemClick(ListView的L,视图V,INT位置,长的id){
        //做一点事
    }
}
 

我已经试过这些方法 destroyLoader restartLoader 不同的组合,但没有任何成功...是否任何人都知道这是怎么回事?

修改 使用 LoaderManager.enableDebugLogging(真)我得到以下日志: 第一负载给出了这样的

  initLoader在LoaderManager {在HistoryFragments {424a7950 42507c68}}参数:args = NULL
   首发:{的LoaderInfo#424a7da0 1:CursorLoader {42faae18}}
   创建新的装载机的LoaderInfo {424a7da0#1:CursorLoader {42faae18}}
 initLoader在LoaderManager {在HistoryFragments {424a7950 42507c68}}参数:args = NULL
   首发:{的LoaderInfo#42e5a280 2:CursorLoader {42e5a2f8}}
   创建新的装载机的LoaderInfo {42e5a280#2:CursorLoader {42e5a2f8}}
 的onLoadComplete:{的LoaderInfo#424a7da0 1:CursorLoader {42faae18}}
   onLoadFinished在CursorLoader {42faae18 ID = 1}:CursorWrapperInner {42506d58}
 的onLoadComplete:{的LoaderInfo#42e5a280 2:CursorLoader {42e5a2f8}}
   onLoadFinished在CursorLoader {42e5a2f8 ID = 2}:{CursorWrapperInner 42fab1f0}
 

然后当我改变方向,它给这个

 护在LoaderManager {424a7950在HistoryFragments {42507c68}}
   护:{的LoaderInfo#42e5a280 2:CursorLoader {42e5a2f8}}
   护:{的LoaderInfo#424a7da0 1:CursorLoader {42faae18}}
 销毁不活动的LoaderManager {在HistoryFragments 424a7950 {42507c68}}
 initLoader在LoaderManager {在HistoryFragments {424a7950 426d0af0}}参数:args = NULL
   重新使用现有的装载机的LoaderInfo {424a7da0#1:CursorLoader {42faae18}}
 initLoader在LoaderManager {在HistoryFragments {424a7950 426d0af0}}参数:args = NULL
   重新使用现有的装载机的LoaderInfo {42e5a280#2:CursorLoader {42e5a2f8}}
 在LoaderManager成品护{424a7950在HistoryFragments {426d0af0}}
   成品护:{的LoaderInfo#42e5a280 2:CursorLoader {42e5a2f8}}
   停止:{的LoaderInfo#42e5a280 2:CursorLoader {42e5a2f8}}
   成品护:{的LoaderInfo#424a7da0 1:CursorLoader {42faae18}}
   停止:{的LoaderInfo#424a7da0 1:CursorLoader {42faae18}}
 

然后,当我再回到最初的方向,我得到一个错误,但随后一切都被再次加载:

 保留在LoaderManager {在HistoryFragments {424a7950 426d0af0}}
 调用doRetain时,不启动:LoaderManager {424a7950在HistoryFragments {426d0af0}}
 java.lang.RuntimeException的:在这里
    在android.app.LoaderManagerImpl.doRetain(LoaderManager.java:795)
    在android.app.Activity.performStop(Activity.java:5497)
    在android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3591)
    在android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3654)
    在android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3854)
    在android.app.ActivityThread.access $ 800(ActivityThread.java:159)
    在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1322)
    在android.os.Handler.dispatchMessage(Handler.java:99)
    在android.os.Looper.loop(Looper.java:176)
    在android.app.ActivityThread.main(ActivityThread.java:5419)
    在java.lang.reflect.Method.invokeNative(本机方法)
    在java.lang.reflect.Method.invoke(Method.java:525)
    在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:1046)
    在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
    在dalvik.system.NativeStart.main(本机方法)
 销毁活动在LoaderManager {在HistoryFragments 424a7950 {426d0af0}}
   销毁:{的LoaderInfo#42e5a280 2:CursorLoader {42e5a2f8}}
   CH375复位:{的LoaderInfo#42e5a280 2:CursorLoader {42e5a2f8}}
   销毁:{的LoaderInfo#424a7da0 1:CursorLoader {42faae18}}
   CH375复位:{的LoaderInfo#424a7da0 1:CursorLoader {42faae18}}
 销毁不活动的LoaderManager {在HistoryFragments 424a7950 {426d0af0}}
 销毁活动在LoaderManager {在HistoryFragments 424a7950 {426d0af0}}
 销毁不活动的LoaderManager {在HistoryFragments 424a7950 {426d0af0}}
 initLoader在LoaderManager {在HistoryFragments {4271b070 42702c68}}参数:args = NULL
   首发:{的LoaderInfo#4271b690 1:CursorLoader {4271b708}}
   创建新的装载机的LoaderInfo {4271b690#1:CursorLoader {4271b708}}
 initLoader在LoaderManager {在HistoryFragments {4271b070 42702c68}}参数:args = NULL
   首发:{的LoaderInfo#42720ab8 2:CursorLoader {42720b30}}
   创建新的装载机的LoaderInfo {42720ab8#2:CursorLoader {42720b30}}
 的onLoadComplete:{的LoaderInfo#4271b690 1:CursorLoader {4271b708}}
   onLoadFinished在CursorLoader {4271b708 ID = 1}:CursorWrapperInner {4271f518}
 的onLoadComplete:{的LoaderInfo#42720ab8 2:CursorLoader {42720b30}}
   onLoadFinished在CursorLoader {42720b30 ID = 2}:{CursorWrapperInner 427222c0}
 

日志然后重复自己进一步的方向改变。为什么在 CursorLoaders 被停止,并没有重新启动?我该如何重新启动呢?

编辑2

我固定我的问题感谢Nikis街,但他提出了一个有趣的问题: 为什么是 android.app.LoaderManager 不工作?

下面是使用支持版本后,日志。 第一负载给出了同样的事情上面,但方向改变后,再使用光标不会阻止他们。

 护在LoaderManager {43945c70在HistoryFragments {427cb468}}
   护:{的LoaderInfo#439d8a58 2:CursorLoader {439d8ad0}}
   护:{的LoaderInfo#432dea88 1:CursorLoader {4393ad48}}
 销毁不活动的LoaderManager {在HistoryFragments 43945c70 {427cb468}}
 initLoader在LoaderManager {在HistoryFragments {43945c70 438f0a38}}参数:args = NULL
   重新使用现有的装载机的LoaderInfo {432dea88#1:CursorLoader {4393ad48}}
 initLoader在LoaderManager {在HistoryFragments {43945c70 438f0a38}}参数:args = NULL
   重新使用现有的装载机的LoaderInfo {439d8a58#2:CursorLoader {439d8ad0}}
 开始在LoaderManager {在HistoryFragments 43945c70 {438f0a38}}
 在LoaderManager成品护{43945c70在HistoryFragments {438f0a38}}
   成品护:{的LoaderInfo#439d8a58 2:CursorLoader {439d8ad0}}
   onLoadFinished在CursorLoader {439d8ad0 ID = 2}:{CursorWrapperInner 43952be0}
   成品护:{的LoaderInfo#432dea88 1:CursorLoader {4393ad48}}
   onLoadFinished在CursorLoader {4393ad48 ID = 1}:CursorWrapperInner {43952fa8}
 

当我再回到最初的方向,这是结果:

 护在LoaderManager {43945c70在HistoryFragments {438f0a38}}
   护:{的LoaderInfo#439d8a58 2:CursorLoader {439d8ad0}}
   护:{的LoaderInfo#432dea88 1:CursorLoader {4393ad48}}
 销毁不活动的LoaderManager {在HistoryFragments 43945c70 {438f0a38}}
 initLoader在LoaderManager {在HistoryFragments {43945c70 432cab50}}参数:args = NULL
   重新使用现有的装载机的LoaderInfo {432dea88#1:CursorLoader {4393ad48}}
 initLoader在LoaderManager {在HistoryFragments {43945c70 432cab50}}参数:args = NULL
   重新使用现有的装载机的LoaderInfo {439d8a58#2:CursorLoader {439d8ad0}}
 开始在LoaderManager {在HistoryFragments 43945c70 {432cab50}}
 在LoaderManager成品护{43945c70在HistoryFragments {432cab50}}
   成品护:{的LoaderInfo#439d8a58 2:CursorLoader {439d8ad0}}
   onLoadFinished在CursorLoader {439d8ad0 ID = 2}:{CursorWrapperInner 43952be0}
   成品护:{的LoaderInfo#432dea88 1:CursorLoader {4393ad48}}
   onLoadFinished在CursorLoader {4393ad48 ID = 1}:CursorWrapperInner {43952fa8}
 

解决方案

您可以使用 LoaderManager.enableDebugLogging(真)来调试器行为,或者你可以尝试使用 getSupportLoadermanager()而不是 getLoaderManager()

My problem is basically the same as this one:Sometimes don't get onCreateLoader callback after calling initLoader

I have 2 ListFragments that are contained in a ViewPager. They get loaded ok at first, but when I change the orientation, the initLoadermethod doesn't call the onCreateLoader. However, if I revert back to the initial orientation, all is fine again.

Here is my code for the FragmentActivity:

import java.util.Locale;

import com.d.camera.R;
import com.d.camera.R.id;
import com.d.camera.R.layout;
import com.d.camera.R.menu;
import com.d.camera.R.string;

import android.app.ActionBar;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.NavUtils;
import android.support.v4.view.ViewPager;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class HistoryFragments extends FragmentActivity implements
    ActionBar.TabListener {

/**
 * The {@link android.support.v4.view.PagerAdapter} that will provide
 * fragments for each of the sections. We use a
 * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
 * will keep every loaded fragment in memory. If this becomes too memory
 * intensive, it may be best to switch to a
 * {@link android.support.v4.app.FragmentStatePagerAdapter}.
 */
SectionsPagerAdapter mSectionsPagerAdapter;

/**
 * The {@link ViewPager} that will host the section contents.
 */
ViewPager mViewPager;

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

    // Set up the action bar.
    final ActionBar actionBar = getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    actionBar.setDisplayShowTitleEnabled(false);
    actionBar.setDisplayShowHomeEnabled(false);

    // Create the adapter that will return a fragment for each of the three
    // primary sections of the app.
    mSectionsPagerAdapter = new SectionsPagerAdapter(
            getSupportFragmentManager());

    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);

    // When swiping between different sections, select the corresponding
    // tab. We can also use ActionBar.Tab#select() to do this if we have
    // a reference to the Tab.
    mViewPager
            .setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    actionBar.setSelectedNavigationItem(position);
                }
            });

    // For each of the sections in the app, add a tab to the action bar.
    for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
        // Create a tab with text corresponding to the page title defined by
        // the adapter. Also specify this Activity object, which implements
        // the TabListener interface, as the callback (listener) for when
        // this tab is selected.
        actionBar.addTab(actionBar.newTab()
                .setText(mSectionsPagerAdapter.getPageTitle(i))
                .setTabListener(this));
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.history, menu);
    return true;
}

@Override
public void onTabSelected(ActionBar.Tab tab,
        FragmentTransaction fragmentTransaction) {
    // When the given tab is selected, switch to the corresponding page in
    // the ViewPager.
    mViewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabUnselected(ActionBar.Tab tab,
        FragmentTransaction fragmentTransaction) {
}

@Override
public void onTabReselected(ActionBar.Tab tab,
        FragmentTransaction fragmentTransaction) {
}

/**
 * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
 * one of the sections/tabs/pages.
 */
public class SectionsPagerAdapter extends FragmentPagerAdapter {

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        // getItem is called to instantiate the fragment for the given page.
        // Return a DummySectionFragment (defined as a static inner class
        // below) with the page number as its lone argument.

        Fragment fragment = null;

        if (position == 0) {
            fragment = new HistoryListFragment();               
        } else{
            fragment = new HistoryElemListFragment();

        }
        return fragment;
    }

    @Override
    public int getCount() {
        // Show 2 total pages.
        return 2;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        Locale l = Locale.getDefault();
        switch (position) {
        case 0:
            return getString(R.string.title_section1).toUpperCase(l);
        case 1:
            return getString(R.string.title_section2).toUpperCase(l);
        case 2:
            return getString(R.string.title_section3).toUpperCase(l);
        }
        return null;
    }
}


}

and here is the code of one of the ListFragments:

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import com.d.camera.HistoryContentProvider;
import com.d.camera.HistoryDatabase;
import com.d.camera.HistoryEntry;
import com.d.camera.R;

import android.app.LoaderManager;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.ViewGroup;
import android.widget.FilterQueryProvider;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.SimpleCursorAdapter.ViewBinder;

public class HistoryListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>{

    private static final int LOADER_ID = 0x01;
    private static final int DELETE_ID = Menu.FIRST + 1;
    public static final String SECTION_NUMBER = "section_number";
    private SimpleCursorAdapter adapter;
    private Context context;

    public HistoryListFragment() {
    }


    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        context = getActivity();
        fillData();
        registerForContextMenu(getListView());
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.list_fragment, container, false);
        return rootView;
    }




    private void fillData() {
        getActivity().getLoaderManager().initLoader(LOADER_ID, null, this);
        String[] from = new String[] {
                HistoryDatabase.MOBILE_RESULT,
                HistoryDatabase.FP_TIMESTAMP,
                HistoryDatabase.PRODUCT_IMAGE,};

        int[] to = new int[] {
                R.id.resultImage,
                R.id.time,
                R.id.productImage,};

        adapter = new SimpleCursorAdapter(context, R.layout.history_element, null, from, to, 0);


        // We want monitor the list setup and change the milliseconds time to a readable format.*******
        adapter.setViewBinder(new ViewBinder(){
            public boolean setViewValue(View v, Cursor c, int columnIndex) {

                if(columnIndex == c.getColumnIndex(HistoryDatabase.FP_TIMESTAMP))
                {
                    Long timeInMilli = c.getLong(c.getColumnIndex(HistoryDatabase.FP_TIMESTAMP));
                    SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
                    String formatedTime = sdf.format(new Date(timeInMilli));
                    TextView tv = (TextView)v;
                    tv.setText(formatedTime);
                    return true;
                }
                return false;
            }
        });
        //*********************************************************************************************

        setListAdapter(adapter);

  }


    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
            ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        menu.add(0, DELETE_ID, 0, R.string.menu_delete);
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        //...
        return super.onContextItemSelected(item);
    }



    // Reaction to the menu selection
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        //...
        return super.onOptionsItemSelected(item);
    }


    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        String[] projection = new String[]{HistoryDatabase.ID, HistoryDatabase.MOBILE_RESULT, HistoryDatabase.MOBILE_SCORE, HistoryDatabase.FP_TIMESTAMP, HistoryDatabase.PRODUCT_IMAGE, HistoryDatabase.QR_MESSAGE};
        return new CursorLoader(context, HistoryContentProvider.CONTENT_URI, projection, null, null, HistoryDatabase.ID + " DESC");
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        adapter.swapCursor(cursor);     
    }

    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {
        adapter.swapCursor(null);           
    }   

    public void onListItemClick(ListView l, View v, int position, long id) {
        //do something
    }
}

I've tried different combinations of these methods destroyLoader,restartLoader, but without any success... Does anyone know what's going on?

Edit Using LoaderManager.enableDebugLogging(true) I get the following logs: The first load gives this

 initLoader in LoaderManager{424a7950 in HistoryFragments{42507c68}}: args=null
   Starting: LoaderInfo{424a7da0 #1 : CursorLoader{42faae18}}
   Created new loader LoaderInfo{424a7da0 #1 : CursorLoader{42faae18}}
 initLoader in LoaderManager{424a7950 in HistoryFragments{42507c68}}: args=null
   Starting: LoaderInfo{42e5a280 #2 : CursorLoader{42e5a2f8}}
   Created new loader LoaderInfo{42e5a280 #2 : CursorLoader{42e5a2f8}}
 onLoadComplete: LoaderInfo{424a7da0 #1 : CursorLoader{42faae18}}
   onLoadFinished in CursorLoader{42faae18 id=1}: CursorWrapperInner{42506d58}
 onLoadComplete: LoaderInfo{42e5a280 #2 : CursorLoader{42e5a2f8}}
   onLoadFinished in CursorLoader{42e5a2f8 id=2}: CursorWrapperInner{42fab1f0}

Then when I change the orientation, it gives this

Retaining in LoaderManager{424a7950 in HistoryFragments{42507c68}}
   Retaining: LoaderInfo{42e5a280 #2 : CursorLoader{42e5a2f8}}
   Retaining: LoaderInfo{424a7da0 #1 : CursorLoader{42faae18}}
 Destroying Inactive in LoaderManager{424a7950 in HistoryFragments{42507c68}}
 initLoader in LoaderManager{424a7950 in HistoryFragments{426d0af0}}: args=null
   Re-using existing loader LoaderInfo{424a7da0 #1 : CursorLoader{42faae18}}
 initLoader in LoaderManager{424a7950 in HistoryFragments{426d0af0}}: args=null
   Re-using existing loader LoaderInfo{42e5a280 #2 : CursorLoader{42e5a2f8}}
 Finished Retaining in LoaderManager{424a7950 in HistoryFragments{426d0af0}}
   Finished Retaining: LoaderInfo{42e5a280 #2 : CursorLoader{42e5a2f8}}
   Stopping: LoaderInfo{42e5a280 #2 : CursorLoader{42e5a2f8}}
   Finished Retaining: LoaderInfo{424a7da0 #1 : CursorLoader{42faae18}}
   Stopping: LoaderInfo{424a7da0 #1 : CursorLoader{42faae18}}

Then when I come back to the initial orientation, I get an error but then everything gets loaded again:

Retaining in LoaderManager{424a7950 in HistoryFragments{426d0af0}}
 Called doRetain when not started: LoaderManager{424a7950 in HistoryFragments{426d0af0}}
 java.lang.RuntimeException: here
    at android.app.LoaderManagerImpl.doRetain(LoaderManager.java:795)
    at android.app.Activity.performStop(Activity.java:5497)
    at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3591)
    at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3654)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3854)
    at android.app.ActivityThread.access$800(ActivityThread.java:159)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1322)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:176)
    at android.app.ActivityThread.main(ActivityThread.java:5419)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
    at dalvik.system.NativeStart.main(Native Method)
 Destroying Active in LoaderManager{424a7950 in HistoryFragments{426d0af0}}
   Destroying: LoaderInfo{42e5a280 #2 : CursorLoader{42e5a2f8}}
   Reseting: LoaderInfo{42e5a280 #2 : CursorLoader{42e5a2f8}}
   Destroying: LoaderInfo{424a7da0 #1 : CursorLoader{42faae18}}
   Reseting: LoaderInfo{424a7da0 #1 : CursorLoader{42faae18}}
 Destroying Inactive in LoaderManager{424a7950 in HistoryFragments{426d0af0}}
 Destroying Active in LoaderManager{424a7950 in HistoryFragments{426d0af0}}
 Destroying Inactive in LoaderManager{424a7950 in HistoryFragments{426d0af0}}
 initLoader in LoaderManager{4271b070 in HistoryFragments{42702c68}}: args=null
   Starting: LoaderInfo{4271b690 #1 : CursorLoader{4271b708}}
   Created new loader LoaderInfo{4271b690 #1 : CursorLoader{4271b708}}
 initLoader in LoaderManager{4271b070 in HistoryFragments{42702c68}}: args=null
   Starting: LoaderInfo{42720ab8 #2 : CursorLoader{42720b30}}
   Created new loader LoaderInfo{42720ab8 #2 : CursorLoader{42720b30}}
 onLoadComplete: LoaderInfo{4271b690 #1 : CursorLoader{4271b708}}
   onLoadFinished in CursorLoader{4271b708 id=1}: CursorWrapperInner{4271f518}
 onLoadComplete: LoaderInfo{42720ab8 #2 : CursorLoader{42720b30}}
   onLoadFinished in CursorLoader{42720b30 id=2}: CursorWrapperInner{427222c0}

The logs then repeat themselves for further orientation changes. Why are the CursorLoaders being stopped and not restarted? How can I restart them?

EDIT 2

I fixed my problem thanks to nikis, but he raised an interesting question: why was the android.app.LoaderManager not working?

Here's the logs after using the support version. The first load gives the same thing as above, but after the orientation change, re-using the cursors doesn't stop them.

 Retaining in LoaderManager{43945c70 in HistoryFragments{427cb468}}
   Retaining: LoaderInfo{439d8a58 #2 : CursorLoader{439d8ad0}}
   Retaining: LoaderInfo{432dea88 #1 : CursorLoader{4393ad48}}
 Destroying Inactive in LoaderManager{43945c70 in HistoryFragments{427cb468}}
 initLoader in LoaderManager{43945c70 in HistoryFragments{438f0a38}}: args=null
   Re-using existing loader LoaderInfo{432dea88 #1 : CursorLoader{4393ad48}}
 initLoader in LoaderManager{43945c70 in HistoryFragments{438f0a38}}: args=null
   Re-using existing loader LoaderInfo{439d8a58 #2 : CursorLoader{439d8ad0}}
 Starting in LoaderManager{43945c70 in HistoryFragments{438f0a38}}
 Finished Retaining in LoaderManager{43945c70 in HistoryFragments{438f0a38}}
   Finished Retaining: LoaderInfo{439d8a58 #2 : CursorLoader{439d8ad0}}
   onLoadFinished in CursorLoader{439d8ad0 id=2}: CursorWrapperInner{43952be0}
   Finished Retaining: LoaderInfo{432dea88 #1 : CursorLoader{4393ad48}}
   onLoadFinished in CursorLoader{4393ad48 id=1}: CursorWrapperInner{43952fa8}

And when I come back to the initial orientation, this is the result:

Retaining in LoaderManager{43945c70 in HistoryFragments{438f0a38}}
   Retaining: LoaderInfo{439d8a58 #2 : CursorLoader{439d8ad0}}
   Retaining: LoaderInfo{432dea88 #1 : CursorLoader{4393ad48}}
 Destroying Inactive in LoaderManager{43945c70 in HistoryFragments{438f0a38}}
 initLoader in LoaderManager{43945c70 in HistoryFragments{432cab50}}: args=null
   Re-using existing loader LoaderInfo{432dea88 #1 : CursorLoader{4393ad48}}
 initLoader in LoaderManager{43945c70 in HistoryFragments{432cab50}}: args=null
   Re-using existing loader LoaderInfo{439d8a58 #2 : CursorLoader{439d8ad0}}
 Starting in LoaderManager{43945c70 in HistoryFragments{432cab50}}
 Finished Retaining in LoaderManager{43945c70 in HistoryFragments{432cab50}}
   Finished Retaining: LoaderInfo{439d8a58 #2 : CursorLoader{439d8ad0}}
   onLoadFinished in CursorLoader{439d8ad0 id=2}: CursorWrapperInner{43952be0}
   Finished Retaining: LoaderInfo{432dea88 #1 : CursorLoader{4393ad48}}
   onLoadFinished in CursorLoader{4393ad48 id=1}: CursorWrapperInner{43952fa8}

解决方案

You can use LoaderManager.enableDebugLogging(true) to debug your loader behavior or you can try to use getSupportLoadermanager() instead of getLoaderManager()

这篇关于onCreateLoader不叫时,方向更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆