I'd like to implement an update checker in an application, and I obviously only need this to show up once when you start the application. If I do the call in the onCreate()
or onStart()
method, it'll be shown every time the activity is created and this is not a viable solution.
我想在应用程序中实现更新检查程序,显然我只需要在启动应用程序时显示一次。如果我在onCreate()或onStart()方法中进行调用,则每次创建活动时都会显示该调用,这不是一个可行的解决方案。
So my question is: Is there a way to do something, like check for updates, just once per application start / launch?
所以我的问题是:有没有办法做一些事情,比如检查更新,每个应用程序启动/启动一次?
I'm sorry if it's a bit hard to understand, I'm having difficulties explaning myself on this one.
如果有点难以理解,我很抱歉,我在解释这个问题时遇到了困难。
9 个解决方案
#1
50
SharedPreferences seems like ugly solution to me. It's much more neat when you use application constructor for such purposes.
SharedPreferences对我来说似乎是丑陋的解决方案。当您将应用程序构造函数用于此类目的时,它会更加整洁。
All you need is to use your own Application class, not default one.
您只需要使用自己的Application类,而不是默认的类。
public class MyApp extends Application {
public MyApp() {
// this method fires only once per application start.
// getApplicationContext returns null here
Log.i("main", "Constructor fired");
}
@Override
public void onCreate() {
super.onCreate();
// this method fires once as well as constructor
// but also application has context here
Log.i("main", "onCreate fired");
}
}
Then you should register this class as your application class inside AndroidManifest.xml
然后,您应该在AndroidManifest.xml中将此类注册为您的应用程序类
<application android:label="@string/app_name" android:name=".MyApp"> <------- here
<activity android:name="MyActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
You even can press Back button, so application go to background, and will not waste your processor resources, only memory resource, and then you can launch it again and constructor still not fire since application was not finished yet.
您甚至可以按“返回”按钮,因此应用程序转到后台,并且不会浪费您的处理器资源,只会浪费内存资源,然后您可以再次启动它,并且构建器仍然没有激活,因为应用程序尚未完成。
You can clear memory in Task Manager, so all applications will be closed and then relaunch your application to make sure that your initialization code fire again.
您可以在任务管理器中清除内存,以便关闭所有应用程序,然后重新启动应用程序以确保再次触发初始化代码。
#2
4
looks like you might have to do something like this
看起来你可能不得不做这样的事情
PackageInfo info = getPackageManager().getPackageInfo(PACKAGE_NAME, 0);
int currentVersion = info.versionCode;
this.versionName = info.versionName;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int lastVersion = prefs.getInt("version_code", 0);
if (currentVersion > lastVersion) {
prefs.edit().putInt("version_code", currentVersion).commit();
// do the activity that u would like to do once here.
}
You can do this every time, to check if the app has been upgraded, so it runs only once for app upgrade
您可以每次执行此操作,以检查应用程序是否已升级,因此仅运行一次以进行应用升级
#3
4
The shared preferences approach is messy, and the application class has no access to an activity.
共享首选项方法很混乱,应用程序类无法访问活动。
Another alternative I've used is to have a retained fragment instance, and within that instance, a lot more stuff can be done especially if you need access to the main activity UI.
我使用的另一个替代方案是拥有一个保留的片段实例,在该实例中,可以完成更多的工作,尤其是在您需要访问主活动UI时。
For this example, I've used asynctask within the retained fragment. My AsyncTask has callbacks to the parent activity. It is guaranteed to run only once per application because the fragment is never destroyed-recreated when the same activity is destroyed-recreated. It is a retained fragment.
对于这个例子,我在保留的片段中使用了asynctask。我的AsyncTask具有对父活动的回调。它保证每个应用程序只运行一次,因为片段永远不会被销毁 - 当同一个活动被销毁 - 重新创建时重新创建。它是一个保留的片段。
public class StartupTaskFragment extends Fragment {
public interface Callbacks {
void onPreExecute();
void onProgressUpdate(int percent);
void onCancelled();
void onPostExecute();
}
public static final String TAG = "startup_task_fragment";
private Callbacks mCallbacks;
private StartupTask mTask;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (Callbacks) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true); // this keeps fragment in memory even if parent activity is destroyed
mTask = new StartupTask();
mTask.execute();
}
@Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
private class StartupTask extends AsyncTask<Void, Integer, Void> {
@Override
protected void onPreExecute() {
if (mCallbacks != null) {
mCallbacks.onPreExecute();
}
}
@Override
protected Void doInBackground(Void... ignore) {
// do stuff here
return null;
}
@Override
protected void onProgressUpdate(Integer... percent) {
if (mCallbacks != null) {
mCallbacks.onProgressUpdate(percent[0]);
}
}
@Override
protected void onCancelled() {
if (mCallbacks != null) {
mCallbacks.onCancelled();
}
}
@Override
protected void onPostExecute(Void ignore) {
if (mCallbacks != null) {
mCallbacks.onPostExecute();
}
}
}
}
Then, in main (or parent) activity where you want this startup task fragment to run once.
然后,在主要(或父)活动中,您希望此启动任务片段运行一次。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getFragmentManager();
StartupTaskFragment st = (StartupTaskFragment) fm.findFragmentByTag(StartupTaskFragment.TAG);
if(st == null) {
fm.beginTransaction().add(mStartupTaskFragment = new StartupTaskFragment(), StartupTaskFragment.TAG).commit();
}
...
}
Ideas for retained fragment came from here: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html. I just figured out its other uses aside from config changes.
保留片段的想法来自这里:http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html。除了配置更改之外,我只是想出了它的其他用途。
#4
2
Yes you can do it Using SharedPrefernce concept of android. Just create a boolean flag and save it in SharedPrefernce and check its value in your onCreate() method .
是的,你可以使用Android的SharedPrefernce概念。只需创建一个布尔标志并将其保存在SharedPrefernce中,并在onCreate()方法中检查其值。
#5
0
I do this the same way as described in the other answer. I just have a global variable in the first activity which matches the release number from the manifest. I increment it for every upgrade and when the check sees a higher number, it executes the one-time code.
我这样做的方式与其他答案中描述的方式相同。我在第一个活动中只有一个全局变量,它与清单中的版本号相匹配。我为每次升级都增加它,当检查看到更高的数字时,它会执行一次性代码。
If successful, it writes the new number to shared preferences so it wont do it again until the next upgrade.
如果成功,它会将新号码写入共享首选项,因此在下次升级之前不会再次执行此操作。
Make sure you assign the default to -1 when you retrieve the version from shared preferences so that you error on the side of running the code again as opposed to not running it and not having your app update correctly.
当您从共享首选项中检索版本时,请确保将默认值指定为-1,以便在再次运行代码时出错,而不是运行代码而不是正确更新应用程序。
#6
0
Use SharedPreference for this-
使用SharedPreference -
-
If you are not restarting your launcher activity again once your app is active then in that case you case use it.
如果您的应用处于活动状态时没有再次重新启动启动器活动,那么在这种情况下您将使用它。
-
Use this in a Splash screen if you are implementing it in the app.
如果您在应用程序中实现它,请在启动画面中使用它。
-
If you are not using any splash screen then you need to create a activity with no view set and on it's oncreate call you can do start updation and start your main activity.
如果您没有使用任何启动画面,那么您需要创建一个没有设置视图的活动,并且在它的oncreate调用上,您可以开始更新并开始您的主要活动。
you can use counter value or boolean for this.
你可以使用计数器值或布尔值。
Here is SharedPreference doc:
这是SharedPreference文档:
http://developer.android.com/reference/android/content/SharedPreferences.html
#7
0
try {
boolean firstboot = getSharedPreferences("BOOT_PREF",MODE_PRIVATE)
.getBoolean("firstboot", true);
if(firstboot){
//place your code that will run single time
getSharedPreferences("BOOT_PREF",MODE_PRIVATE).edit().
putBoolean("firstboot", false)
.commit();
}
#8
0
I just solved doing this myself, I reopen my main activity multiple times throughout the application's execution. While the constructor is a valid approach for some things it doesn't let you access the current Application context to write toasts among other things.
我自己解决了这个问题,在整个应用程序的执行过程中,我多次重新打开我的主要活动。虽然构造函数是某些事物的有效方法,但它不允许您访问当前的Application上下文来编写toast等。
My solution was to create a simple 'firstRun' boolean set to true in the class of my MainActivity, from there I run the contents of the if statement then set it to true. Example:
我的解决方案是在我的MainActivity类中创建一个简单的'firstRun'布尔值设置为true,从那里我运行if语句的内容然后将其设置为true。例:
public class MainActivity extends AppCompatActivity
{
private static boolean firstRun = true;
@Override
protected void onCreate(Bundle savedInstanceState)
{
if(firstRun)
{
Toast.makeText(getApplicationContext(), "FIRST RUN", Toast.LENGTH_SHORT).show();
//YOUR FIRST RUN CODE HERE
}
firstRun = false;
super.onCreate(savedInstanceState);
//THE REST OF YOUR CODE
}
#9
0
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (!prefs.getBoolean("onlyonce", false)) {
// <---- run your one time code here
// mark once runned.
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("onlyonce", true);
editor.commit();
}
}
#1
50
SharedPreferences seems like ugly solution to me. It's much more neat when you use application constructor for such purposes.
SharedPreferences对我来说似乎是丑陋的解决方案。当您将应用程序构造函数用于此类目的时,它会更加整洁。
All you need is to use your own Application class, not default one.
您只需要使用自己的Application类,而不是默认的类。
public class MyApp extends Application {
public MyApp() {
// this method fires only once per application start.
// getApplicationContext returns null here
Log.i("main", "Constructor fired");
}
@Override
public void onCreate() {
super.onCreate();
// this method fires once as well as constructor
// but also application has context here
Log.i("main", "onCreate fired");
}
}
Then you should register this class as your application class inside AndroidManifest.xml
然后,您应该在AndroidManifest.xml中将此类注册为您的应用程序类
<application android:label="@string/app_name" android:name=".MyApp"> <------- here
<activity android:name="MyActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
You even can press Back button, so application go to background, and will not waste your processor resources, only memory resource, and then you can launch it again and constructor still not fire since application was not finished yet.
您甚至可以按“返回”按钮,因此应用程序转到后台,并且不会浪费您的处理器资源,只会浪费内存资源,然后您可以再次启动它,并且构建器仍然没有激活,因为应用程序尚未完成。
You can clear memory in Task Manager, so all applications will be closed and then relaunch your application to make sure that your initialization code fire again.
您可以在任务管理器中清除内存,以便关闭所有应用程序,然后重新启动应用程序以确保再次触发初始化代码。
#2
4
looks like you might have to do something like this
看起来你可能不得不做这样的事情
PackageInfo info = getPackageManager().getPackageInfo(PACKAGE_NAME, 0);
int currentVersion = info.versionCode;
this.versionName = info.versionName;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int lastVersion = prefs.getInt("version_code", 0);
if (currentVersion > lastVersion) {
prefs.edit().putInt("version_code", currentVersion).commit();
// do the activity that u would like to do once here.
}
You can do this every time, to check if the app has been upgraded, so it runs only once for app upgrade
您可以每次执行此操作,以检查应用程序是否已升级,因此仅运行一次以进行应用升级
#3
4
The shared preferences approach is messy, and the application class has no access to an activity.
共享首选项方法很混乱,应用程序类无法访问活动。
Another alternative I've used is to have a retained fragment instance, and within that instance, a lot more stuff can be done especially if you need access to the main activity UI.
我使用的另一个替代方案是拥有一个保留的片段实例,在该实例中,可以完成更多的工作,尤其是在您需要访问主活动UI时。
For this example, I've used asynctask within the retained fragment. My AsyncTask has callbacks to the parent activity. It is guaranteed to run only once per application because the fragment is never destroyed-recreated when the same activity is destroyed-recreated. It is a retained fragment.
对于这个例子,我在保留的片段中使用了asynctask。我的AsyncTask具有对父活动的回调。它保证每个应用程序只运行一次,因为片段永远不会被销毁 - 当同一个活动被销毁 - 重新创建时重新创建。它是一个保留的片段。
public class StartupTaskFragment extends Fragment {
public interface Callbacks {
void onPreExecute();
void onProgressUpdate(int percent);
void onCancelled();
void onPostExecute();
}
public static final String TAG = "startup_task_fragment";
private Callbacks mCallbacks;
private StartupTask mTask;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (Callbacks) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true); // this keeps fragment in memory even if parent activity is destroyed
mTask = new StartupTask();
mTask.execute();
}
@Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
private class StartupTask extends AsyncTask<Void, Integer, Void> {
@Override
protected void onPreExecute() {
if (mCallbacks != null) {
mCallbacks.onPreExecute();
}
}
@Override
protected Void doInBackground(Void... ignore) {
// do stuff here
return null;
}
@Override
protected void onProgressUpdate(Integer... percent) {
if (mCallbacks != null) {
mCallbacks.onProgressUpdate(percent[0]);
}
}
@Override
protected void onCancelled() {
if (mCallbacks != null) {
mCallbacks.onCancelled();
}
}
@Override
protected void onPostExecute(Void ignore) {
if (mCallbacks != null) {
mCallbacks.onPostExecute();
}
}
}
}
Then, in main (or parent) activity where you want this startup task fragment to run once.
然后,在主要(或父)活动中,您希望此启动任务片段运行一次。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getFragmentManager();
StartupTaskFragment st = (StartupTaskFragment) fm.findFragmentByTag(StartupTaskFragment.TAG);
if(st == null) {
fm.beginTransaction().add(mStartupTaskFragment = new StartupTaskFragment(), StartupTaskFragment.TAG).commit();
}
...
}
Ideas for retained fragment came from here: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html. I just figured out its other uses aside from config changes.
保留片段的想法来自这里:http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html。除了配置更改之外,我只是想出了它的其他用途。
#4
2
Yes you can do it Using SharedPrefernce concept of android. Just create a boolean flag and save it in SharedPrefernce and check its value in your onCreate() method .
是的,你可以使用Android的SharedPrefernce概念。只需创建一个布尔标志并将其保存在SharedPrefernce中,并在onCreate()方法中检查其值。
#5
0
I do this the same way as described in the other answer. I just have a global variable in the first activity which matches the release number from the manifest. I increment it for every upgrade and when the check sees a higher number, it executes the one-time code.
我这样做的方式与其他答案中描述的方式相同。我在第一个活动中只有一个全局变量,它与清单中的版本号相匹配。我为每次升级都增加它,当检查看到更高的数字时,它会执行一次性代码。
If successful, it writes the new number to shared preferences so it wont do it again until the next upgrade.
如果成功,它会将新号码写入共享首选项,因此在下次升级之前不会再次执行此操作。
Make sure you assign the default to -1 when you retrieve the version from shared preferences so that you error on the side of running the code again as opposed to not running it and not having your app update correctly.
当您从共享首选项中检索版本时,请确保将默认值指定为-1,以便在再次运行代码时出错,而不是运行代码而不是正确更新应用程序。
#6
0
Use SharedPreference for this-
使用SharedPreference -
-
If you are not restarting your launcher activity again once your app is active then in that case you case use it.
如果您的应用处于活动状态时没有再次重新启动启动器活动,那么在这种情况下您将使用它。
-
Use this in a Splash screen if you are implementing it in the app.
如果您在应用程序中实现它,请在启动画面中使用它。
-
If you are not using any splash screen then you need to create a activity with no view set and on it's oncreate call you can do start updation and start your main activity.
如果您没有使用任何启动画面,那么您需要创建一个没有设置视图的活动,并且在它的oncreate调用上,您可以开始更新并开始您的主要活动。
you can use counter value or boolean for this.
你可以使用计数器值或布尔值。
Here is SharedPreference doc:
这是SharedPreference文档:
http://developer.android.com/reference/android/content/SharedPreferences.html
#7
0
try {
boolean firstboot = getSharedPreferences("BOOT_PREF",MODE_PRIVATE)
.getBoolean("firstboot", true);
if(firstboot){
//place your code that will run single time
getSharedPreferences("BOOT_PREF",MODE_PRIVATE).edit().
putBoolean("firstboot", false)
.commit();
}
#8
0
I just solved doing this myself, I reopen my main activity multiple times throughout the application's execution. While the constructor is a valid approach for some things it doesn't let you access the current Application context to write toasts among other things.
我自己解决了这个问题,在整个应用程序的执行过程中,我多次重新打开我的主要活动。虽然构造函数是某些事物的有效方法,但它不允许您访问当前的Application上下文来编写toast等。
My solution was to create a simple 'firstRun' boolean set to true in the class of my MainActivity, from there I run the contents of the if statement then set it to true. Example:
我的解决方案是在我的MainActivity类中创建一个简单的'firstRun'布尔值设置为true,从那里我运行if语句的内容然后将其设置为true。例:
public class MainActivity extends AppCompatActivity
{
private static boolean firstRun = true;
@Override
protected void onCreate(Bundle savedInstanceState)
{
if(firstRun)
{
Toast.makeText(getApplicationContext(), "FIRST RUN", Toast.LENGTH_SHORT).show();
//YOUR FIRST RUN CODE HERE
}
firstRun = false;
super.onCreate(savedInstanceState);
//THE REST OF YOUR CODE
}
#9
0
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (!prefs.getBoolean("onlyonce", false)) {
// <---- run your one time code here
// mark once runned.
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("onlyonce", true);
editor.commit();
}
}