2015-10-17 22 views
0

我試圖製作一個應用程序,打開一項服務,每5小時更換手機上的壁紙。爲什麼我的服務進入timertask循環?

出於測試目的,我只是改變了定時器1分鐘只是爲了看看它是否工作(因爲當它有5小時不工作),

確實也改變了牆紙的每一分鐘。即使當我關閉我的應用程序,並關閉服務 我有一個聲明重新啓動它,以便工作。

不幸的是,當手機變黑(屏幕超時)。我把它重新打開就像它一直在卡住。它需要在電話被暫停時進入聽者的內部,因此它會立即進入timerTask內部,例如,立即連續10次(或者它離線的時間,並且應該已經進入內部)。換句話說,如果我把手機靜止10分鐘,然後再打開它,它會連續10次更換我的壁紙。

所以這是一個問題。另一個是如果我改變計時器5個小時,它根本不會改變壁紙。

有人可以幫助我或知道爲什麼發生在我身上?

這是我的代碼>

我的服務>

package com.greenroad.candidate.mywallpaperchanger; 

import android.app.Service; 
import android.app.WallpaperManager; 
import android.content.Context; 
import android.content.Intent; 
import android.content.SharedPreferences; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.os.Handler; 
import android.os.IBinder; 
import android.preference.PreferenceManager; 
import android.util.DisplayMetrics; 
import android.util.Log; 
import android.view.Display; 
import android.view.WindowManager; 
import android.widget.Toast; 

import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Random; 
import java.util.Timer; 
import java.util.TimerTask; 

/** 
* Created by pitsponet on 31/08/2015. 
*/ 
public class myService extends Service { 
    int oneSecond = 1000; 
    int oneMinute = oneSecond*60; 
    int oneHour = oneMinute*60; 
    int timerDeley = oneMinute; 

    private Timer timer; 

    //this is the tast or the reciver the timer will go into every time it  has being called 
    private TimerTask timerTask = new TimerTask() { 

     @Override 
     public void run() { 

     //shows a toast saying timer listener has entered 
     Handler mainHandler = new Handler(getApplicationContext().getMainLooper()); 
     mainHandler.post(new Runnable() { 
      @Override 
      public void run() { 
       Toast.makeText(getApplicationContext(), "timer listener Entered", Toast.LENGTH_LONG).show(); 
      } 
     }); 



     //gets the picture modifire to know what picture to choose to change the wallpaper to 
     // Access the default SharedPreferences 
     SharedPreferences pref = getApplicationContext().getSharedPreferences("myGlobalPrefTable", MODE_PRIVATE); 
     SharedPreferences.Editor editor = pref.edit(); 

     Integer pictureModifireInt = pref.getInt("pictureModifire", 0); 

     //updates teh picture modifire by one 
     pictureModifireInt++; 


     /////holds a list with all the images that are avilable to change 
     int displayPicture = R.drawable.captain; 

     ArrayList<Integer> pictureNames = new ArrayList<>(); 
     pictureNames.add(R.drawable.captain); 
     pictureNames.add(R.drawable.flash); 
     pictureNames.add(R.drawable.superman); 
     pictureNames.add(R.drawable.thor); 
     pictureNames.add(R.drawable.wonder); 
     pictureNames.add(R.drawable.a); 
     pictureNames.add(R.drawable.b); 
     pictureNames.add(R.drawable.c); 
     pictureNames.add(R.drawable.d); 
     pictureNames.add(R.drawable.e); 
     pictureNames.add(R.drawable.f); 
     pictureNames.add(R.drawable.g); 
     pictureNames.add(R.drawable.h); 
     pictureNames.add(R.drawable.i); 
     pictureNames.add(R.drawable.j); 
     pictureNames.add(R.drawable.k); 
     pictureNames.add(R.drawable.l); 
     pictureNames.add(R.drawable.m); 
     pictureNames.add(R.drawable.n); 
     pictureNames.add(R.drawable.o); 


     //logs the stored prefrence and select the correct image at place > picture modifire 
     Log.d("myLog", "storedPreference: " + pictureModifireInt); 
     displayPicture = pictureNames.get(pictureModifireInt-1); 

     //stores the picture modifire back in the shared prefrences or initlizes it if it reached the last image 
     if(pictureModifireInt > 19){ 
      // Edit the saved preferences 
      Log.d("myLog", "putting in pictureModifire : : " + 0); 
      editor.putInt("pictureModifire", 0); 
      editor.commit(); 

     } else { 
      Log.d("myLog", "putting in pictureModifire : : " + pictureModifireInt); 
      editor.putInt("pictureModifire", pictureModifireInt); 
      editor.commit(); 
     } 



     //most important part of the code 
     //gets the dimentions of the phones screen and changes the wallpaper 
     //it has to get the dimentions so that the wallpaper will be in full screen 
     //maybe he can't do this part when he is in suspend mode ? 
     WindowManager wm= (WindowManager) getSystemService(MainActivity.WINDOW_SERVICE); 
     Display display = wm.getDefaultDisplay(); 
     int width = display.getWidth(); 
     int height = display.getHeight(); 

     Bitmap bmap2 = BitmapFactory.decodeResource(getResources(), displayPicture); 
     Bitmap bitmap = Bitmap.createScaledBitmap(bmap2, width, height, true); 

     WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext()); 
     try { 
      wallpaperManager.setBitmap(bitmap); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 



     //just shoes a post to let knnow what wallpaper has been changed, and that the walpaper indeed changed 
     mainHandler = new Handler(getApplicationContext().getMainLooper()); 
     final Integer finalPictureModifireInt = pictureModifireInt-1; 

     mainHandler.post(new Runnable() { 
      @Override 
      public void run() { 
       Toast.makeText(getApplicationContext(), "wallpaper changed to : "+ finalPictureModifireInt+" and started a new timer", Toast.LENGTH_LONG).show(); 
      } 
     }); 


    } 
}; 



@Override 
public IBinder onBind(Intent intent) { 
    return null; 
} 

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

    //show a toast to indicae that a new service was created 
    Toast.makeText(getApplicationContext(), "a new service created", 
      Toast.LENGTH_LONG).show(); 
} 



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

    Log.d("MyLog", "a new service started"); 

    final Handler mainHandler = new Handler(getApplicationContext().getMainLooper()); 
    mainHandler.post(new Runnable() { 
     @Override 
     public void run() { 

      //show a toast to indicae that a new service was started 
      Toast.makeText(getApplicationContext(), "serviceStarterd", Toast.LENGTH_LONG).show(); 

      // Access the default SharedPreferences 
      SharedPreferences pref = getApplicationContext().getSharedPreferences("myGlobalPrefTable", MODE_PRIVATE); 
      SharedPreferences.Editor editor = pref.edit(); 

      //open a boolean to tell if the service is activated for the first time it will say false 
      boolean serviceStateOn = pref.getBoolean("isServiceActivated", false); 

      if(serviceStateOn == false){ 
       //if ther serviceStateOn is false then there is no service running and it's fine to run a timer task 
       Toast.makeText(getApplicationContext(), "a New Timer Started with Delay: "+timerDeley, Toast.LENGTH_LONG).show(); 

       editor.putBoolean("isServiceActivated", true); // getting String 
       editor.commit(); 

       timer = new Timer(); 
       timer.scheduleAtFixedRate(timerTask, timerDeley, timerDeley); 

      } else { 
       //if ther serviceStateOn is true then there is a service runing so just don't do anything 
       Log.d ("myLog", "Service is on so do nothing"); 

      } 



     } 
    }); 

    return START_STICKY; 
} 

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

    Toast.makeText(getApplicationContext(), "service stoped", 
      Toast.LENGTH_LONG).show(); 
} 
} 

我的清單文件>

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

<uses-permission android:name="android.permission.SET_WALLPAPER"/> 

<application 
    android:allowBackup="true" 
    android:icon="@mipmap/ic_launcher" 
    android:label="@string/app_name" 
    android:theme="@style/AppTheme" > 
    <activity 
     android:name=".MainActivity" 
     android:label="@string/app_name" > 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 

      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 

<service 
    android:name=".myService" 
    android:exported="false" 
    /> 
</application> 

</manifest> 

我的主要acticity>

import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.preference.PreferenceManager; 
import android.support.v7.app.ActionBarActivity; 
import android.os.Bundle; 
import android.util.DisplayMetrics; 
import android.util.Log; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.view.View; 
import android.widget.Button; 
import android.widget.Toast; 

import java.io.IOException; 


public class MainActivity extends ActionBarActivity implements  View.OnClickListener { 

@Override 
protected void onCreate(Bundle savedInstanceState) { 

    //declaring all the buttons 
    Button comixButtonSuperman, comixButtonFlash, comixButtonCaptainAmerica, comixButtonThor, comixButtonWonderWoman; 
    Button startServiceButton, stopServiceButton; 

    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    //casting and connecting the buttons to the actual buttons 
    comixButtonSuperman = (Button) findViewById(R.id.BT_wallpaper1); 
    comixButtonFlash = (Button) findViewById(R.id.BT_wallpaper2); 
    comixButtonCaptainAmerica = (Button) findViewById(R.id.BT_wallpaper3); 
    comixButtonThor = (Button) findViewById(R.id.BT_wallpaper4); 
    comixButtonWonderWoman = (Button) findViewById(R.id.BT_wallpaper5); 
    startServiceButton = (Button) findViewById(R.id.BT_startService); 
    stopServiceButton = (Button) findViewById(R.id.BT_stopService); 

    //adding listeners for all the buttons 
    comixButtonSuperman.setOnClickListener(this); 
    comixButtonFlash.setOnClickListener(this); 
    comixButtonCaptainAmerica.setOnClickListener(this); 
    comixButtonThor.setOnClickListener(this); 
    comixButtonWonderWoman.setOnClickListener(this); 
    startServiceButton.setOnClickListener(this); 
    stopServiceButton.setOnClickListener(this); 


} 

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

    Log.d ("myLog", "Application exists here"); 

    // when going to suspend the service is destroyd, so we should change the boolean to indicate this 
    //also this will make the service statement added in the service possible. 
    SharedPreferences pref = getApplicationContext().getSharedPreferences("myGlobalPrefTable", MODE_PRIVATE); 
    SharedPreferences.Editor editor7 = pref.edit(); 

    editor7.putBoolean("isServiceActivated", false); // getting String 
    editor7.commit(); 
} 


@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    // Inflate the menu; this adds items to the action bar if it is present. 
    //maybe will add options in a later date 
    getMenuInflater().inflate(R.menu.menu_main, menu); 
    return true; 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    // Handle action bar item clicks here. The action bar will 
    // automatically handle clicks on the Home/Up button, so long 
    // as you specify a parent activity in AndroidManifest.xml. 
    int id = item.getItemId(); 

    //noinspection SimplifiableIfStatement 
    if (id == R.id.action_settings) { 
     return true; 
    } 

    return super.onOptionsItemSelected(item); 
} 

@Override 
public void onClick(View v) { 


    switch (v.getId()) { 

     case R.id.BT_wallpaper1: // superman button 
      //was used for testings 

      break; 

     case R.id.BT_wallpaper2: // flash button 
      //was used for testings 


      break; 

     case R.id.BT_wallpaper3: // captain america button 
      //was used for testings 

      break; 

     case R.id.BT_wallpaper4: // thor button 
      //was used for testings 


      break; 

     case R.id.BT_wallpaper5: // wonder woman button 
      //was used for testings 


      break; 



     case R.id.BT_startService: // starts the service 

      //starts the service up 
      Intent i= new Intent(this, myService.class); 
      startService(i); 

      break; 

     case R.id.BT_stopService: // stops the service 

      //stop the service 
      Intent j= new Intent(this, myService.class); 
      stopService(j); 


      //updates ths shared prefrence that there is no service suning any moew 
      SharedPreferences pref = getApplicationContext().getSharedPreferences("myGlobalPrefTable", MODE_PRIVATE); 
      SharedPreferences.Editor editor7 = pref.edit(); 

      editor7.putBoolean("isServiceActivated", false); // getting String 
      editor7.commit(); 


      break; 
    } 

} 
} 

回答

1

我相信,這種情況下你應該使用AlarmManager而不是定時器+處理程序。它爲您提供了一種在應用程序生命週期之外執行基於時間的操作的方法。

下面是使用AlarmManager

https://stackoverflow.com/a/8801990/1163224

調度的一個例子,我決定爲凍壞的代碼如何使用AlarmManager,使我的答案更完整

import android.app.AlarmManager; 
import android.app.PendingIntent; 
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.os.PowerManager; 
import android.widget.Toast; 

public class Alarm extends BroadcastReceiver 
{  
    @Override 
    public void onReceive(Context context, Intent intent) 
    { 
     PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 
     PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ""); 
     wl.acquire(); 

     // Put here YOUR code. 
     Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example 

     wl.release(); 
    } 

    public void SetAlarm(Context context) 
    { 
     AlarmManager am =(AlarmManager)context.getSystemService(Context.ALARM_SERVICE); 
     Intent i = new Intent(context, Alarm.class); 
     PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0); 
     am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 10, pi); // Millisec * Second * Minute 
    } 

    public void CancelAlarm(Context context) 
    { 
     Intent intent = new Intent(context, Alarm.class); 
     PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0); 
     AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 
     alarmManager.cancel(sender); 
    } 
} 

添加到清單中添加.xml:

<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission> 
<receiver android:process=":remote" android:name=".Alarm"></receiver> 

服務

public class YourService extends Service 
{ 
    Alarm alarm = new Alarm(); 
    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) 
    { 
     alarm.SetAlarm(this); 
     return START_STICKY; 
    } 
.... 
} 

Link上面是如何在引導

希望你覺得我的回答有用創建服務,並啓動服務的完整代碼。 :)