【问题标题】:Need Help in Downloading in Background Images in Android?在 Android 中下载背景图像时需要帮助吗?
【发布时间】:2011-06-10 07:40:22
【问题描述】:

我有一个图像视图,我写了滑动,在滑动的时候,图像是从互联网下载的,所以我认为我必须在滑动之前在后台下载图像,为此我需要使用 asynctask或服务或 IntentService,所有这些都将有助于下载和存储在 data/data/mypackages 中,但在我的情况下仍然刷卡会变慢任何想法,也告诉我哪一个是最好的,我是否以正确的方式调用

1.异步任务

2。服务

3. Intent Service如下图,

我很困惑哪种方法是正确的,因为我的问题仍然没有解决

这里是 asynctask 代码示例 sn-p

public class Demo extends Activity {

  @Override

  public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

       new FirstTask().execute(); // calling Asynctask here

  }

}

异步任务代码

private class FirstTask extends AsyncTask<Void, Void, Void> {
        private final ProgressDialog dialog = new ProgressDialog(Catalogue.this);
        int temp = 0;

        // can use UI thread here
        protected void onPreExecute() {
            this.dialog.setMessage("Loading...");
            this.dialog.setCancelable(false);
            //this.dialog.show();
            System.gc();
            Toast.makeText(Catalogue.this, "My Async  Created",
                    Toast.LENGTH_LONG).show();
        }

        @Override
        protected Void doInBackground(Void... params) {
            Looper.prepare();  
            try {

                myddownloadmethod();// calling my download method

            } catch (Exception e) {
                Util.trace("Error in Async"+e.getMessage());

            }
              Looper.loop();

            return null;
        }

        protected void onPostExecute(Void result) {

            if (this.dialog.isShowing()) {
                Toast.makeText(Catalogue.this, "My Async destroyed",
                        Toast.LENGTH_LONG).show();
                Toast.makeText(Catalogue.this, "count" + temp,
                        Toast.LENGTH_LONG).show();
                this.dialog.dismiss();
            }
        }
    }

这是我的服务sinppet

public class MyService extends Service implements Runnable

{      @Override

        public void onCreate() {

                super.onCreate();

                Thread mythread = new Thread(this);

                mythread.start();

        }



        public void run() {

                Looper.prepare();  

                try {

                        myddownloadmethod();// calling my download method

                } catch (Exception e1) {

                        // TODO Auto-generated catch block

                        e1.printStackTrace();

                }

                Looper.loop();

        }



        @Override
        public IBinder onBind(Intent intent) {

                // TODO Auto-generated method stub

                return null;

        }



}



Invoking Service  

public class ServicesDemo extends Activity {    

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

      startService(new Intent(this, MyService.class));


  }

}

这里是 IntentService 代码

public class Downloader extends IntentService {

    public Downloader() {
        super("Downloader");
    }

    @Override
    public void onCreate() {
        super.onCreate();


    }

    @Override
    public void onDestroy() {
        super.onDestroy();

            }

    @Override   
    public void onHandleIntent(Intent i) {

        try {
             myddownloadmethod();// calling my download method
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            Log.d("Error",e1.getMessage());
        }

    }
}

从 MyActivity 调用 IntentService

public class ServicesDemo extends Activity {    
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Intent i1=new Intent(this, Downloader.class);
        startService(i1);



      }

    }

【问题讨论】:

  • Looper.prepare();在 doInBackground 为什么?看起来像设计缺陷
  • @selvin:我遇到了这个异常,无法在没有调用 Looper.prepare() 的线程中创建处理程序,这就是我使用的原因
  • heh 不要在 doInBackground 中使用 UI 线程 ...使用 publishProgress 并覆盖 onProgressUpdate 并在此方法中对 UI 线程进行 somtheting ... AsyncTask 的工作原理...
  • @Selvin:可以在onProgressUpdate中举例说明
  • AsyncTask 就足够了...在 doInBackground 中您只下载数据,在 onPostExecute 中您使用新图像设置 ImageView

标签: android service android-asynctask intentservice


【解决方案1】:

使用服务下载它的最佳方式就像我从服务器下载文件并放入 SD 卡一样,也使用它的通知。 这是相当长的代码,但我认为是完美的,如果有什么不明白的,请去android开发者博客寻求服务。

public class DownloadService extends Service{

     SharedPreferences preferences;

    private static final String DOCUMENT_VIEW_STATE_PREFERENCES = "DjvuDocumentViewState";

      private Looper mServiceLooper;
      private ServiceHandler mServiceHandler;
      private NotificationManager mNM;
      String downloadUrl;
      public static boolean serviceState=false;

      // Handler that receives messages from the thread
      private final class ServiceHandler extends Handler {
          public ServiceHandler(Looper looper) {
              super(looper);
          }
          @Override
          public void handleMessage(Message msg) {
              downloadFile();
              showNotification(getResources().getString(R.string.notification_catalog_downloaded),"VVS");
              stopSelf(msg.arg1);
          }
      }


    @Override
        public void onCreate() {
            serviceState=true;
            mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
            HandlerThread thread = new HandlerThread("ServiceStartArguments",1);
            thread.start();

            // Get the HandlerThread's Looper and use it for our Handler 
            mServiceLooper = thread.getLooper();
            mServiceHandler = new ServiceHandler(mServiceLooper);

        }



     @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
             Log.d("SERVICE-ONCOMMAND","onStartCommand");  

               Bundle extra = intent.getExtras();
               if(extra != null){
                   String downloadUrl = extra.getString("downloadUrl");
                   Log.d("URL",downloadUrl);

                   this.downloadUrl=downloadUrl;
               }

              Message msg = mServiceHandler.obtainMessage();
              msg.arg1 = startId;
              mServiceHandler.sendMessage(msg);

              // If we get killed, after returning from here, restart
              return START_STICKY;
          }



     @Override
          public void onDestroy() {

             Log.d("SERVICE-DESTROY","DESTORY");
             serviceState=false;
            //Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); 
          }


     @Override
      public IBinder onBind(Intent intent) {
          // We don't provide binding, so return null
          return null;
      }


      public void downloadFile(){

            downloadFile(this.downloadUrl,fileName);


      }



        void showNotification(String message,String title) {
        // In this sample, we'll use the same text for the ticker and the expanded notification
        CharSequence text = message;

        // Set the icon, scrolling text and timestamp
       Notification notification = new Notification(R.drawable.icon, "vvs",
                System.currentTimeMillis());
        notification.flags |= Notification.FLAG_AUTO_CANCEL;
        Intent intent = new Intent(this, HomeScreenActivity.class);
        intent.setFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP);
         //The PendingIntent to launch our activity if the user selects this notification
        PendingIntent contentIntent = PendingIntent.getActivity(this.getBaseContext(), 0,
              intent, PendingIntent.FLAG_CANCEL_CURRENT);

        // Set the info for the views that show in the notification panel.
        notification.setLatestEventInfo(this, title,
                      text, contentIntent);
        // Send the notification.
        // We use a layout id because it is a unique number.  We use it later to cancel.
        mNM.notify(R.string.app_name, notification);
    }

  public void downloadFile(String fileURL, String fileName) {

    StatFs stat_fs = new StatFs(Environment.getExternalStorageDirectory().getPath());
    double avail_sd_space = (double)stat_fs.getAvailableBlocks() *(double)stat_fs.getBlockSize();
    //double GB_Available = (avail_sd_space / 1073741824);
    double MB_Available = (avail_sd_space / 10485783);
    //System.out.println("Available MB : " + MB_Available);
    Log.d("MB",""+MB_Available);
   try {
        File root =new File(Environment.getExternalStorageDirectory()+"/vvveksperten");
        if(root.exists() && root.isDirectory()) {

        }else{
            root.mkdir();
        }
        Log.d("CURRENT PATH",root.getPath());
        URL u = new URL(fileURL);
        HttpURLConnection c = (HttpURLConnection) u.openConnection();
        c.setRequestMethod("GET");
        c.setDoOutput(true);
        c.connect();
          int fileSize  = c.getContentLength()/1048576;
          Log.d("FILESIZE",""+fileSize);
          if(MB_Available <= fileSize ){
               this.showNotification(getResources().getString(R.string.notification_no_memory),getResources().getString(R.string.notification_error));
              c.disconnect();
              return;
          } 

        FileOutputStream f = new FileOutputStream(new File(root.getPath(), fileName));

        InputStream in = c.getInputStream();


        byte[] buffer = new byte[1024];
        int len1 = 0;
        while ((len1 = in.read(buffer)) > 0) {
            f.write(buffer, 0, len1);
        }
        f.close();
        File file = new File(root.getAbsolutePath() + "/" + "some.pdf");
        if(file.exists()){
            file.delete();
            Log.d("FILE-DELETE","YES");
        }else{
            Log.d("FILE-DELETE","NO");
        }
        File from =new File(root.getAbsolutePath() + "/" + fileName);
        File to = new File(root.getAbsolutePath() + "/" + "some.pdf");


        } catch (Exception e) {
        Log.d("Downloader", e.getMessage());

    }

【讨论】:

  • 我喜欢这个解决方案,但是让 HandlerThread 运行而不调用 quit() 或 quitSafely() 方法是否安全?或者 HandlerThread 会在一段时间后自动杀死自己吗?我不知道也找不到这样一个对象的生命周期。
  • 如何从我的活动中调用这个类?
【解决方案2】:

对于以后遇到此问题的任何人,请查看项目com.example.android.bitmapfun.ui.ImageGridActivity 的android 示例代码中使用的异步下载机制。它异步下载图像,并将它们缓存在 ImageView 中以供离线显示。人们已经将他们的代码包裹在这个代码上,并制作了图像加载库of their own。这些库使用 AsyncTask 而不是服务。预计异步任务将在几秒钟内完成它们的工作。

如果您要下载更大的内容,我建议您使用自 API 9 起可用的 DownloadManager,而不是使用服务。里面有很多代码可以增加下载的弹性。

下载管理器是处理长时间运行的 HTTP 下载的系统服务。客户端可能会请求将 URI 下载到特定的目标文件。下载管理器将在后台进行下载,处理 HTTP 交互并在失败或连接更改和系统重新启动后重试下载。这个类的实例应该通过getSystemService(String)通过DOWNLOAD_SERVICE来获取。通过此 API 请求下载的应用应为 ACTION_NOTIFICATION_CLICKED 注册一个广播接收器,以便在用户在通知中或从下载 UI 中单击正在运行的下载时进行适当处理。请注意,应用程序必须具有 INTERNET 权限才能使用此类。

【讨论】:

  • 我想很多人会想要比 UIL 更强大的东西。 UIL 还需要将数据写入外部存储。 DownloadManager 也很棒,但同样需要将数据写入辅助位置,然后复制到您的应用程序中。
【解决方案3】:

你可能过度设计了这个。我已经实现了动态加载图像的滑动,我只是使用了一个简单的实用程序类,它通过静态方法调用为我完成了这一切。 试试这个课程:

package com.beget.consumer.util;

/*
 Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.    
*/
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ImageView;

public class DrawableLoader {
    private final Map<String, Drawable> drawableMap;
    private WeakReference<ImageView> imageViewReference;

    public DrawableLoader() {
        drawableMap = new HashMap<String, Drawable>();
    }

    public Drawable fetchDrawable(String urlString) {
        if (drawableMap.containsKey(urlString)) {
            return drawableMap.get(urlString);
        }

        Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
        try {
            InputStream is = fetch(urlString);
            Drawable drawable = Drawable.createFromStream(is, "src");
            drawableMap.put(urlString, drawable);
            Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
                    + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
                    + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
            return drawable;
        } catch (MalformedURLException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        } catch (IOException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        }
    }

    public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {

        imageViewReference = new WeakReference<ImageView>(imageView);

        if (drawableMap.containsKey(urlString)) {
            imageViewReference.get().setImageDrawable(drawableMap.get(urlString));
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageViewReference.get().setImageDrawable((Drawable) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                //TODO : set imageView to a "pending" image
                Drawable drawable = fetchDrawable(urlString);
                Message message = handler.obtainMessage(1, drawable);
                handler.sendMessage(message);
            }
        };
        thread.start();
    }

    private InputStream fetch(String urlString) throws MalformedURLException, IOException {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet request = new HttpGet(urlString);
        HttpResponse response = httpClient.execute(request);
        return response.getEntity().getContent();
    }

}

这就是你所需要的。然后当你需要加载图片时,调用:

fetchDrawableOnThread("http://path/to/your/image.jpg", yourImageViewReference);

就是这样。
如果您有来自 JSON 对象的 URL,请将 URL 解析为您的字符串:
String url = jsonObj.getString("url"); 然后拨打fetchDrawableOnThread(url, yourImageViewReference);

【讨论】:

  • 我不能这样做,因为所有的 url 都是从 JSON 解析的动态 url
  • 和我一样。将 JSON 中的 URL 解析为变量,然后将字符串第一个参数替换为变量。
  • 游戏后期,但是当您的应用旋转时会怎样。这不会被杀死吗?
  • 可能。我从来没有遇到过任何问题,但也无法测试你的理论——太忙了。
【解决方案4】:

使用截击。 使用 volley network image view 你可以做到这一点

【讨论】:

    【解决方案5】:

    我们在这里使用最新的架构组件。我们为一些代表下载状态的标志使用实时数据制作一些观察者。在服务中,我们下载图像并完成更新实时数据,以便自动调用观察者方法

    猜你喜欢
    • 2015-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-22
    • 2016-05-30
    • 1970-01-01
    • 2014-06-10
    相关资源
    最近更新 更多