我的应用中有AsyncTask
,可从网络服务器下载数据。
但是当我旋转屏幕时,我的应用程序崩溃了。这是因为第二次不执行onPostExecute(我存储下载的数据)。
但是在屏幕旋转后,onCreate()
方法会运行,AsynchTask
(它会)也会运行,但第二次不会调用onPostExecute
。我希望你有一个解决方案。
class ProductManager{
public ArrayList<ProductClass> productArray;
ProductManager(){
Log.d("LOGTAG","TAG2");
new DownloadProductTask().execute();
}
class DownloadProductTask extends AsyncTask<String,Integer,Void>
{
private ProgressDialog progressDialog = new ProgressDialog(ProductList.this);
InputStream is = null ;
String result = "";
@Override
protected void onPreExecute() {
progressDialog.setMessage("Download data...");
progressDialog.show();
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface arg0) {
DownloadProductTask.this.cancel(true);
}
});
}
@Override
protected Void doInBackground(String... params) {
Log.d("LOGTAG","TAG2.1");
String url_select = "http://jaspevj20.twenty.axc.nl/vhapp/displayproducts.php"; //Use http:// except for localhost & 127.0.0.1// jaspevj20.twenty.axc.nl for emulator local connection
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url_select);
ArrayList param = new ArrayList();
try {
httpPost.setEntity(new UrlEncodedFormEntity(param));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
//read content
is = httpEntity.getContent();
} catch (Exception e) {
Log.e("log_tag", "Error in http connection "+e.toString());
}
try {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = "";
while((line=br.readLine())!=null)
{
sb.append(line+"\n");
}
is.close();
result=sb.toString();
} catch (Exception e) {
// TODO: handle exception
Log.e("log_tag", "Error converting result "
+e.toString());
}
return null;
}
@Override
protected void onPostExecute(Void v) {
// ambil data dari Json database
try {
Log.d("LOGTAG","TAG3");
JSONArray Jarray = new JSONArray(result);
productArray = new ArrayList<ProductClass>();
int productid;
String productname;
double productprice;
int cookingtime;
String productoptionsstring;
List<String> productoptionslist;
String productflavoursstring;
List<String> productflavourslist;
String productdescription;
String category;
List<String> categorylist;
for(int i=0;i<Jarray.length();i++)
{
JSONObject Jasonobject = null;
Jasonobject = Jarray.getJSONObject(i);
productid = Integer.parseInt(Jasonobject.getString("ProductId"));
productname = Jasonobject.getString("ProductName");
productprice = Double.parseDouble(Jasonobject.getString("ProductPrice"));
cookingtime = Integer.parseInt(Jasonobject.getString("CookingTime"));
productoptionsstring = Jasonobject.getString("ProductOptions");
productoptionslist = Arrays.asList(productoptionsstring.split("\\s*,\\s*"));
productflavoursstring = Jasonobject.getString("ProductFlavours");
productflavourslist = Arrays.asList(productflavoursstring.split("\\s*,\\s*"));
productdescription = Jasonobject.getString("ProductDescription");
category = Jasonobject.getString("Category");
categorylist = Arrays.asList(category.split("\\s*,\\s*"));
Log.d("LOGTAG","TAG4");
productArray.add(new ProductClass(productid,productname,productprice,cookingtime));
ProductClass product = productArray.get(productArray.size()-1);
product.setProductOptions(productoptionslist);
product.setFlavours(productflavourslist);
product.setDescription(productdescription);
product.setCategories(categorylist);
}
mTitle = mDrawerTitle = getTitle();
mCategoryTitles = mProductManager.getAllCategories();
// set a custom shadow that overlays the main content when the drawer opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
mDrawerList.setAdapter(new ArrayAdapter<String>(ProductList.this,
R.layout.drawer_list_item, mCategoryTitles));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// Select the first category displaying as default
selectItem(0);
this.progressDialog.dismiss();
}
catch (Exception e)
{
Log.e("log_tag", "Error parsing data "+e.toString());
}
}
}
答案 0 :(得分:2)
实际上更可能的是你的AsyncTask确实执行了,而onPostExecute使用的是对Android销毁的小部件(来自之前的Activity实例)的引用。由于您的DownloadProductTask是您的Activity的内部,它包含对您的Activity的隐式引用,并且它不允许释放您的活动。
如果你不想使用android:configChanges hack - 然后使你的AsyncTask静态,然后使用onRetainNonConfigurationInstance / getLastNonConfigurationInstance保留你的AsyncTask实例,并在onCreate中使用新的小部件更新你的AsyncTask进行更新。这实际上是短篇小说,相当复杂。其他选项 - IMO更容易将AsyncTask放入保留的片段中。以下是一些信息:
Android Fragments. Retaining an AsyncTask during screen rotation or configuration change
使用android:configChanges的问题是,当你的Activity在正常的LifeCycle变化中被破坏时,它不会保护你,即。你称之为AsyncTask,然后你隐藏你的活动,然后转到其他一些活动 - Android现在可以自由地销毁你的活动 - 导致同样的问题。
答案 1 :(得分:0)
使用捆绑包保存您的数据。或者使用
编辑所需活动的清单 android:configChanges="orientation|keyboardHidden"
Bundle简介:
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putBoolean("MyBoolean", true);
savedInstanceState.putDouble("myDouble", 1.9);
savedInstanceState.putInt("MyInt", 1);
savedInstanceState.putString("MyString", "Welcome back to Android");
// etc.
}
Bundle本质上是一种存储NVP(“名称 - 值对”)地图的方式,它将被传递到onCreate
以及onRestoreInstanceState
,您可以在其中提取值这样:
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
double myDouble = savedInstanceState.getDouble("myDouble");
int myInt = savedInstanceState.getInt("MyInt");
String myString = savedInstanceState.getString("MyString");
}