【问题标题】:Activity crashing when setting non-view fragment listener on rotation在旋转时设置非视图片段侦听器时活动崩溃
【发布时间】:2014-10-03 15:45:10
【问题描述】:

我有一个Activity 动态添加两个片段。一个是隐藏的(无视图)Fragment,它具有setRetainInstance(true) 并处理我的数据库处理程序的接口。其目的是启动AsyncTask 以从数据库中获取数据并侦听数据库处理程序以返回其结果。然后它将通过另一个侦听器将数据交还给Activity。然后Activity 会将数据交给显示器Fragment,其中有一个ListView,并将相应地显示。

活动:不是片段活动

import android.app.Activity; 
import android.os.Bundle; 

public class Workout_Search_Display_Activity  extends Activity { 
private final String search_string = "SEARCH_STRING"; 
private final String search_type = "SEARCH_TYPE"; 
private String Search_String = ""; 
private String Search_Type = ""; 
private Workout_Search_Holder_Fragment SearchHolder; 
private Workout_Search_Display_Fragment search_display_fragment; 
private Workout_Search_Activity_Listener WSAL; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 

    super.onCreate(savedInstanceState); 

    Search_String =  getIntent().getStringExtra(search_string); 
    Search_Type = getIntent().getStringExtra(search_type); 

    if (getFragmentManager().findFragmentById(android.R.id.content) == null) {
        SearchHolder = Workout_Search_Holder_Fragment.newInstance(Search_String, Search_Type); 
        getFragmentManager().beginTransaction() 
                .add(android.R.id.content, SearchHolder).commit(); 
        search_display_fragment = Workout_Search_Display_Fragment.newInstance(); 
        getFragmentManager().beginTransaction() 
                .add(android.R.id.content, search_display_fragment).commit; 
    } //added too try to fix// else 
     //added to try to fix// SearchHolder = (Workout_Search_Holder_Fragment) getFragmentManager.findFragmentByTag("search_holder");

    WSAL = new Workout_Search_Activity_Listener() { 
        public void NothingFound() { 
            search_display_fragment.no_data(); 

            } 

        public void results_found(ArrayList<Search_Results_Holder> results) { 
        search_display_fragment.is_data(); 
            search_display_fragment.handover_data(results); 

        } 

       }; 
SearchHolder.setListener(WSAL); 
  } 
}

片段:

import android.app.Fragment; 
import android.os.AsyncTask; 
import android.os.Build; 
import android.os.Bundle; 
import android.util.Log; 

public class Workout_Search_Holder_Fragment extends Fragment implements DatabaseHelper.Workout_Search_Listener { 
private String Search_String = ""; 
private String Search_Type = ""; 
private final static String search_string = "SEARCH_STRING"; 
private final static String search_type = "SEARCH_TYPE"; 
private Workout_Search_Activity_Listener listener; 

protected static Workout_Search_Holder_Fragment newInstance( 
        String Search_String, String Search_Type) { 
    Workout_Search_Holder_Fragment f = new Workout_Search_Holder_Fragment(); 

    Bundle args = new Bundle(); 

    args.putString(search_string, Search_String); 
    args.putString(search_type, Search_Type); 
    f.setArguments(args); 
    return f; 
} 

public void onActivityCreated(Bundle savedInstanceState) { 

    super.onActivityCreated(savedInstanceState); 
    setRetainInstance(true); 
    Search_String = getArguments().getString(search_string, null); 
    Search_Type = getArguments().getString(search_type, null); 
    sendSearch(); 
} 

public Workout_Search_Activity_Listener getListener() { 
    return listener; 
} 


public void setListener(Workout_Search_Activity_Listener listener) { 
    this.listener = listener; 
} 
private void sendSearch() { 
    DatabaseHelper.getInstance(getActivity()).getSearchResultsAsync( 
            Search_String, Search_Type, this); 


} 

static public <T> void executeAsyncTask(AsyncTask<T, ?, ?> task, T... params) { 
    if (Build.VERSION.SDK_INT > +Build.VERSION_CODES.HONEYCOMB) { 
        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); 

    } else { 
        task.execute(params); 
    } 
} 
@Override 
public void return_no_results_found() { 
    listener.NothingFound(); 
} 
@Override 
public void return_search_results(ArrayList<Search_Results_Holder> results) { 
    Log.v("workout search holder fragment", "results found in fragment, handing off to activity");   
    listener.results_found(results); 

   }     
} 

我的问题是:旋转屏幕时,我的代码在 Activity 中的 Search_Hander 的 SetListener 上出现空指针异常而崩溃。如果我将Activity 更改为FragmentActivity 并使用SupportFragmentManager....这都不是问题...只需这些快速更改即可正常工作(关于现在已弃用的onRetainNonConfigurationInstance()SupportFragmentManager 覆盖,它会为你处理一切)。

在尝试解决此问题时,我将其保留为Activity,但如果R.id.Content 不是null,则将SearchHolder = (Workout_Search_Holder_Fragment) getFragmentManager.findFragmentByTag("search_holder") 作为else 的一部分并给Fragment 一个标签当我最初设置它时,如果R.id.Content WAS null。请参阅上面注释掉的代码。这有效,但产生了另一个问题,onActivityCreated 再次启动并在我不想要的时候启动了我的 AsyncTask。我无法将savedInstanceState 包中的变量发送或检查到片段,因为setRetainInstance(true) 导致它为空。我知道我做错了什么,但无法绕过它。

【问题讨论】:

    标签: android android-activity android-fragments fragmentmanager


    【解决方案1】:

    你正在使用

    添加(ANDROID.R.id.content, SearchHolder)

    在添加片段时,请尝试

    add(ContainerID, SearchHolder,"search_holder"),确保您的片段添加了标签“search_holder”

    然后就像你在其他部分所做的那样尝试通过调用来获取该片段对象

    findFragmentByTag() 方法

    希望对你有帮助!!!

    【讨论】:

    • 我最初尝试了所有这些......它工作但现在当我抓住 Else 部分中的旧片段时片段调用 onActivityCreated。我是否应该从 OnCreate 执行我的 AsyncTask,这样它就不会被调用两次(因为如果我保留片段,则不会再次调用 OnCreate,但 OnActivityCreated 会)。我唯一担心的是,任务可能会在我的听众被设置在活动中之前完成。有趣的是,如果我将 FragmenyActivity 与 SupportFragmentManager 一起使用,则根本不需要这些……为什么会有行为差异?
    • 您希望异步任务只执行一次?为什么不能在提交事务之前设置监听器,以便在从片段的 oncreate 执行异步任务时监听器可用?我想知道您是否说“将 FragmentActivity 与 SupportFragmentManager 一起使用时不需要”,我没有遇到过这种行为。
    • 无论屏幕旋转多少次都只有一次……在活动创建时只有一次。持有者片段用于允许活动在旋转的情况下持有正在运行的后台代码。持有者片段的唯一职责是在我的 DataHelper(从 opensqlhelper 扩展的另一个单独的类)中启动 sql 查询并将它收到的结果传递给活动。然后 Activity 将这些结果传递给显示片段进行显示。
    • 在下面发布了答案,但我仍然要感谢您的帮助和意见。
    【解决方案2】:

    答案有两点:

    1. 我需要手动附加Fragments,这我知道。
    2. 我在错误的区域执行了我的AsyncTask。这我不知道。

    事实证明,我的AsyncTask 正在重新执行,因为OnActivityCreated 再次被调用,即使设置了saveInstanceState(true)。但是,onCreate 不是。通过将调用方法更改为onCreate,我确保AsyncTask 仅被调用一次,因为在Activity 娱乐时不会再次调用它。在 Activity 中,我仍然需要在测试 R.id.content 是否不为空时通过抓取与标签匹配的那些片段来重置两个片段的持有者......这是 Dinash 给出的答案的一部分。

        if (getFragmentManager().findFragmentById(android.R.id.content) == null) {
            SearchHolder = Workout_Search_Holder_Fragment.newInstance(
                    Search_String, Search_Type, false);
            getFragmentManager().beginTransaction()
                    .add(android.R.id.content, SearchHolder, "searchholder")
                    .commit();
            search_display_fragment = Workout_Search_Display_Fragment
                    .newInstance();
            getFragmentManager()
                    .beginTransaction()
                    .add(android.R.id.content, search_display_fragment,
                            "displayholder").commit();
        } else {
            Log.v("activity", "non-null holder");
        SearchHolder = (Workout_Search_Holder_Fragment) getFragmentManager()
                .findFragmentByTag("searchholder");
        search_display_fragment = (Workout_Search_Display_Fragment) getFragmentManager()
                .findFragmentByTag("displayholder");
        }
    

    FragmentManager 要求我测试内容是否为空,以及我自己重新附加Fragments,这是FragmentSupportManager 不需要的。这也要求我保存我用于 ListView...再次...FragmentSupportManager 的 ArrayList 自己完成了这一切,而没有受到我的刺激。

    我仍然很好奇为什么 FragmentActivity 的这种行为会有所不同,因为它似乎为我处理了所有这些并且需要最少的工作量/代码来工作。

    【讨论】:

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