[英]Android how to make a thread wait until a certain event happens?
[我的狀況]
現在在MainActivity中,我創建了一些片段,其中有一些TextView。 MainActivity中有一個異步線程AsyncTask,用於從Web獲取信息。 AsyncTask完成獲取后,它將通過回調方法更新上述TextViews中的文本(該Fragment實現一個OnInfoGotInterface並實例化接口中的onInfoGot()方法。onInfoGot()將調用Fragment中定義的setTextView()方法以更新信息。 )。
[我的問題]
執行程序時,我發現AsyncTask完成從Web獲取信息的時間點比Fragment調用onCreateView()的時間點早。 換句話說,當AsyncTask調用(OnInfoGotInterface)fragment.onInfoGot()設置TextView時,尚未實例化TextView(通過rootView.findViewById()方法在CreateView()上實例化TextView)。 結果,出現了NullPointerException。
[我需要解決方案]
現在我想這樣做:當AsyncTask完成從Web上獲取信息並要調用onInfoGot()時,我們將其停止,並使其等待Fragment完成onCreateView()。 之后,我們喚醒AsyncTask並允許它更新片段。
PS。 有人建議我在Fragment的定義中的onCreateView()之后調用新的AsyncTask.excute()。 但是這里AsyncTask和Fragment都是在MainActivity中創建的。 它們是MainActivity中兩個不同的任務線程,一個用於顯示數據,另一個用於從Web獲取數據。
任何人都可以提一些建議嗎? 我真的很感激! 這是代碼:
MainActivity.java:
public class MainActivity extends Activity{
private List<City> cityList;
private ViewPager mPager; /*ViewPager for show the page of city info*/
private ScreenSlidePagerAdapter mPagerAdapter; /* Adapter for the ViewPager,
* ScreenSlidePagerAdapter is a subclass of FragmentStatePagerAdapter*/
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_city);
cityList = new ArrayList<City>();
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
init();
}
private void init(){
loadCities(); //Load cities from database into cityList
initFragments();
getCityInfo();
}
private void initFragments(){
mPagerAdapter.removeAllFragments();
for(City city: cityList){
PageFragment fragment = new PageFragment(city.getName());
mPagerAdapter.addFragment(fragment);
mPagerAdapter.notifyDataSetChanged();
}
}
private void getCityInfo(){
for(City city: cityList){
String cityName = city.getName();
obtainCityInfo(cityName);
}
}
private obtainCityInfo(String cityName){
String request = "http://example.abc.com/"
+ cityName + "&output=json";
new AccessWebServiceTask().execute(request, cityName);
}
private class AccessWebServiceTask extends AsyncTask<String, Void, CityInfo>{
@Override
protected CityInfo doInBackground(String... urls) {
String result = getWebContent(urls[0]); /*Access web through HTTP*/
String cityName = urls[1];
/*Transform the String result to a CityInfo object containing information of a city*/
CityInfo cityInfo = encodeJason(result, cityName);
return cityInfo;
}
protected void onPostExecute(CityInfo cityInfo){
OnCityGot(cityInfo);
}
}
public void onCityGot(CityInfo cityInfo){
if(cityInfo != null){
String cityName = cityInfo.getCityName();
/*Set the info field of a city object*/
cityList.getByName(cityName).setCityInfo(cityInfo);
mPagerAdapter.updateFragment(cityInfo);
}
}
}
ScreenSlidePagerAdapter.java
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter{
private List<PageFragment> fragmentsList;
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
fragmentsList = new ArrayList<PageFragment>();
}
public ScreenSlidePagerAdapter(FragmentManager fm, List<PageFragment> list){
super(fm);
fragmentsList = list;
}
@Override
public PageFragment getItem(int position) {
return fragmentsList.get(position);
}
@Override
public int getCount() {
return fragmentsList.size();
}
public void setFragmentsList(List<PageFragment> fragmentsList){
this.fragmentsList = fragmentsList;
notifyDataSetChanged();
}
public void addFragment(PageFragment f){
fragmentsList.add(f);
notifyDataSetChanged();
}
public void removeFragment(int position){
fragmentsList.remove(position);
notifyDataSetChanged();
}
public void removeAllFragments(){
fragmentsList.clear();
notifyDataSetChanged();
}
private PageFragment findFragmentByName(String cityName){
for(PageFragment fragment: fragmentsList){
if(fragment.getCityName().equals(cityName))
return fragment;
}
return null;
}
public void updateFragment(CityInfo cityInfo){
String cityName = cityInfo.getCityName();
OnCityInfoChanged fragment = (OnCityInfoChanged)findFragmentByName(cityName);
String population = cityInfo.getPopulation();
fragment.onCityInfoChanged(population);
notifyDataSetChanged();
}
}
PageFragment.java:
public class PageFragment extends Fragment implements OnCityInfoChanged{
private TextView cityNameText;
private TextView populationText;
String cityName;
String population;
public PageFragment(){}
public PageFragment(String cityName, String population){
this.cityName = cityName;
this.population = population
}
public PageFragment(CityInfo cityInfo){
this.cityName = cityInfo.getCityName();
this.population = cityInfo.getPopulation();
}
public PageFragment(String cityName){
this.cityName = cityName;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.fragment_city_page2, container, false);
cityNameText = (TextView)rootView.findViewById(R.id.city_name);
populationText = (TextView)rootView.findViewById(R.id.population);
setCityName(cityName);
setPopulation(population)
return rootView;
}
public void setCityName(String name){
cityNameText.setText(name);
}
public void setPopulation(String population){
populationText.setText(population);
}
public String getCityName(){
return cityName;
}
@Override
public void onCityInfoChanged(String population) {
//setCityName(cityName);
setPopulation();
}
}
您可以嘗試ConditionVariable ,它可以用於保存AsyncTask
private ConditionVariable mCondition = new ConditionVariable(false);
mCondition.block(); //used to block
// your condition
mCondition.open(); // used to open
首先,您不應該將Fragment構造函數與參數一起使用。 您應該將捆綁包中的片段的參數發送給片段參數集。 參見: https : //stackoverflow.com/a/15392591/360211
我將在其onCreate
obtainCityInfo
其片段稱為obtainCityInfo
方法。 然后,不再進行查找,我可以將OnCityInfoChanged
傳遞給異步任務,以使其調用onPostExecute
。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.fragment_city_page2, container, false);
cityNameText = (TextView)rootView.findViewById(R.id.city_name);
populationText = (TextView)rootView.findViewById(R.id.population);
setCityName(cityName);
obtainCityInfo(cityName, this);
return rootView;
}
private obtainCityInfo(String cityName, OnCityInfoChanged callback){
String request = "http://example.abc.com/"
+ cityName + "&output=json";
new AccessWebServiceTask(callback).execute(request, cityName);
}
我會建議刪除的AsyncTask AccessWebServiceTask
從在MainActivity並把它放在片段PageFragment
。 然后在此片段中,重寫onActivityCreated
,啟動AsyncTask。
[編輯]
這是您代碼的更新版本。 測試它是否有效:
主要活動
public class MainActivity extends Activity{
private List<City> cityList;
private ViewPager mPager; /*ViewPager for show the page of city info*/
private ScreenSlidePagerAdapter mPagerAdapter; /* Adapter for the ViewPager,
* ScreenSlidePagerAdapter is a subclass of FragmentStatePagerAdapter*/
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_city);
cityList = new ArrayList<City>();
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
init();
}
private void init(){
loadCities(); //Load cities from database into cityList
initFragments();
}
private void initFragments(){
mPagerAdapter.removeAllFragments();
for(City city: cityList){
PageFragment fragment = PageFragment.newFragment(city.getName());
mPagerAdapter.addFragment(fragment);
}
}
}
ScreenSlidePagerAdapter:
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter{
private List<PageFragment> fragmentsList;
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
fragmentsList = new ArrayList<PageFragment>();
}
public ScreenSlidePagerAdapter(FragmentManager fm, List<PageFragment> list){
super(fm);
fragmentsList = list;
}
@Override
public PageFragment getItem(int position) {
return fragmentsList.get(position);
}
@Override
public int getCount() {
return fragmentsList.size();
}
public void setFragmentsList(List<PageFragment> fragmentsList){
this.fragmentsList = fragmentsList;
notifyDataSetChanged();
}
public void addFragment(PageFragment f){
fragmentsList.add(f);
notifyDataSetChanged();
}
public void removeFragment(int position){
fragmentsList.remove(position);
notifyDataSetChanged();
}
public void removeAllFragments(){
fragmentsList.clear();
notifyDataSetChanged();
}
}
PageFragment:
public class PageFragment extends Fragment {
private TextView cityNameText;
private TextView populationText;
private String cityName;
private String population;
public static final String CITY_NAME_KEY = "cityname";
public PageFragment(){}
public static PageFragment newFragment(String cityName){
PageFragment fragment = new PageFragment();
Bundle args = new Bundle();
args.putString(CITY_NAME_KEY, cityName);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate (Bundle savedInstanceState){
super.onCreate();
if(savedInstanceState != null){
this.cityName = savedInstanceState.getString(CITY_NAME_KEY);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.fragment_city_page2, container, false);
cityNameText = (TextView)rootView.findViewById(R.id.city_name);
populationText = (TextView)rootView.findViewById(R.id.population);
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState){
if(this.cityName != null){
String request = "http://example.abc.com/" + cityName + "&output=json";
new AccessWebServiceTask().execute(request, cityName);
}
}
public void setCityName(String name){
cityNameText.setText(name);
}
public void setPopulation(String population){
populationText.setText(population);
}
public String getCityName(){
return cityName;
}
private class AccessWebServiceTask extends AsyncTask<String, Void, CityInfo>{
@Override
protected CityInfo doInBackground(String... urls) {
String result = getWebContent(urls[0]); /*Access web through HTTP*/
String cityName = urls[1];
/*Transform the String result to a CityInfo object containing information of a city*/
CityInfo cityInfo = encodeJason(result, cityName);
return cityInfo;
}
protected void onPostExecute(CityInfo cityInfo){
OnCityGot(cityInfo);
}
}
public void onCityGot(CityInfo cityInfo){
if(cityInfo != null){
String population = cityInfo.getPopulation();
setPopulation(population);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.