当相机拍摄新照片时,Oreo JobScheduler无法正常工作

时间:2018-06-15 09:19:51

标签: android android-jobscheduler

在android奥利奥广播接收器不适用于“android.hardware.action.NEW_PICTURE”所以我必须用JobScheduler替换它。 现在问题是PhotoContentsJob被调用并显示我重新启动应用程序时拍摄的新图像的祝酒词但是一旦拍摄新照片它就无法在后台运行。请帮助我如何实现它。 附上的代码供参考。

在MainActivity onCreate方法

 if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        scheduleCameraJob();
    }

@RequiresApi(api = Build.VERSION_CODES.O)
private void scheduleCameraJob() {
     final Uri MEDIA_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/");

    JobInfo.Builder builder = new JobInfo.Builder(11,
            new ComponentName(this, PhotosContentJob.class.getName()));
    // Look for specific changes to images in the provider.
    builder.addTriggerContentUri(new JobInfo.TriggerContentUri(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
    // Also look for general reports of changes in the overall provider.
    builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI, 0));
    builder.setTriggerContentUpdateDelay(1);
    builder.setTriggerContentMaxDelay(100);
    JobInfo myCameraJob  = builder.build();
    JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
    jobScheduler.schedule(myCameraJob);
}

PhotosContentJob服务 - 工作代码

@RequiresApi(api = Build.VERSION_CODES.O)
public class PhotosContentJob extends JobService {

SpreadsheetImage spreadsheetImage;
DatabaseHandler databaseHandler;

// Path segments for image-specific URIs in the provider.
static final List<String> EXTERNAL_PATH_SEGMENTS
        = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.getPathSegments();
// The columns we want to retrieve about a particular image.
static final String[] PROJECTION = new String[] {
        MediaStore.Images.ImageColumns._ID, MediaStore.Images.ImageColumns.DATA
};
static final int PROJECTION_ID = 0;
static final int PROJECTION_DATA = 1;
// This is the external storage directory where cameras place pictures.
static final String DCIM_DIR = Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_DCIM).getPath();


JobParameters mRunningParams;

// Check whether this job is currently scheduled.
public static boolean isScheduled(Context context) {
    JobScheduler js = context.getSystemService(JobScheduler.class);
    List<JobInfo> jobs = js.getAllPendingJobs();
    if (jobs == null) {
        return false;
    }
    for (int i=0; i<jobs.size(); i++) {
        if (jobs.get(i).getId() == 11) {
            return true;
        }
    }
    return false;
}

// Cancel this job, if currently scheduled.
public static void cancelJob(Context context) {
    JobScheduler js = context.getSystemService(JobScheduler.class);
    js.cancel(11);
}

@Override
public boolean onStartJob(JobParameters params) {
    Log.e("PhotosContentJob", "JOB STARTED!");
    mRunningParams = params;
    // Instead of real work, we are going to build a string to show to the user.
    Date addedDate=new Date();
    databaseHandler=new DatabaseHandler(getApplicationContext());
    spreadsheetImage=new SpreadsheetImage();

    StringBuilder sb = new StringBuilder();
    // Did we trigger due to a content change?
    if (params.getTriggeredContentAuthorities() != null) {
        boolean rescanNeeded = false;
        if (params.getTriggeredContentUris() != null) {
            // If we have details about which URIs changed, then iterate through them
            // and collect either the ids that were impacted or note that a generic
            // change has happened.
            ArrayList<String> ids = new ArrayList<>();
            for (Uri uri : params.getTriggeredContentUris()) {
                List<String> path = uri.getPathSegments();
                if (path != null && path.size() == EXTERNAL_PATH_SEGMENTS.size()+1) {
                    // This is a specific file.
                    ids.add(path.get(path.size()-1));
                } else {
                    // Oops, there is some general change!
                    rescanNeeded = true;
                }
            }
            if (ids.size() > 0) {
                // If we found some ids that changed, we want to determine what they are.
                // First, we do a query with content provider to ask about all of them.
                StringBuilder selection = new StringBuilder();
                for (int i=0; i<ids.size(); i++) {
                    if (selection.length() > 0) {
                        selection.append(" OR ");
                    }
                    selection.append(MediaStore.Images.ImageColumns._ID);
                    selection.append("='");
                    selection.append(ids.get(i));
                    selection.append("'");
                }
                // Now we iterate through the query, looking at the filenames of
                // the items to determine if they are ones we are interested in.
                Cursor cursor = null;
                boolean haveFiles = false;
                try {
                    cursor = getContentResolver().query(
                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            PROJECTION, selection.toString(), null, null);
                    while (cursor.moveToNext()) {
                        // We only care about files in the DCIM directory.
                        String dir = cursor.getString(PROJECTION_DATA);
                        if (dir.startsWith(DCIM_DIR)) {
                            if (!haveFiles) {
                                haveFiles = true;
                                sb.append("New photos:\n");
                            }
                            sb.append(cursor.getInt(PROJECTION_ID));
                            sb.append(": ");
                            sb.append(dir);
                            sb.append("\n");

                            spreadsheetImage.ImagePath=dir;
                            spreadsheetImage.AddedOn=addedDate;
                            databaseHandler.AddSpreadSheetImage(spreadsheetImage);
                        }
                    }
                } catch (SecurityException e) {
                    sb.append("Error: no access to media!");
                } finally {
                    if (cursor != null) {
                        cursor.close();
                    }
                }
            }
        } else {
            // We don't have any details about URIs (because too many changed at once),
            // so just note that we need to do a full rescan.
            rescanNeeded = true;
        }
        if (rescanNeeded) {
            sb.append("Photos rescan needed!");
        }
    } else {
        sb.append("(No photos content)");
    }

    Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
    jobFinished(params, /*reschedule*/false);
    scheduleCameraJob( /*immediate*/false);
    return true;
}
@Override
public boolean onStopJob(JobParameters params) {

    return false;
}

@RequiresApi(api = Build.VERSION_CODES.O)
private void scheduleCameraJob(Boolean Immediate) {
    final Uri MEDIA_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/");

    JobInfo.Builder builder = new JobInfo.Builder(11,
            new ComponentName(this, PhotosContentJob.class.getName()));
    // Look for specific changes to images in the provider.
    builder.addTriggerContentUri(new JobInfo.TriggerContentUri(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
    // Also look for general reports of changes in the overall provider.
    builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI, 0));

    if (Immediate) {
        // Get all media changes within a tenth of a second.
        builder.setTriggerContentUpdateDelay(1);
        builder.setTriggerContentMaxDelay(100);
    } else {
        builder.setTriggerContentUpdateDelay(1);
        builder.setTriggerContentMaxDelay(100);
    }

    JobInfo myCameraJob  = builder.build();
    JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
    int result =jobScheduler.schedule(myCameraJob);
    if (result == JobScheduler.RESULT_SUCCESS) {
        Log.e("JobScheduler"," JobScheduler OK");
    } else {
        Log.e("JobScheduler"," JobScheduler fails");
    }
}
}

2 个答案:

答案 0 :(得分:1)

基于内容观察者URI调度import subprocess import ast # here we will get a string, there will be a list of dictionary # with name and version from all packages that we have, example: # [{"name": "amqp", "version": "2.2.2"}, {"name": "asn1crypto", "version": "0.24.0"}] # also we need to `decode()`, because this is of type `bytes` packages = subprocess.check_output( ['pip', 'list', '--format=json'], stderr=subprocess.STDOUT).decode() # name of our package that we search name = 'requests' # with ast.literal_eval() we transform the string to list # and check if in this list of dictionary we have a pip package print(any(name in package['name'] for package in ast.literal_eval(packages))) 只是一次性任务。当您收到# if we search `requests` True 的更改后,您需要在JobScheduler结束时重新安排作业,以继续接收更新。

基于文档:

  

注意:TriggerContentUri()不能与之结合使用   setPeriodic()或setPersisted()。 持续监控内容   更改,在应用程序的JobService完成之前安排新的JobInfo   处理最近的回调。

注意:

请记住在设备重启时重新安排作业。由于计划的作业不会在重新启动后持续存在。

答案 1 :(得分:0)

这对我有用(从相机拍摄任何单张照片):

public class PhotoJobService extends JobService {
    private static final String TAG = PhotoJobService.class.getSimpleName();
    {
        Log.d(TAG, "This class object instance: " + this.toString() + ", " + jobinfoinststr());
    }
    private static String jobinfoinststr() {
        return (
            (JOB_INFO == null) ?
                "null" : (
                JOB_INFO.getClass().getSimpleName()
                + "@"
                + Integer.toHexString(java.lang.System.identityHashCode(JOB_INFO))
            )
        );
    }
    //static final Uri MEDIA_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/");
    public static final int JOBSERVICE_JOB_ID = 499; // any number but avoid conflicts
    private static JobInfo JOB_INFO;

    private static boolean isRegistered(Context context) {
        Log.d(TAG, "isRegistered() ?");
        JobScheduler js = context.getSystemService(JobScheduler.class);
        List<JobInfo> jobs = js.getAllPendingJobs();
        if (jobs == null) {
            Log.d(TAG, "JobService not registered ");
            return false;
        }
        for (int i = 0; i < jobs.size(); i++) {
            if (jobs.get(i).getId() == JOBSERVICE_JOB_ID) {
                Log.d(TAG, "JobService is registered: " + jobinfoinststr());
                return true;
            }
        }
        Log.d(TAG, "JobService is not registered");
        return false;
    }

    public static void startJobService(Context context) {
        Log.d(TAG, "registerJob(): JobService init");
        if (!isRegistered(context)) {
            Log.d(TAG, "JobBuilder executes");
            JobInfo.Builder builder = new JobInfo.Builder(JOBSERVICE_JOB_ID,
                    new ComponentName(context, PhotoJobService.class.getName()));
            // Look for specific changes to images in the provider.
            builder.addTriggerContentUri(
                    new JobInfo.TriggerContentUri(
                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
            // Also look for general reports of changes in the overall provider.
            //builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI, 0));

            // Get all media changes within a tenth of a second.
            builder.setTriggerContentUpdateDelay(1);
            builder.setTriggerContentMaxDelay(100);

            JOB_INFO = builder.build();
            Log.d(TAG, "JOB_INFO created " + jobinfoinststr());

            JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
            int result = scheduler.schedule(JOB_INFO);
            if (result == JobScheduler.RESULT_SUCCESS) {
                Log.d(TAG, "JobScheduler OK");
            } else {
                Log.d(TAG, " JobScheduler fails " + result);
            }
        }
    }

    public static void stopJobService(Context context) {
        Log.d(TAG, "cancelJob() " + jobinfoinststr());
        JobScheduler js =
                (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
        js.cancel(JOBSERVICE_JOB_ID);
        isRegistered(context);
    }

    @Override
    public boolean onStartJob(JobParameters params) {
        Log.d(TAG, "onStartJob() " + this.toString() + ", "
                + ((JOB_INFO == null) ? "null" : JOB_INFO.getClass().getSimpleName() + "@" + Integer.toHexString(java.lang.System.identityHashCode(JOB_INFO))));
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            if (params.getJobId() == JOBSERVICE_JOB_ID) {
                if (params.getTriggeredContentAuthorities() != null) {
                    for (Uri uri : params.getTriggeredContentUris()) {
                        Log.d(TAG, "onStartJob() JobService Uri=" + uri.toString());
                    }
                }
            }
        }
        this.jobFinished(params, false);  // false = do not reschedule

        // manual reschedule
        ((JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE)).cancel(JOBSERVICE_JOB_ID);
        startJobService(getApplicationContext());

        return true; // false =  no threads inside
    }

    //This method is called if the system has determined that you must stop execution of your job
    //even before you've had a chance to call {@link #jobFinished(JobParameters, boolean)}.
    @Override
    public boolean onStopJob(JobParameters params) {
        Log.d(TAG, "onStopJob() " + this.toString() + ", " + jobinfoinststr());
        return false; // no restart from here
    }
}