on API > 21 when my phone is locked this service is stop working (when I wake up a phone a service is starting working). This is what I do :
public class JobDispacherService extends JobService {
private Preferences prefs = null;
public static final String GCM_ONEOFF_TAG = "oneoff|[0,0]";
public static final String GCM_REPEAT_TAG = "komunalRepeat|[7200,1800]";
private static final String TAG = JobDispacherService.class.getSimpleName();
private UplaudPossitionTask uplaudPossitionTask;
#Override
public boolean onStartJob(#NonNull JobParameters job) {
uplaudPossitionTask = new UplaudPossitionTask() {
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
jobFinished(job, false);
}
};
uplaudPossitionTask.execute();
return false; // Answers the question: "Is there still work going on?"
}
#Override
public boolean onStopJob(JobParameters job) {
return true; // Answers the question: "Should this job be retried?"
}
private class UplaudPossitionTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
uploadPosition();
return null;
}
}
}
And I call this service just like this :
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
Job myJob = dispatcher.newJobBuilder()
.setService(JobDispacherService.class)
.setTag("my-unique-tag")
.setRecurring(true)
.setLifetime(Lifetime.FOREVER)
.setTrigger(Trigger.executionWindow(10, (int) 15))
.setReplaceCurrent(false)
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
.setConstraints(Constraint.ON_ANY_NETWORK)
.build();
dispatcher.mustSchedule(myJob);
I want to repeat this time all the time and I do not have idea why this service is stop wrking when my phone is locked more than 1h
WorkManager :
public static void refreshCouponPeriodicWork() {
//define constraints
Constraints myConstraints = new Constraints.Builder()
.setRequiresDeviceIdle(false)
.setRequiresCharging(false)
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.setRequiresStorageNotLow(true)
.build();
Data source = new Data.Builder()
.putString("workType", "PeriodicTime")
.build();
PeriodicWorkRequest refreshCpnWork =
new PeriodicWorkRequest.Builder(RefreshLatestCouponWorker.class, 10, TimeUnit.HOURS,30, TimeUnit.SECONDS)
.setConstraints(myConstraints)
.setInputData(source)
.build();
WorkManager.getInstance().enqueue(refreshCpnWork);
}
public class RefreshLatestCouponWorker extends Worker {
private Preferences prefs = null;
public RefreshLatestCouponWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Worker.Result doWork() {
//read input argument
String workType = getInputData().getString("workType");
Log.i("refresh cpn work", "type of work request: " + workType);
uploadPosition();
//sending work status to caller
return success();
}
}
I do this for work manager but task run only once and never is repeating
I suggest you read about WorkManager, that will be the correct solution for you. The WorkManager API makes it easy to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or device restarts. You can define Periodic requests with specified time interval and device state. Revert in case you find the implementation difficult, i could help you with it.
Related
I am trying to schedule the job which will run at 10 PM daily.
I tried to use the setExact method and provide the milliseconds by converting 22 hours to milliseconds and for testing I executed the app and changed the system time to 10 PM but the job did not execute.
I also tried to give coming time so converted 12:45 to milliseconds and given to setExact method. But that also did not work.
How can I set this and test?
FileTrackJob
class FileTrackJob extends Job {
static final String TAG = "FileTracking";
#NonNull
#Override
protected Result onRunJob(Params params) {
PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0,
new Intent(getContext(), MainActivity.class), 0);
Calendar cal = Calendar.getInstance();
Date currentLocalTime = cal.getTime();
DateFormat date = new SimpleDateFormat("HH:mm a");
// you can get seconds by adding "...:ss" to it
String localTime = date.format(currentLocalTime);
Notification notification = new NotificationCompat.Builder(getContext())
.setContentTitle("Android Job Demo")
.setContentText("Notification from Android Job Demo App. " + localTime)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.setSmallIcon(R.mipmap.ic_launcher)
.setShowWhen(true)
.setColor(Color.RED)
.setLocalOnly(true)
.build();
NotificationManagerCompat.from(getContext())
.notify(new Random().nextInt(), notification);
return Result.SUCCESS;
}
static void scheduleNoti() {
new JobRequest.Builder(TrackingJob.TAG)
// .setPeriodic(TimeUnit.MINUTES.toMillis(15), TimeUnit.MINUTES.toMillis(15))
.setExact(44820000)
.setUpdateCurrent(true)
.setPersisted(true)
.build()
.schedule();
}
}
MainActivity
FileTrackJob.scheduleNoti();
MainApp
public class MainApp extends Application {
#Override
public void onCreate() {
super.onCreate();
JobManager.create(this).addJobCreator(new DemoJobCreator());
}
}
DemoJobCreator
class DemoJobCreator implements JobCreator {
#Override
public Job create(String tag) {
switch (tag) {
case TrackingJob.TAG:
return new TrackingJob();
case FileTrackJob.TAG:
return new FileTrackJob();
default:
return null;
}
}
}
Also I have scheduled one periodic job, this job is not working on some devices like red mi,on one samsung device its not repeated but on moto g4 plus it worked well.
class TrackingJob extends Job {
static final String TAG = "tracking";
#NonNull
#Override
protected Result onRunJob(Params params) {
Intent pi = new Intent(getContext(), GetLocationService.class);
getContext().startService(pi);
return Result.SUCCESS;
}
static void schedulePeriodic() {
new JobRequest.Builder(TrackingJob.TAG)
.setPeriodic(TimeUnit.MINUTES.toMillis(15), TimeUnit.MINUTES.toMillis(15))
.setUpdateCurrent(true)
.setPersisted(true)
.build()
.schedule();
}
}
Can anyone help with this please? Thank you..
You must use DailyJob instead of Job to do something at the specific time daily.
public static final class MyDailyJob extends DailyJob {
public static final String TAG = "MyDailyJob";
public static void schedule() {
// schedule between 1 and 6 *PM*
DailyJob.schedule(new JobRequest.Builder(TAG), TimeUnit.HOURS.toMillis(13), TimeUnit.HOURS.toMillis(18));
}
#NonNull
#Override
protected DailyJobResult onRunDailyJob(Params params) {
return DailyJobResult.SUCCESS;
}
}
Plus: If you want to set specific minutes and seconds, then use (assume between 15:48:05 and 17:42:09) :
DailyJob.schedule(new JobRequest.Builder(TAG), TimeUnit.HOURS.toMillis(15)+TimeUnit.MINUTES.toMillis(48)+TimeUnit.SECONDS.toMillis(5),
TimeUnit.HOURS.toMillis(17)+TimeUnit.MINUTES.toMillis(42)+TimeUnit.SECONDS.toMillis(9));
Hope this helps.
I'm trying to retrieve some data from API, but i'm always getting null in async task. Here is my asynctask:
private class DownloadTask extends AsyncTask<Bundle, Void, List<Topic>> {
#Override
protected void onPreExecute() {
HomeActivity.mProgressBar.setVisibility(View.VISIBLE);
HomeActivity.mProgressBar.setIndeterminate(true);
}
#Override
protected List<Topic> doInBackground(Bundle... params) {
return downloadPhotos(params[0]);
}
#Override
protected void onPostExecute(List<Topic> topics) {
HomeActivity.mProgressBar.setVisibility(View.INVISIBLE);
HomeActivity.mProgressBar.setIndeterminate(false);
Log.d("List Size: ", ""+topics); // 0
adapter = new TopicListAdapter(activity, topics);
RecyclerView.LayoutManager manager = new MyCustomLayoutManager(activity);
recyclerView.setLayoutManager(manager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
}
}
Method for retrieving data should merge two arrays into one array because i'm retrieving data from two places:
private List<Topic> downloadPhotos(Bundle params) {
String profileId = activity.getPreferencesManager().getProfileId();
List<Topic> topicsFromMe, topicsFromFriends;
topicsFromFriends = setValuesFromFriends(params);
topicsFromMe = setValuesFromMe(profileId, params);
topicsFromFriends.addAll(topicsFromMe);
sortTopics(topicsFromFriends);
int k = topicsFromFriends.size();
Log.d("List Size: ", "" + topicsFromFriends); // here also 0 for size
if (k > 10)
topicsFromFriends.subList(10, k).clear();
return topicsFromFriends;
}
And here is one method where i'm setting values to array list. It is strange that RecyclerView in this case is populated with this array, but i'm not getting results i want. For instance i should sort this list and show only 10 records from it.
private List<Topic> setValuesFromFriends(final Bundle params) {
final List<Topic> topics = new ArrayList<>();
activity.getSimpleFacebook().getFriends(new OnFriendsListener() {
#Override
public void onComplete(List<Profile> friends) {
for (final Profile profile : friends) {
activity.getSimpleFacebook().get(profile.getId(), "photos/uploaded", params,
new OnActionListener<List<Photo>>() {
#Override
public void onComplete(List<Photo> photos) {
for (final Photo photo : photos) {
// Initialize instance of Topic
final User user = photo.getFrom();
final Topic topic = new Topic();
topic.setCaption(photo.getName());
topic.setImageId(photo.getId());
topic.setCreatedTime(photo.getCreatedTime());
topic.setPostImage(photo.getSource());
topic.setUserId(user.getId());
topic.setName(user.getName());
final Bundle likeParams = new Bundle();
likeParams.putString("fields", "total_count");
likeParams.putString("limit", "100000");
activity.getSimpleFacebook().get(photo.getId(), "likes",
likeParams, new OnActionListener<List<Like>>() {
#Override
public void onComplete(List<Like> likes) {
topic.setNumOfLikes(likes.size());
topics.add(topic);
}
#Override
public void onThinking() {
super.onThinking();
}
});
}
}
});
}
}
});
return topics;
}
You are using AsyncTask incorrectly.
AsyncTask is launching another Thread (thread1) where where it is executing the method, doenloadPhotos. This method is calling setValuesFromFriends which is creating another thread (thread2) with the method getFriends. As thread2 has been launched, the rest of the code in setValuesFromFriends will get executed.
So here is how it is working:
private List<Topic> setValuesFromFriends(final Bundle params) {
final List<Topic> topics = new ArrayList<>();
//launched process on new thread
return topics; //this is 0 as topics = new ArrayList<>();
}
So now topicsFromFriends = 0. Hence you are getting the output = 0.
in effect thread1 is getting executed before thread2 is complete. As the output of thread1 is 0, nothing is displayed in UI after onPostExecute
There is no need of using AsyncTask.
You should put all the required code inside the onComplete of the new OnFriendsListener(). This way the info will be shown correctly. You can launch the progressbar before setValuesFromFriends and then remove it in the onComplete.
I've created a class to download raw data from url(api): GetRawData - GitHub
I extend the class:
GetTVShowDetailsJsonData - GitHub
So, my problem is, I call GetTVShowDetailsJsonData.java on my activity
public class ProcessTVShowsDetails extends GetTVShowDetailsJsonData {
private ProgressDialog progress;
public ProcessTVShowsDetails(TVShow show) {
super(show, TVShowDetailsActivity.this);
}
public void execute() {
// Start loading dialog
progress = ProgressDialog.show(TVShowDetailsActivity.this, "Aguarde...", "Estamos carregando os dados da série.", true);
// Start process data (download and get)
ProcessData processData = new ProcessData();
processData.execute();
}
public class ProcessData extends DownloadJsonData {
protected void onPostExecute(String webData) {
super.onPostExecute(webData);
mTVShowDetails = getTVShowsDetails();
bindParams();
// Close loading dialog.
if (progress.isShowing()) progress.dismiss();
}
}
}
But inside this call, I want to call another download another JSON from other url, using GetSeasonJsonData.java, is the same GetTVShowDetailsJsonData.java do, but for another PARSE.I need to wait the task being completed or maybe do in synchronous way, to add the result from GetSeasonJsonData.java inside the first result from GetTvShowDetailsJsonData. How can I do that?
Just a note, i need to run more than one time, and I already try this, but doesn't work:
// Process and execute data into recycler view
public class ProcessTVShowsDetails extends GetTVShowDetailsJsonData {
private ProgressDialog progress;
public ProcessTVShowsDetails(TVShow show) {
super(show, TVShowDetailsActivity.this);
}
public void execute() {
// Start loading dialog
progress = ProgressDialog.show(TVShowDetailsActivity.this, "Aguarde...", "Estamos carregando os dados da série.", true);
// Start process data (download and get)
ProcessData processData = new ProcessData();
processData.execute();
}
public class ProcessData extends DownloadJsonData {
protected void onPostExecute(String webData) {
super.onPostExecute(webData);
mTVShowDetails = getTVShowsDetails();
//Process SeasonData
for(int seasonNumber = 1; seasonNumber <= mTVShowDetails.getNumberOfSeasons(); seasonNumber++) {
ProcessSeason processSeason = new ProcessSeason(mTVShowDetails.getId(), seasonNumber);
processSeason.execute();
}
bindParams();
// Close loading dialog.
if (progress.isShowing()) progress.dismiss();
}
}
}
// Process Season Data
public class ProcessSeason extends GetTVShowSeasonJsonData {
public ProcessSeason(int showId, int serieNumber) {
super(showId, serieNumber, TVShowDetailsActivity.this);
}
public void execute() {
// Start process data (download and get)
ProcessData processData = new ProcessData();
processData.execute();
}
public class ProcessData extends DownloadJsonData {
protected void onPostExecute(String webData) {
super.onPostExecute(webData);
}
}
}
I'm trying to create a native extension which can receive broadcasts, sent from a native android am as intent broadcasts.
The sending part works, I've tested this with a native app that has a broadcast receiver, but I cant get it to work in the native extension.
Here's what I have so far:
Here the java side of the ANE
public class ReceiverPhidget extends BroadcastReceiver {
private FREContext mFREContext;
public ReceiverPhidget(FREContext mFREContext) {
this.mFREContext = mFREContext;
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(IntentsKeys.INTENT_PHIDGET_CONNECTED)){
//Send listener in ANE project with message that phidget connected (not must)
System.out.println("Phidget connected");
mFREContext.dispatchStatusEventAsync("Yes", Keys.KEY_CONNECTED);
} else
if (action.equals(IntentsKeys.INTENT_PHIDGET_DISCONNECTED)){
//Send listener in ANE project with message that phidget disconnected (not must)
System.out.println("Phidget disconnected");
mFREContext.dispatchStatusEventAsync("Yes", Keys.KEY_DISCONNECTED);
} else
if (action.equals(IntentsKeys.INTENT_PHIDGET_GAIN_TAG)){
//Send listener with data in ANE project with message that phidget gain receive
String message = intent.getStringExtra(IntentsKeys.INTENT_PHIDGET_EXTRA_DATA);
System.out.println("Phidget gain message: " + message);
Log.d("TAG FOUND", message);
mFREContext.dispatchStatusEventAsync(message, Keys.KEY_TAG_GAIN);
}
}
public static IntentFilter getIntentFilter(){
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(IntentsKeys.INTENT_PHIDGET_CONNECTED);
intentFilter.addAction(IntentsKeys.INTENT_PHIDGET_DISCONNECTED);
intentFilter.addAction(IntentsKeys.INTENT_PHIDGET_GAIN_TAG);
return intentFilter;
}
}
And the FREExtension
public class ReceiverExtension implements FREExtension {
private ReceiverPhidget mReceiverPhidget;
private ReceiverExtensionContext mContext;
#Override
public void initialize() {
mReceiverPhidget = new ReceiverPhidget(mContext);
mContext.getActivity().registerReceiver(mReceiverPhidget, ReceiverPhidget.getIntentFilter());
}
#Override
public FREContext createContext(String s) {
return mContext = new ReceiverExtensionContext();
}
#Override
public void dispose() {
mContext.getActivity().unregisterReceiver(mReceiverPhidget);
}
}
And here is the flash library side of the ANE
package nl.mediaheads.anetest.extension {
import flash.events.EventDispatcher;
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
public class RFIDController extends EventDispatcher {
private var extContext:ExtensionContext;
private var channel:int;
private var scannedChannelList:Vector.<int>;
public function RFIDController() {
extContext = ExtensionContext.createExtensionContext(
"nl.mediaheads.anetest.exntension.RFIDController", "");
extContext.addEventListener(StatusEvent.STATUS, onStatus);
}
private function onStatus(event:StatusEvent):void {
if (event.level == EventKeys.KEY_TAG_GAIN) {
dispatchEvent (new TagEvent(TagEvent.TAG_GAINED, event.code) );
}
}
}
}
And here is my test mobile project class to test the ANE
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.text.TextField;
import nl.mediaheads.anetest.extension.RFIDController;
[SWF(width="1280", height="800", frameRate="60", backgroundColor="#ffffff")]
public class AneTestApp extends Sprite
{
private var tf:TextField;
private var rc:RFIDController;
public function AneTestApp()
{
super();
// support autoOrients
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.color = 0xFFFFFF;
addEventListener(Event.ADDED_TO_STAGE, onAdded);
}
private function onAdded(event:Event):void {
//
tf = new TextField();
tf.width = 200;
tf.height = 50;
tf.x = 10;
tf.y = 64;
tf.mouseEnabled = false;
tf.background = true;
tf.backgroundColor = 0xF50000;
addChild(tf);
rc = new RFIDController();
tf.text = "test 1";
this.addEventListener( TagEvent.TAG_GAINED , onTagAdded);
tf.text = "test 2";
//
}
private function onTagAdded(event:TagEvent):void
{
tf.text = event.params;
}
}
}
I have signed the ANE accordingly, I also signed the test app it's self.
I have a Log.d in the java part of the ANE which should pop up on log cat but it doesn't, also the textfield just becomes blank as soon as I initialized the RFIDController even without added the event listener.
If you need any more code or information to help me solve this problem feel free to ask.
I could really use some help because I'm completely lost, I've followed multiple tutorials and guide on how to do this, I should have done everything correctly, but I clearly have not.
UPDATE: 1
The extension xml
<extension xmlns="http://ns.adobe.com/air/extension/3.5">
<id>nl.mediaheads.anetest.exntension.RFIDController</id>
<versionNumber>0.0.1</versionNumber>
<platforms>
<platform name="Android-ARM">
<applicationDeployment>
<nativeLibrary>AneTest.jar</nativeLibrary>
<initializer>nl.mediaheads.anetest.ReceiverExtension</initializer>
<finalizer>nl.mediaheads.anetest.ReceiverExtension</finalizer>
</applicationDeployment>
</platform>
</platforms>
</extension>
UPDATE 2:
I fixed it, it was an context issue together with that flash somehow clean my custom event so I used status event to parse from the flash side of the ANE to the air application itself.
Currently you are creating your receiver at the initialisation point of the extension which will most likely be called before the context creation, so your context may be null at that point and causing your errors.
Try moving the creation of your ReceiverPhidget to the constructor of your ReceiverExtensionContext. Something like the following (I haven't tested this):
public class ReceiverExtensionContext extends FREContext
{
private ReceiverPhidget mReceiverPhidget;
public ReceiverExtensionContext()
{
mReceiverPhidget = new ReceiverPhidget( this );
getActivity().registerReceiver( mReceiverPhidget, ReceiverPhidget.getIntentFilter() );
}
#Override
public Map<String, FREFunction> getFunctions()
{
Map<String, FREFunction> functionMap = new HashMap<String, FREFunction>();
return functionMap;
}
#Override
public void dispose()
{
getActivity().unregisterReceiver( mReceiverPhidget );
}
}
In my android application, I am sending messages to contacts.. and it is showing " This handler class should be static or else might be leak". My application is crashing in Mobile phone but it is working in Emulator, I am giving the code below pls go through it and any error if anybody can help please help..
progresshandler = new Handler()
{
public void handleMessage(Message msg)
{
//progressDialog.dismiss();
//Toast.makeText(SendMessagesActivity.this, "Messages Sent",Toast.LENGTH_LONG).show();
new ProgressTask().execute();
}
};
To avoid leaking Handler create Custom class that extends Handler class as below :
// Handler of incoming messages from clients.
private static class IncomingHandler extends Handler {
private WeakReference<YourActivity> yourActivityWeakReference;
public IncomingHandler(YourActivity yourActivity) {
yourActivityWeakReference = new WeakReference<>(yourActivity);
}
#Override
public void handleMessage(Message message) {
if (yourActivityWeakReference != null) {
YourActivity yourActivity = yourActivityWeakReference.get();
Edited : new ProgressTask().execute();
// switch (message.what) {
// }
}
}
}
Create object of this class wherever you want to use as below.
private IncomingHandler mPulseHandler;
mPulseHandler = new IncomingHandler(HomeActivity.this);
mPulseHandler.sendEmptyMessage(0);
Edited :
IncomingHandler progresshandler = new IncomingHandler(YourActivity.this);
if (editMessage.getText().toString().length() > 0) {
SendMessagesThread thread = new SendMessagesThread(progresshandler);
thread.start();
// progressDialog.show();
}
Edited :
Declare this task in your activity :
private ProgressTask progressTask;
Create instance of it in onCreate()
progressTask=new ProgressTask();
Change line in IncomingHandler :
yourActivity.progressTask.execute();
Thanks