我为我的Android应用程序构建了更新类。它工作正常,除了下载内部AsyncTask类。
我想在下载文件时在LoadingActivity中显示进度对话框。
首先,我在 onCreate 方法中调用更新类。作为参数,我发送活动上下文。然后在更新类构造函数中,我调用检查内部类(AsyncTask),它从URL解析JSON响应(正常工作)并调用下载(下一步) 更新内部类),这就是问题。
当我尝试创建 ProgressDialog 对象时,编译器会抛出:
04-01 02:53:56.864 24393-24425/pl.com.mpkostrowiec.schedule E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #1
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:299)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
at java.util.concurrent.FutureTask.run(FutureTask.java:239)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:838)
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:197)
at android.os.Handler.<init>(Handler.java:111)
at android.app.Dialog.<init>(Dialog.java:107)
at android.app.AlertDialog.<init>(AlertDialog.java:114)
at android.app.AlertDialog.<init>(AlertDialog.java:98)
at android.app.ProgressDialog.<init>(ProgressDialog.java:77)
at pl.com.mpkostrowiec.schedule.DownloadAsync.<init>(DownloadAsync.java:30)
at pl.com.mpkostrowiec.schedule.Updates$Check.doInBackground(Updates.java:128)
at pl.com.mpkostrowiec.schedule.Updates$Check.doInBackground(Updates.java:74)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:838)
我认为ProgressDialog构造函数无法从Updates类访问上下文变量,因此我尝试将其作为参数发送,但它无法解决问题。
LoadingActivity 类:
package pl.com.mpkostrowiec.schedule;
import ...
public class LoadingActivity extends Activity {
private final Preferences preferences = new Preferences(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loading);
preferences.savePreference("Preferences", "firstRun", "1");
// Check if first run
if (preferences.readPreference("Preferences", "firstRun").equals("0")) {
System.out.println("****************** Not first run");
} else {
// Create directory
File dir = this.getDir("Versions", MODE_PRIVATE);
new Updates(this);
}
}
}
更新类:
package pl.com.mpkostrowiec.schedule;
import ...
interface AfterExecuteListener {
public void afterDownload(String[] versionData, int type);
}
public class Updates implements AfterExecuteListener{
private static VersionsTable versionsTable;
private Context context;
public static Boolean status_current = false;
public static Boolean status_new = false;
private final int TYPE_CURRENT = 0;
private final int TYPE_NEW = 1;
private static final String URL = "http://www.mpkostrowiec.com.pl/preview/";
private static final String GET_VERSIONS = "includes/android/versions.php";
private static final String RESOURCES = "resources/android/versions/";
private static final String EXTENSION = ".db";
public Updates(Context context) {
this.context = context;
versionsTable = new VersionsTable(this.context);
new Check(TYPE_CURRENT).execute();
}
public final void afterDownload(String[] versionData, int type) {
// Add version data to DB
versionsTable.open();
versionsTable.add(versionData);
versionsTable.close();
// Set status
if (type == TYPE_CURRENT) {
System.out.println("****************** Downloaded: " + type);
status_current = true;
} else if (type == TYPE_NEW) {
System.out.println("****************** Downloaded: " + type);
status_new = true;
}
Schedule();
}
private void Schedule() {
if (status_current) {
if (status_new) {
System.out.println("****************** SUCCESS");
} else {
new Check(TYPE_NEW).execute();
}
}
}
private class Check extends AsyncTask<String, Integer, String> {
public AfterExecuteListener mListener;
private int type;
public Check(int type) {
this.type = type;
}
@Override
protected String doInBackground(String... Url) {
String[] typeStr = {"current", "new"};
// Get versions form URL
JSONObject json = null;
String versions = null;
HttpResponse response;
HttpClient myClient = new DefaultHttpClient();
HttpPost myConnection = new HttpPost(URL + GET_VERSIONS);
try {
response = myClient.execute(myConnection);
versions = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try{
JSONObject jObject = new JSONObject(versions);
json = jObject.getJSONObject(typeStr[type]);
if (json.length() > 1) {
String[] versionData = {json.getString("id"),
json.getString("name"),
json.getString("expDate")};
versionsTable.open();
Boolean idExist = versionsTable.check(versionData[0]);
versionsTable.close();
// Check version
if (!idExist) {
// Start downloading
Download download = new Download(versionData, type);
download.setListener(Updates.this);
download.execute(URL + RESOURCES + versionData[0] + EXTENSION);
}
} else {
// If array contains only false field then do not update
if (type == TYPE_CURRENT) {
Updates.status_current = true;
} else if (type == TYPE_NEW) {
Updates.status_new = true;
}
Schedule();
}
} catch ( JSONException e) {
e.printStackTrace();
}
return null;
}
}
private class Download extends AsyncTask<String, Integer, String> {
public ProgressDialog mProgressDialog;
public AfterExecuteListener mListener;
private String[] versionData;
private int type;
public Download(String[] versionData, int type) {
this.versionData = versionData;
this.type = type;
// Create progress dialog
mProgressDialog = new ProgressDialog(context);
// Set your progress dialog Title
mProgressDialog.setTitle("Updating...");
// Set your progress dialog Message
mProgressDialog.setMessage("Update in progress. Please wait.");
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// Show progress dialog
mProgressDialog.show();
}
@Override
protected String doInBackground(String... Url) {
try {
java.net.URL url = new URL(Url[0]);
URLConnection connection = url.openConnection();
connection.connect();
// Detect the file lenghth
int fileLength = connection.getContentLength();
// Locate storage location
String filepath = context.getApplicationInfo().dataDir + "/Versions";
// Download the file
InputStream input = new BufferedInputStream(url.openStream());
// Save the downloaded file
OutputStream output = new FileOutputStream(filepath + "/" + versionData[0] + ".db");
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
// Publish the progress
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
// Close connection
output.flush();
output.close();
input.close();
} catch (Exception e) {
// Error Log
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
// Update the progress dialog
mProgressDialog.setProgress(progress[0]);
}
@Override
protected void onPostExecute(String result) {
// Dismiss the progress dialog
mProgressDialog.dismiss();
mListener.afterDownload(versionData, type);
}
private void setListener(AfterExecuteListener listener) {
mListener = listener;
}
}
}