不可见的进度条未通过代码显示
Invisible Progress Bar not showing up through code
我正在制作一个项目 Android 应用程序,它拍摄图像 URL,下载图像并显示图像。如果图像尺寸较大,我想向用户显示图像正在下载的不确定进度。
Java代码:
public class MainActivity extends AppCompatActivity {
ImageView downloadedImg;
ProgressBar progressBar;
Handler handler;
public void downloadImage(View view){
progressBar.setVisibility(View.VISIBLE);
ImageDownloader task = new ImageDownloader();
Bitmap myimage;
try {
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
downloadedImg.setImageBitmap(myimage);
}
catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downloadedImg = (ImageView)findViewById(R.id.imageView);
progressBar = (ProgressBar)findViewById(R.id.pbar);
handler = new Handler();
}
public class ImageDownloader extends AsyncTask<String,Void,Bitmap>{
protected void onPreExecute(){
super.onPreExecute();
//progressBar.setVisibility(View.VISIBLE);
}
@Override
protected Bitmap doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.connect();
InputStream inputStream = connection.getInputStream();
Bitmap mybitmap = BitmapFactory.decodeStream(inputStream);
return mybitmap;
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
handler.post(new Runnable() {
@Override
public void run() {
progressBar.setVisibility(View.GONE);
downloadedImg.setVisibility(View.VISIBLE);
}
});
}
}
public void reset(View view){
downloadedImg.setVisibility(View.GONE);
progressBar.setVisibility(View.INVISIBLE);
}
}
XML代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="match_parent"
tools:context="com.example.syeddanish.downloadingimages.MainActivity">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:onClick="downloadImage"
android:text="Download Image" />
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/button"
android:onClick="reset"
android:text="Reset" />
<ProgressBar
android:id="@+id/pbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:indeterminate="true"
android:visibility="invisible" />
<ImageView
android:id="@+id/imageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:visibility="gone"
android:layout_below="@+id/button1" />
</RelativeLayout>
我面临的问题是我希望进度条在下载开始时可见(即 "Download Image button is pressed" 时)。我正在尝试以两种方式做到这一点,即
- 通过在开头使用
progressbar.setVisibility(View.VISIBLE);
"Download Image" 按钮的 onClick 方法。
或
- 通过在 ASyncTask 的 onPreExecute() 方法中使用
progressbar.setVisibility(View.VISIBLE);
,但使用上述任何方法都不会显示进度条。
谁能指出我做错了什么?
没有 NetworkOnMainThreadException
,此代码是否编译 运行?
您的问题是 get()
的用法
这部分:
Bitmap myimage;
try {
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
downloadedImg.setImageBitmap(myimage);
}
您尝试从 task.execute(...)
获取图像,但 task.get()
根据文档:
[...]Waits if necessary for the computation to complete, and then retrieves its result.[...]
所以你正在等待你的 "task" 在主线程上执行并阻塞它,直到完成。正因为如此,你的进步
永远不可见,因为 UI-Thread 被阻塞了。一旦你的任务完成,
进度设置回不可见。
此外,不要重新发明轮子。使用可用的库之一
用于图像下载和缓存。
两者还提供使用 (1) 回退和 (2) 加载图像的功能。
如果您仍然喜欢自己尝试,请不要使用 Pokémon- "gotta catch'em all" 方法来捕获异常,而是处理特定的 Exceptions
可能会发生并向用户显示消息,将其发送给您的崩溃跟踪器等。仅捕获您希望抛出的异常,否则...让它崩溃。
我不明白,为什么你应该在那里捕获异常。
AsyncTask、Activity 和内存泄漏
接下来是,AsyncTasks
没有整齐地耦合到 Activities
生命周期。当你 运行 你的任务在后台执行时,但是
您的 activity 完成后,此任务仍将存在并泄漏对您的 activity 的引用。这会导致内存泄漏,因为 GC 无法正确完成它的工作,在您之后进行清理。
让你的 AsyncTask 至少是静态的 class 和 stop/kill 任务,一旦你的 activity 完成。
多项任务
下一步,检查您是否已经下载了图像,一旦用户单击了按钮,或者您将创建多个任务。
因此,让您的 ImageDownloader 成为您 activity 的成员并检查它是否已经在执行或完成。 (将其从您的方法中取出并放在 activity class 头部下方)。当您的 activity 调用 onPause()
或 onDestroy()
时,用火杀死任务。
也要注意 方向变化。
Android 任务 API 而不是 AsyncTask
我强烈建议使用 android 任务 api。 (com.google.android.gms.tasks
)
它非常适用于任务,运行在主线程或工作线程上。包括延续,提供 Future
类似的功能,并且可以与 Activities 相结合。
参考文献:gms Task API Doc
尝试将 downloadedImg.setImageBitmap(myimage);
放入 onPostExecute(Bitmap bitmap)
处理程序并更改:
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
至:
task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg");
同时将 Bitmap myimage;
作为全局变量放在您的 Asynctask class 上并更改:
Bitmap mybitmap = BitmapFactory.decodeStream(inputStream);
return mybitmap;
至:
myimage= BitmapFactory.decodeStream(inputStream);
关于 doInBackground
考虑使用 pBar.setAlpha(1f);
当我遇到类似问题时,它很有帮助。
我正在制作一个项目 Android 应用程序,它拍摄图像 URL,下载图像并显示图像。如果图像尺寸较大,我想向用户显示图像正在下载的不确定进度。
Java代码:
public class MainActivity extends AppCompatActivity {
ImageView downloadedImg;
ProgressBar progressBar;
Handler handler;
public void downloadImage(View view){
progressBar.setVisibility(View.VISIBLE);
ImageDownloader task = new ImageDownloader();
Bitmap myimage;
try {
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
downloadedImg.setImageBitmap(myimage);
}
catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downloadedImg = (ImageView)findViewById(R.id.imageView);
progressBar = (ProgressBar)findViewById(R.id.pbar);
handler = new Handler();
}
public class ImageDownloader extends AsyncTask<String,Void,Bitmap>{
protected void onPreExecute(){
super.onPreExecute();
//progressBar.setVisibility(View.VISIBLE);
}
@Override
protected Bitmap doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.connect();
InputStream inputStream = connection.getInputStream();
Bitmap mybitmap = BitmapFactory.decodeStream(inputStream);
return mybitmap;
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
handler.post(new Runnable() {
@Override
public void run() {
progressBar.setVisibility(View.GONE);
downloadedImg.setVisibility(View.VISIBLE);
}
});
}
}
public void reset(View view){
downloadedImg.setVisibility(View.GONE);
progressBar.setVisibility(View.INVISIBLE);
}
}
XML代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="match_parent"
tools:context="com.example.syeddanish.downloadingimages.MainActivity">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:onClick="downloadImage"
android:text="Download Image" />
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/button"
android:onClick="reset"
android:text="Reset" />
<ProgressBar
android:id="@+id/pbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:indeterminate="true"
android:visibility="invisible" />
<ImageView
android:id="@+id/imageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:visibility="gone"
android:layout_below="@+id/button1" />
</RelativeLayout>
我面临的问题是我希望进度条在下载开始时可见(即 "Download Image button is pressed" 时)。我正在尝试以两种方式做到这一点,即
- 通过在开头使用
progressbar.setVisibility(View.VISIBLE);
"Download Image" 按钮的 onClick 方法。 或 - 通过在 ASyncTask 的 onPreExecute() 方法中使用
progressbar.setVisibility(View.VISIBLE);
,但使用上述任何方法都不会显示进度条。
谁能指出我做错了什么?
没有 NetworkOnMainThreadException
,此代码是否编译 运行?
您的问题是 get()
这部分:
Bitmap myimage;
try {
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
downloadedImg.setImageBitmap(myimage);
}
您尝试从 task.execute(...)
获取图像,但 task.get()
根据文档:
[...]Waits if necessary for the computation to complete, and then retrieves its result.[...]
所以你正在等待你的 "task" 在主线程上执行并阻塞它,直到完成。正因为如此,你的进步 永远不可见,因为 UI-Thread 被阻塞了。一旦你的任务完成, 进度设置回不可见。
此外,不要重新发明轮子。使用可用的库之一 用于图像下载和缓存。
两者还提供使用 (1) 回退和 (2) 加载图像的功能。
如果您仍然喜欢自己尝试,请不要使用 Pokémon- "gotta catch'em all" 方法来捕获异常,而是处理特定的 Exceptions
可能会发生并向用户显示消息,将其发送给您的崩溃跟踪器等。仅捕获您希望抛出的异常,否则...让它崩溃。
我不明白,为什么你应该在那里捕获异常。
AsyncTask、Activity 和内存泄漏
接下来是,AsyncTasks
没有整齐地耦合到 Activities
生命周期。当你 运行 你的任务在后台执行时,但是
您的 activity 完成后,此任务仍将存在并泄漏对您的 activity 的引用。这会导致内存泄漏,因为 GC 无法正确完成它的工作,在您之后进行清理。
让你的 AsyncTask 至少是静态的 class 和 stop/kill 任务,一旦你的 activity 完成。
多项任务
下一步,检查您是否已经下载了图像,一旦用户单击了按钮,或者您将创建多个任务。
因此,让您的 ImageDownloader 成为您 activity 的成员并检查它是否已经在执行或完成。 (将其从您的方法中取出并放在 activity class 头部下方)。当您的 activity 调用 onPause()
或 onDestroy()
时,用火杀死任务。
也要注意 方向变化。
Android 任务 API 而不是 AsyncTask
我强烈建议使用 android 任务 api。 (com.google.android.gms.tasks
)
它非常适用于任务,运行在主线程或工作线程上。包括延续,提供 Future
类似的功能,并且可以与 Activities 相结合。
参考文献:gms Task API Doc
尝试将 downloadedImg.setImageBitmap(myimage);
放入 onPostExecute(Bitmap bitmap)
处理程序并更改:
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
至:
task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg");
同时将 Bitmap myimage;
作为全局变量放在您的 Asynctask class 上并更改:
Bitmap mybitmap = BitmapFactory.decodeStream(inputStream);
return mybitmap;
至:
myimage= BitmapFactory.decodeStream(inputStream);
关于 doInBackground
考虑使用 pBar.setAlpha(1f);
当我遇到类似问题时,它很有帮助。