【问题标题】:Android - Running Service At Boot With No ActivityAndroid - 在没有活动的情况下在启动时运行服务
【发布时间】:2018-11-22 20:12:03
【问题描述】:

问题:

在 Android 中,似乎没有办法指定您希望同步到云的 DCIM 文件夹中的各个文件夹。 Facebook 应用程序将图像保存到 DCIM/Facebook,因此我保存的任何图像都会自动同步到云端。我可以通过在文件夹中放置一个 .NOMEDIA 文件来解决此问题,但这意味着我无法在不进入文件资源管理器的情况下浏览文件,因此我无法轻松访问以消息形式发送这些图像。

我目前正在开发一个 Android 应用程序,以自动将 .NOMDEIA 文件以外的文件从 DCIM/Facebook 移动到图片/Facebook。我目前有可以在 MainActivity 类中执行此操作的代码,我希望将其转换为将自动运行的服务。

简而言之,我希望此服务在启动时启动并始终运行而不显示活动,因此它可以消除我的任何手动工作。同样,我不想手动启动任何东西,而且我认为不需要任何活动,因为我不想要任何用户交互。我已经阅读了很多页面,迷失在文档中,并且似乎看过无数关于 Service、IntentService、JobScheduler 等的帖子,我目前正在研究实施和正确的方法。

对于每隔几秒运行一次的 JobSchedule 来说,这是一个很好的例子吗?它应该是一个在每次迭代中等待几秒钟的循环中一遍又一遍地运行代码的服务吗?是否可以在向文件夹添加内容时触发服务?

如上所述,我一直在努力实施。在这一点上,我唯一能做的就是从 MainActivity 中调用该服务,但这会在 Activity 短暂打开和关闭时发生。这是不受欢迎的行为。在这一点上事情变得有点混乱,所以我选择不包含任何代码,希望有人可以为我指出正确的文档/教程或提供我可以使用的适当框架。我宁愿不从一开始就搅浑水。

重要说明:我的活动实现请求 READ_EXTERNAL_STORAGE 的权限(据我了解,您不需要请求 WRITE_EXTERNAL_STORAGE 的权限;我的代码无需请求该权限即可工作)但我也不确定如何确保这一点为服务完成,因为请求权限的方法似乎希望将活动作为参数之一。

编辑:为接收者和服务添加清单和代码

FacebookImageListener.java

public class FacebookImageListener extends BroadcastReceiver {


    @Override
    public void onReceive(Context context, Intent intent) {
        context.startService(new Intent(context, FacebookImageMoverService.class));
        Log.i("FacebookImageMoverService", "started");
    }
}

FacebookImageMoverService.java

public class FacebookImageMoverService extends Service {

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        while (true) {

            //TODO remove this
            Log.i("imagemover", "DELETE THIS");

//            String path = this.getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath() + "/Facebook";
            String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() + "/Facebook";
            Log.d("Files", "Path: " + path);
            File directory = new File(path);
            File[] files = directory.listFiles();

            Log.d("Files", "Size: " + files.length);
            for (int i = 0; i < files.length; i++) {
                Toast toast = Toast.makeText(this.getApplicationContext(), "FileName:" + files[i].getName(), Toast.LENGTH_LONG);
                toast.show();
                Log.d("Files", "FileName:" + files[i].getName());

                if (!files[i].getName().equals(".NOMEDIA")) {
//                    moveFile(path + "/", files[i].getName(), this.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/Facebook/");
                    moveFile(path + "/", files[i].getName(), Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/Facebook/");
                }
            }

            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        //TODO check this out
//        return Service.START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        //TODO for communication return IBinder implementation
        return null;
    }

    private void moveFile(String inputPath, String inputFile, String outputPath) {

        InputStream in = null;
        OutputStream out = null;
        try {

            //create output directory if it doesn't exist
            File dir = new File(outputPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }


            in = new FileInputStream(inputPath + inputFile);
            out = new FileOutputStream(outputPath + inputFile);

            byte[] buffer = new byte[1024];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
            in.close();
            in = null;

            // write the output file
            out.flush();
            out.close();
            out = null;

            // delete the original file
            new File(inputPath + inputFile).delete();


        } catch (FileNotFoundException fnfe1) {
            Log.e("tag", fnfe1.getMessage());
        } catch (Exception e) {
            Log.e("tag", e.getMessage());
        }

    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="shogg.facebookimagemover"
    >

    <!--<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />-->
    <!--<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />-->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />


    <application android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round">

        <receiver android:name=".FacebookImageListener"
            android:icon="@mipmap/ic_launcher"
            android:exported="true"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

        <service android:enabled="true" android:name=".FacebookImageMoverService" />
    </application>


</manifest>

【问题讨论】:

  • 从 Android 3.1 开始,您的应用将在 stopped 状态下安装,并且在您的应用以某种方式明确启动之前,在您的应用清单中注册的接收器将无法工作。基本上,您需要一个Activity,用户可以在安装后至少运行一次以使您的应用退出该状态。

标签: android service android-service android-jobscheduler


【解决方案1】:

在您的AndroidManifest.xml 中注册一个BroadcastReceiver,并通过将此权限添加到您的清单来请求侦听设备启动广播的权限:

android:permission="android.permission.RECEIVE_BOOT_COMPLETED"&gt;

然后,您可以在 BroadcastListerneronReceive() 方法中启动您的服务,而无需启动应用程序的主要活动,以任何方式阻碍用户。

【讨论】:

  • 感谢您的帮助。我将开始研究这个实现。这是否解决了服务需要读取存储权限的问题,还是不必为服务指定权限?
  • 取决于你在哪里写。从 API 级别 19 开始,读取/写入 Context.getExternalFilesDir(String)Context.getExternalCacheDir(). 返回的应用程序特定目录中的文件不需要此权限,这直接取自参考。如果这还不够,您应该仍然可以通过服务请求权限。
  • 我似乎仍然无法让这个解决方案发挥作用。该服务似乎根本没有执行,无论是从 Android Studio 运行还是重新启动设备后。如果这有任何帮助,我已经添加了上面的代码。我看到的唯一值得注意的是:“等待应用程序上线:shogg.facebookimagemover.test | shogg.facebookimagemover”
猜你喜欢
  • 2015-03-07
  • 2016-06-27
  • 1970-01-01
  • 1970-01-01
  • 2015-11-17
  • 2013-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多