所以我想要实现的是创建一个将大(~200 MB)文件下载到应用程序内部目录的服务。它应该在取消后恢复(不重启)并在系统重启后自动恢复。它有时应该(如在propeties文件中所写)仅使用WiFi连接下载。
为此,我创建了IntentService
(这是一个合适的解决方案吗?),它由Frgament
的UI或BroadcastReceiver
启动(启动后):
@Override
public void onHandleIntent(final Intent intent) {
c.registerReceiver(receiver, new IntentFilter(
ConnectivityManager.CONNECTIVITY_ACTION));
c.registerReceiver(receiver, new IntentFilter(
WifiManager.NETWORK_STATE_CHANGED_ACTION));
receiver.onReceive(null, null); // To start the download the first time
}
最后一行调用处理下载过程的BroadcastReceiver
。这是我尝试确保一次只有一个正在下载的方式:
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
boolean allowed = isConnectionAllowed();
if (allowed && !thread.isAlive()) {
thread.start();
} else if (allowed && thread.isAlive()) {
thread.notify(); // Can this cause any problems in this case?
} else if (!allowed && thread.isAlive()) {
try {
thread.wait();
} catch (InterruptedException e) {
if (StartActivity.DEV_MODE)
Log.i(StartActivity.LOG_TAG, Log.getStackTraceString(e));
}
}
}
};
下载itselv分开运行Thread
。
private Thread thread = new Thread() {
@SuppressWarnings("resource")
@Override
public void run() {
HttpURLConnection connection = null;
BufferedInputStream input = null;
RandomAccessFile output = null;
try {
long already_downloaded = 0;
URL url = new URL(getSource());
File outputFileCache = new File(getDestination());
connection = (HttpURLConnection) url.openConnection();
if (outputFileCache.exists()) {
connection.setAllowUserInteraction(true);
connection.setRequestProperty("Range", "bytes="
+ outputFileCache.length() + "-");
}
connection.setConnectTimeout(14000);
connection.setReadTimeout(20000);
connection.connect();
if (connection.getResponseCode() / 100 != 2)
throw new Exception("Invalid response code!");
else {
String connectionField = connection
.getHeaderField("content-range");
if (connectionField != null) {
String[] connectionRanges = connectionField.substring(
"bytes=".length()).split("-");
already_downloaded = Long.valueOf(connectionRanges[0]);
}
if (connectionField == null && outputFileCache.exists())
outputFileCache.delete();
long fileLength = connection.getContentLength()
+ already_downloaded;
input = new BufferedInputStream(connection.getInputStream());
output = new RandomAccessFile(outputFileCache, "rw");
output.seek(already_downloaded);
byte data[] = new byte[1024];
int count = 0;
int progress = 0;
int progress_last_value = 0;
while ((count = input.read(data, 0, 1024)) != -1
&& progress != 100) {
already_downloaded += count;
output.write(data, 0, count);
progress = (int) ((already_downloaded * 100) / fileLength);
if (progress != progress_last_value) {
// Update notification
}
}
}
} catch (MalformedURLException e) {
if (StartActivity.DEV_MODE)
Log.i(StartActivity.LOG_TAG, Log.getStackTraceString(e));
} catch (IOException e) {
if (StartActivity.DEV_MODE)
Log.i(StartActivity.LOG_TAG, Log.getStackTraceString(e));
} catch (Exception e) {
if (StartActivity.DEV_MODE)
Log.i(StartActivity.LOG_TAG, Log.getStackTraceString(e));
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
if (connection != null)
connection.disconnect();
} catch (IOException e) {
if (StartActivity.DEV_MODE)
Log.i(StartActivity.LOG_TAG, Log.getStackTraceString(e));
}
}
// notify the Fragment using a `LocalBroadcast`.
}
};
为了确保WiFi连接保持活动,我使用WifiLock
类。
注意:我在一些情况下缩短了代码,但我已经设法编写了该代码。
所以我不确定这是否是解决我问题的好方法:
IntentService
还是普通Service
?Thread
一个好的解决方案并且有效吗?
HttpURLConnection
不会过期吗?wait()
和notify()
)我知道这是很多代码,但它是我能得到的最接近的代码。我希望有人知道一个解决方案,因为我在这个主题上找不到任何有用的东西(“只在WiFi上打开”,使用谷歌和StackOverflow。)
提前致谢, 菲利克斯
(评论是否需要整个Class
)