编辑:我发现 Activity 正在保存实例,但 Fragments 保存的数据没有达到 Activity savedInstanceState。我将当前时间保存在 outState 中,但它并没有一直向上,因为该 Activity 当时在其 SavedInstanceState 中没有任何内容,如果我将其打印到 logcat,则该时间返回“null”。 ..
我正在构建一个内置了倒计时计时器的应用程序。计时器的基本托管 Activity 是一个 FragmentActivity,它托管一个 FragementPagerAdapter,它在代码中膨胀两个 fragment (我没有为 fragment 提供 ID在 XML 中,因为它们未定义为 .xml 中的 fragment )。一切都很好,直到方向改变,然后 Activity 看起来像它与旧 fragment 失去联系,只是选择创建新 fragment 。这意味着任何当前倒计时都会丢失,并且任何选择的时间也会在配置更改时丢失。我需要继续计数(如果它开始了)和当前显示的任何数字....
我知道适配器应该自己处理这些事情,我在 OnCreate 和 OnCreateView 中都设置了 SetRetainInstance(true)。
我在 fragment 代码中加入了钩子(Hook),以便在 saveInstanceState 不为 null 时通知我,所以至少我知道发生了什么,但实例似乎始终为 NULL,并且它从头开始创建...总是.
其他一些解决方案让我覆盖了 instantiateItem,但它似乎只用于重置回调,其他解决方案更改 list 中的设置(不赞成)....其他解决方案在我看来就像我已经设置好了东西对...但很明显,我一路上搞砸了。我只提供 FragmentActivity、FragementPagerAdapter 的代码和一些 Fragment 代码,因为我不想用可能不是问题的代码向帖子发送垃圾邮件。
fragment Activity
public class Timer_Main extends FragmentActivity {
ViewPager pager;
Timer_Pager mAdapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.timer_pager);
mAdapter = new Timer_Pager(this, getSupportFragmentManager());
pager = (ViewPager) findViewById(R.id.timer_pager_display);
pager.setAdapter(mAdapter);
}
public static String getTitle(Context ctxt, int position) {
// TODO Auto-generated method stub
return null;
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("pageItem", pager.getCurrentItem());
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
}
FragementPagerAdapter
public class Timer_Pager extends FragmentPagerAdapter{
Context ctxt = null;
public Timer_Pager(Context ctxt, FragmentManager fm) {
super(fm);
this.ctxt = ctxt;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0: {
return(Countdown_Fragment.newInstance());
}
case 1:
return(Countup_Fragment.newInstance());
}
return null;
}
@Override
public String getPageTitle(int position) {
switch (position) {
case 0:
return(String.format(ctxt.getString(R.string.Countdown_label)));
case 1:
return(String.format(ctxt.getString(R.string.Countup_label)));
}
return null;
}
@Override
public int getCount() {
// doing only three pages, right now...one for countdown, one for countup, and one for Tabata.
return 2;
}
private static String makeFragmentName(int viewId, int position)
{
return "android:switcher:" + viewId + ":" + position;
}
}
Fragment 中有更多的代码,所以我将把应该是问题的核心的代码放入其中......如果需要更多,我会拼接进去。
public class Countdown_Fragment extends Fragment implements OnClickListener {
Calendar CountdownTime = Calendar.getInstance();
static AutoResizeTextView tv;
static ImageButton HoursUp;
static ImageButton HoursDown;
static ImageButton MinutesUp;
static ImageButton MinutesDown;
static ImageButton SecondsUp;
static ImageButton SecondsDown;
static ImageButton Reset;
static ImageButton StartPausecount;
static ImageButton Stopcount;
static Boolean Arewecounting = false;
static Boolean Arewecountingdown = false;
static AutoResizeTextView ThreetwooneGO;
static MyCountdownTimer Countdown_Timer_Activity;
ThreetwooneCount Start_countdown;
static Long MillstoPass;
static Countdown_Fragment newInstance() {
Countdown_Fragment frag = new Countdown_Fragment();
return (frag);
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("CurrentTimer", (String) tv.getText());
Log.v("status", "saved fragment state" + tv.getText());
super.onSaveInstanceState(outState);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
@Override
public void onCreate(Bundle savedInstanceState) {
setRetainInstance(true);
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setRetainInstance(true);
View result = inflater.inflate(R.layout.countdown_timer_layout,
container, false);
tv = (AutoResizeTextView) result.findViewById(R.id.timer_textview);
tv.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
new TimePickerDialog(getActivity(), t, 0, 0, true).show();
}
});
if (savedInstanceState != null) {
Log.v("status", "fragment is NOT empty");
tv.setText(savedInstanceState.getString("CurrentTimer",
tv.toString()));
} else {
Log.v("status", "fragment is empty");
// tv.setText("00:00:00");
}
tv.resizeText();
ThreetwooneGO = (AutoResizeTextView) result
.findViewById(R.id.timer_countdown_text);
HoursUp = (ImageButton) result.findViewById(R.id.hours_up);
HoursDown = (ImageButton) result.findViewById(R.id.hours_down);
MinutesUp = (ImageButton) result.findViewById(R.id.minutes_up);
MinutesDown = (ImageButton) result.findViewById(R.id.minutes_down);
SecondsUp = (ImageButton) result.findViewById(R.id.seconds_up);
SecondsDown = (ImageButton) result.findViewById(R.id.seconds_down);
Reset = (ImageButton) result.findViewById(R.id.reset);
StartPausecount = (ImageButton) result
.findViewById(R.id.startpausecount);
Stopcount = (ImageButton) result.findViewById(R.id.stopcount);
HoursUp.setOnClickListener(this);
HoursDown.setOnClickListener(this);
SecondsUp.setOnClickListener(this);
SecondsDown.setOnClickListener(this);
MinutesUp.setOnClickListener(this);
MinutesDown.setOnClickListener(this);
Reset.setOnClickListener(this);
StartPausecount.setOnClickListener(this);
Stopcount.setOnClickListener(this);
return (result);
}
public void chooseTime(View v) {
new TimePickerDialog(getActivity(), t, 0, 0, true).show();
}
TimePickerDialog.OnTimeSetListener t = new TimePickerDialog.OnTimeSetListener() {
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
CountdownTime.set(Calendar.HOUR_OF_DAY, hourOfDay);
CountdownTime.set(Calendar.MINUTE, minute);
CountdownTime.set(Calendar.SECOND, 0);
CountdownTime.set(Calendar.MILLISECOND, 0);
updateLabel();
}
};
private void updateLabel() {
String entiretime;
entiretime = String.format("%tT", CountdownTime);
tv.setText(entiretime);
}
这是我用于倒计时的计时器....
public class MyCountdownTimer {
private long millisInFuture;
private long countDownInterval;
Countdown_Fragment ctxt;
AutoResizeTextView Timer_edit;
private volatile boolean IsStopped = false;
public MyCountdownTimer(long pMillisInFuture, long pCountDownInterval,
AutoResizeTextView Artv) {
this.millisInFuture = pMillisInFuture;
this.countDownInterval = pCountDownInterval;
Timer_edit = Artv;
}
public void Start() {
final Handler handler = new Handler();
final Runnable counter = new Runnable() {
public void run() {
if (IsStopped == false) {
if (millisInFuture <= 0) {
Countdown_Fragment.done_counting();
} else {
long sec = millisInFuture / 1000;
Timer_edit.setText(String.format("%02d:%02d:%02d",
sec / 3600, (sec % 3600) / 60, (sec % 60)));
millisInFuture -= countDownInterval;
handler.postDelayed(this, countDownInterval);
}
}
}
};
handler.postDelayed(counter, countDownInterval);
}
public void Cancel() {
IsStopped = true;
Timer_edit = null;
Log.v("status", "Main Timer cancelled");
// this.ctxt = null;
}
public long whatisourcount(){
return(millisInFuture);
}
}
最佳答案
事实证明,RetainInstance 导致其自身与 ViewPager/Adapter/FragmentManager 之间发生冲突。删除它会导致寻呼机正确重建 fragment ,包括我拥有的 TextView,而以前没有。我也开始在 OnCreateView 中收到一个 Bundle,在 RetainInstance 设置为 True 之前它始终为 null。
我必须删除 RetainInstance 并利用 OnSaveInstanceState 和 OnCreateView 传入 Fragment 销毁前的当前状态,然后在 OnCreateView 中重新创建它以将 Fragment 重置为销毁前的状态。
我希望我用来倒计时的 Runnable 能够存活下来,或者我能够重新附加它,但我找不到办法。我必须以毫秒为单位保存当前计数,然后传回 fragment 以从中断处继续。这没什么大不了的,但我很好奇你是否真的能重新连接所有这些东西。 Runnable 在配置更改后仍然继续,但它不再更新 UI 上的任何内容,因此当我在 OnSaveInstanceState 中时,我尝试取消回调并将其清空。
我还阅读了一些项目,其中我只需要将 RetainInstance 用于附加了 AsyncTask 的项目或其他类似项目....否则,只需在代码中重建它即可。
关于android - FragmentPagerAdapter 在方向更改时不恢复 fragment ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18425646/
如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe
假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。
我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功
我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO
我正在使用Watir运行一个Ruby脚本来为我自动化一些事情。我试图自动将一些文件保存到某个目录。因此,在我的Mozilla设置中,我将默认下载目录设置为桌面并选择自动保存文件。但是,当我开始运行我的脚本时,这些更改并没有反射(reflect)出来。似乎首选项恢复为默认值。我已经包括以下内容require"rubygems"#Optional.require"watir-webdriver"#Forwebautomation.require"win32ole"#Forfilesavedialog.并打开一个新的firefox实例:browser=Watir::Browser.new(:
我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的