Android开发-AsyncTask在片段中的错误实现?

Android开发-AsyncTask在片段中的错误实现?,android,android-fragments,android-asynctask,fragment,Android,Android Fragments,Android Asynctask,Fragment,我最近开始尝试在我的Android项目片段中实现异步任务,并立即遇到一个常见错误,即配置更改导致了一个重大问题。我在网上看到的方法并不容易融入我的ViewPager设置中,我用自己的知识来处理配置更改 我的问题是:我的方法有什么危险吗?最大的问题是内存泄漏,但我确保在ondeach()方法上清空每个创建的_视图 执行情况摘要: 将片段的setRetainInstance设置为true,这样就不必重新创建它,也不会丢失重要数据 在onCreateView()中,当必须重新创建片段的视图时,始终调

我最近开始尝试在我的Android项目片段中实现异步任务,并立即遇到一个常见错误,即配置更改导致了一个重大问题。我在网上看到的方法并不容易融入我的ViewPager设置中,我用自己的知识来处理配置更改

我的问题是:我的方法有什么危险吗?最大的问题是内存泄漏,但我确保在ondeach()方法上清空每个创建的_视图

执行情况摘要:

  • 将片段的setRetainInstance设置为true,这样就不必重新创建它,也不会丢失重要数据

  • 在onCreateView()中,当必须重新创建片段的视图时,始终调用代码部分,应用程序将检查其AsyncTask是否正在运行。如果是这样,则显示一个不确定的进度条,当它完成onPostExecute时,将其可见性更改为GONE

  • onDetach()
    中,确保已创建的视图设置为null,这样就不会出现与最初使用的活动相关的内存泄漏

  • 在配置更改前的
    onAttach
代码

公共类RosterFragment扩展片段
{
List dataforlotster=new ArrayList();//将保存从解析数据库检索到的花名册对象的列表,
//然后将其传递给RosterCustomArrayaAdapter的构造函数。
检索到的列表\u List=new ArrayList();//将保存从ParseUser查询检索到的值的列表。
View createdView;//将与构建的RosterFragment一起传回的视图
private ProgressBar花名册\u progress;//在异步任务完成花名册下载之前将显示的不确定进度栏。
布尔运行任务;
私人RosterAsyncTask获取花名册;
@凌驾
创建时的公共void(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//跨配置更改保留此片段。
setRetainInstance(真);
get_花名册=new RosterAsyncTask();//创建新的RosterAsyncTask实例。
获取花名册。执行();
正在运行_task=true;
}
@凌驾
CreateView上的公共视图(布局、充气机、视图组容器、捆绑包保存状态)
{
createdView=充气机。充气(R.layout.rosterfragment,container,false);//使用特定布局充气碎片
花名册\进度=(ProgressBar)createdView.findViewById(R.id.LoadingFloster);//在布局中查找进度栏并将其设置为花名册\进度。
if(运行_任务==true)
{
花名册\进度设置可见性(视图可见);
}
其他的
{
填写花名册();
}
返回createdView;
}
@凌驾
公共无效连接()
{
super.onDetach();
createdView=null;
}
公共填补空缺名册()
{
如果(!datafor花名册.isEmpty())
{
//获取膨胀布局中的引用ListView。
ListView_花名册=(ListView)createdView.findViewById(R.id.rostercoachofficers);
//使用DataForFloster列表创建RosterCustomArrayAdapter的实例。
RosterCustomArrayAdapter花名册\ U适配器=新的RosterCustomArrayAdapter(getActivity(),DataFor花名册);
//对花名册适配器进行排序,以便ListView中的元素按名字的字母顺序进行排序。
花名册适配器.sort(新花名册比较程序());
//将适配器连接到ListView以填充其数据。
setAdapter(花名册适配器);
}
}
//AsyncTask负责在后台线程中下载花名册。
私有类RosterAsyncTask扩展异步任务
{
//要在AsyncTask后台线程中执行的操作。结果(下载的花名册数据)将传递给onPostExecute。
@凌驾
受保护列表doInBackground(无效…参数)
{
系统时钟。睡眠(10000);
ParseQuery query=ParseUser.getQuery();//为ParseUsers获取特定的ParseQuery。
尝试
{
已检索_list=query.find();//启动查询。
for(ParseUser current\u user:retrieved\u list)//对于从查询返回的每个ParseUser,使用ParseUser创建一个新的名册成员
//数据,然后将其添加到DataForFloster列表中。
{
名册成员当前成员=新名册成员();
current_member.username=current_user.getUsername();
ParseFile parse_ByteArray=(ParseFile)current_user.get(“profile_picture”);
位图配置文件\u Picture=BitmapFactory.decodeByteArray(parse\u ByteArray.getData(),0,parse\u ByteArray.getData().length);
当前_member.profile_Picture=profile_Picture;
current_member.title=当前_user.getString(“title”);
添加(当前_成员);
}
} 
//若查询执行中出现问题,请使用Toast显示错误消息。
捕获(解析异常)
{
Toast.makeText(getActivity(),“Error,”+e.getMessage(),Toast.LENGTH_LONG.show();
}
返回花名册数据;
}
//doinBackground方法完成后在主UI线程中运行的代码。
@凌驾
受保护的void onPostExecute(列出DataForFloster)
{    
正在运行_task=false;
填写花名册();
花名册_progress.setVisibility(View.GONE);
}
}
}    

我能看到的两件主要事情都与你的活动有关。doInBackground()中的toast需要从主线程调用,因此我确信这将失败。您传递给适配器的活动也与片段分开,因此每当您有一个配置更改将被销毁且不再有效时

为了帮助防止任何强制关闭,您可能希望用发送给logcat的消息替换toast,并在执行之前验证活动和进度是否为空
public class RosterFragment extends Fragment 
{

List<RosterMember> dataforroster = new ArrayList<RosterMember>(); //List that will hold the Roster objects retrieved from Parse database,
                                 //and later passed in to constructor for the RosterCustomArrayAdapter.
List<ParseUser> retrieved_list = new ArrayList<ParseUser>(); //List that will hold values retrieved from ParseUser Query. 
View createdView; //View that will be passed back with built RosterFragment
private ProgressBar roster_progress; //The indeterminate ProgressBar that will be displayed until the AsyncTask is finished downloading the roster.
boolean running_task;
private RosterAsyncTask get_roster;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    // Retain this fragment across configuration changes.
    setRetainInstance(true);
    get_roster = new RosterAsyncTask(); //Create new RosterAsyncTask instance.
    get_roster.execute();
    running_task = true;

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) 
{
    createdView = inflater.inflate(R.layout.rosterfragment, container, false); //Inflate the fragment using the specific layout
    roster_progress = (ProgressBar) createdView.findViewById(R.id.loadingroster); //Find the ProgressBar in layout and set it to roster_progress.
    if(running_task == true)
    {
        roster_progress.setVisibility(View.VISIBLE);
    }
    else
    {
        fill_roster();
    }
    return createdView;
}

@Override
public void onDetach()
{
    super.onDetach();
    createdView = null;
}


public void fill_roster()
{
    if(!dataforroster.isEmpty())
    {
    //Get reference ListView in the inflated layout.
    ListView the_Roster = (ListView) createdView.findViewById(R.id.rostercoachofficers);
    //Create an instance of the RosterCustomArrayAdapter using the dataforroster List.
    RosterCustomArrayAdapter roster_Adapter = new RosterCustomArrayAdapter(getActivity(), dataforroster);
    //Sort the roster_Adapter so elements in ListView will be sorted alphabetically by first name.
    roster_Adapter.sort(new RosterComparator());    
    //Attach adapter to the ListView to populate its data.
    the_Roster.setAdapter(roster_Adapter);
    }

}


//AsyncTask responsible for downloading roster in background thread.
private class RosterAsyncTask extends AsyncTask<Void, Void , List<RosterMember>>
{


    //The operations to perform in the AsyncTask background thread. The results(the roster data downloaded) will be passed to onPostExecute.
    @Override
    protected List<RosterMember> doInBackground(Void... params)
    {
        SystemClock.sleep(10000);
        ParseQuery<ParseUser> query = ParseUser.getQuery(); //Get specific ParseQuery for ParseUsers.

        try 
        {
        retrieved_list = query.find(); //Initiate query.
        for(ParseUser current_user: retrieved_list) //For every ParseUser returned from query, create a new RosterMember using the ParseUser
                               //data and then add it to the dataforroster List.
            {
                RosterMember current_member = new RosterMember();
                current_member.username = current_user.getUsername();
                ParseFile parse_ByteArray = (ParseFile)current_user.get("profile_picture");
                Bitmap profile_Picture = BitmapFactory.decodeByteArray(parse_ByteArray.getData(), 0, parse_ByteArray.getData().length);
                current_member.profile_Picture = profile_Picture;
                current_member.title = current_user.getString("title");
                dataforroster.add(current_member);
            }




        } 

        //If problem occurred in query execution, use Toast to display error message.
        catch (ParseException e) 
        {
            Toast.makeText(getActivity(), "Error, " + e.getMessage(), Toast.LENGTH_LONG).show();
        }
        return dataforroster;
   }



  //Code to run in main UI thread once the doinBackground method is finished.
  @Override
  protected void onPostExecute(List<RosterMember> dataforroster) 
  {    
      running_task = false; 
      fill_roster();
      roster_progress.setVisibility(View.GONE);

  }



}

}    
public class RosterFragment extends Fragment 
{
    List<RosterMember> dataforroster = new ArrayList<RosterMember>(); //List that will hold the Roster objects retrieved from Parse database,
                                     //and later passed in to constructor for the RosterCustomArrayAdapter.
    List<ParseUser> retrieved_list = new ArrayList<ParseUser>(); //List that will hold values retrieved from ParseUser Query. 
    View createdView; //View that will be passed back with built RosterFragment
    private ProgressBar roster_progress; //The indeterminate ProgressBar that will be displayed until the AsyncTask is finished downloading the roster.
    boolean running_task;
    private RosterAsyncTask get_roster;
    private boolean successful_query;
    private String error_message;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // Retain this fragment across configuration changes.
        setRetainInstance(true);
        get_roster = new RosterAsyncTask(); //Create new RosterAsyncTask instance.
        get_roster.execute();
        running_task = true;

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) 
    {
        createdView = inflater.inflate(R.layout.rosterfragment, container, false); //Inflate the fragment using the specific layout
        roster_progress = (ProgressBar) createdView.findViewById(R.id.loadingroster); //Find the ProgressBar in layout and set it to roster_progress.
        fill_roster();
        return createdView;
    }

    @Override
    public void onDetach()
    {
        super.onDetach();
        createdView = null;
    }


    public void fill_roster()
    {

            if(running_task == true)
            {
                roster_progress.setVisibility(View.VISIBLE);
            }
            else
            {

                roster_progress.setVisibility(View.GONE);

                if(!dataforroster.isEmpty())//Get reference ListView in the inflated layout.
                {
                    ListView the_Roster = (ListView) createdView.findViewById(R.id.rostercoachofficers);
                    //Create an instance of the RosterCustomArrayAdapter using the dataforroster List.
                    RosterCustomArrayAdapter roster_Adapter = new RosterCustomArrayAdapter(getActivity(), dataforroster);
                    //Sort the roster_Adapter so elements in ListView will be sorted alphabetically by first name.
                    roster_Adapter.sort(new RosterComparator());    
                    //Attach adapter to the ListView to populate its data.
                    the_Roster.setAdapter(roster_Adapter);

                }
                else
                {
                    if(successful_query == false)
                    {
                        Toast.makeText(getActivity(), error_message, Toast.LENGTH_LONG).show();
                    }
                }
            }


    }




    //AsyncTask responsible for downloading roster in background thread.
    private class RosterAsyncTask extends AsyncTask<Void, Void , Void>
    {


        //The operations to perform in the AsyncTask background thread. The results(the roster data downloaded) will be passed to onPostExecute.
        @Override
        protected Void doInBackground(Void... params)
        {
            dataforroster.clear();
            ParseQuery<ParseUser> query = ParseUser.getQuery(); //Get specific ParseQuery for ParseUsers.

            try 
            {
            retrieved_list = query.find(); //Initiate query.
            for(ParseUser current_user: retrieved_list) //For every ParseUser returned from query, create a new RosterMember using the ParseUser
                                   //data and then add it to the dataforroster List.
                {
                    RosterMember current_member = new RosterMember();
                    current_member.username = current_user.getUsername();
                    ParseFile parse_ByteArray = (ParseFile)current_user.get("profile_picture");
                    Bitmap profile_Picture = BitmapFactory.decodeByteArray(parse_ByteArray.getData(), 0, parse_ByteArray.getData().length);
                    current_member.profile_Picture = profile_Picture;
                    current_member.title = current_user.getString("title");
                    dataforroster.add(current_member);
                }


            successful_query = true;        

            } 

            //If problem occurred in query execution, use Toast to display error message.
            catch (ParseException e) 
            {
                successful_query = false;
                error_message = "Error, " + e.getMessage();
            }
            return null;

       }



      //Code to run in main UI thread once the doinBackground method is finished.
      @Override
      protected void onPostExecute(Void ignore) 
      {    

          running_task = false; 

          if(getActivity()!=null)
          {
              fill_roster();
          }

      }



    }   
}