我最近开始尝试在Android项目的片段中实现 AsyncTasks ,并立即遇到导致重大问题的配置更改的常见错误。我在网上看到的方法并没有轻易地融入到我的ViewPager设置中,而且我利用自己的知识自行处理配置更改。
我的问题是:我的做法有什么危险吗?最大的问题是内存泄漏,但我确保在onDetach()方法上清空每个created_View。
实施摘要:
对于Fragment,setRetainInstance为true,因此不必重新创建,也不会丢失重要数据。
在onCreateView()中,当必须重新创建Fragment的View时,始终调用代码部分,应用程序将检查其AsyncTask是否正在运行。如果是,则显示IndeterminateProgressBar,当它完成onPostExecute时,将其可见性更改为GONE。
在onDetach()
中,确保created_view视图设置为null,因此没有与最初使用的Activity相关的内存泄漏
onAttach
中的代码
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);
}
}
}
答案 0 :(得分:1)
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();
}
}
}
}
答案 1 :(得分:0)
我能看到的两件主要事情都涉及你的活动。 doInBackground()中的toast需要从主线程调用,所以我很确定会失败。您传递给适配器的活动也与片段是分开的,因此每当您有一个配置更改将被销毁并且将不再有效时。
为了帮助防止强制关闭,您可能希望用tocat的消息替换toast,并在onPostExecute中执行任何操作之前验证activity和roster_progress是否为null。