Android背景线程

时间:2016-12-02 11:32:43

标签: android multithreading performance android-asynctask intentservice

我正在制作图像处理器应用。我需要扫描手机中的图片并列出它们的像素数。所以这将对性能产生巨大影响,据我所知,我需要让它在后台线程上运行。

所以我的问题是,最好的办法是什么?我知道IntentService可能是最好的解决方案,但我不确定如何用它实现进度条,我需要返回Picture对象,然后在随机播放按钮上更新UI。我正在使用Glide库进行更新,以便顺利进行。

阅读关于Asynctasks,我偶然发现评论它是如何坏,并导致内存泄漏,应避免使用它。 rXJava目前太复杂了。  这是我的代码:

主要活动:

@OnClick(R.id.shuffle)
public void shuffleList() {
    Collections.shuffle(listOfImageFiles);
    recyclerViewAdapter = new PictureRecycleViewAdapter(listOfImageFiles, this);
    recyclerView.swapAdapter(recyclerViewAdapter, false);
    recyclerViewAdapter.notifyDataSetChanged();
}

@OnClick(R.id.scan)
public void processImages() {

    //progress bar

    listOfPictures = new ArrayList<>();

    //Gets data from default camera roll directory. Note that some of the phone companies have different file paths. So instead of hardcoding string paths, I used this instead.
    String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath();
    File filePath = new File(path);
    listOfImageFiles = scanPhotos(filePath);

    // async?
    for (File file : listOfImageFiles
            ) {
        Bitmap bitmap = BitmapFactory.decodeFile(file.getPath());

        //int is sufficient for most today's pixels. long would be overkill - 4 vs 8 bytes
        int pixels = bitmap.getHeight() * bitmap.getWidth();

        listOfPictures.add(new Picture(file.getPath(), pixels));
    }
}

public List<File> scanPhotos(File directory) {
    List<File> listOfPictures = new ArrayList<>();
    try {
        File[] files = directory.listFiles();
        for (File file : files
                ) {
            if (file.isDirectory() && !file.isHidden()) {
                listOfPictures.addAll(scanPhotos(file));
            } else {
                if (file.getName().endsWith(".jpg") || file.getName().endsWith(".jpeg") || file.getName().endsWith(".png")) {
                    listOfPictures.add(file);
                }
            }
        }
    } catch (Exception e) {
        Log.e(e.getMessage(), e.getMessage());
    }

    return listOfPictures;
}

2 个答案:

答案 0 :(得分:2)

AsyncTask很好,你只需要小心它的实现。

但是,对于运行时间较长的任务,有更好的选择。 IntentService是个不错的选择。

使用IntentService时,如果涉及到自适应用户界面,则可以添加两项内容。

通知

创建一个持续通知,指示您的应用正在处理某些事情。这让用户知道他们的CPU周期被后台的东西吃掉了,他们不太可能(?)对他们的设备运行速度变慢而感到困惑。

此外,当Android正在寻找要杀死以释放内存的后台应用程序时,它会为您的应用程序提供更多的活动余量。

EventBus

使用EventBus库可以使UI报告变得非常简单。我个人是greenbot/EventBus的粉丝,但还有其他人。

实施例

Activity

@Subscribe(threadMode = ThreadMode.MAIN)  
public void onProgressEvent(ProgressEvent event) {
    mProgressBar.setProgress(event.value);
}

IntentService

EventBus.getDefault().post(new ProgressEvent(5000));

答案 1 :(得分:2)

IntentService

IntentService绝对是一种有效的方法。您可以使用广播将结果返回到应用的其他组件,无论是活动还是其他服务,例如:

  1. 启动IntentService - 如果您需要一些参数,请将它们放在服务意图的附加内容中。
  2. 您的IntentService在后​​台线程上运行,直到计算完成。
  3. 完成后,发送一个包含意图附加内容的计算结果的广播。
  4. 在您的活动中,注册一个将监听您的计算结果广播的BroadcastReceiver
  5. Activity中收到广播后,从意图附加内容中检索计算结果。
  6. 您也可以实施服务收到的广播,例如取消计算或更新参数。

    IntentService的一个优点是,您可以轻松地将其与JobScheduler API集成,以推迟执行,直到满足某些系统条件。

    替代

    • 您可以使用总线库(例如https://github.com/greenrobot/EventBus)在ActivityService之间进行通信 - 唯一的问题是,EventBus无法与远程服务一起使用(正在运行)在一个单独的过程中。)

    • 正如您所提到的,将RxJava与 IO 计算调度程序一起使用也是一个好主意。

    • AsyncTask只要您不将其与活动的硬引用联系起来就可以了 - 不要将其作为Activity的内部类实现,如果您想要将结果传回去,请执行通过WeakReference<T>