我正在重写我的Android
应用,以取消对onResume()
的直接通话。
我的应用目前在onResume()
内完成了大部分工作,然后发布了显示内容,这是onResume()
的结尾。
@Override
public void onResume() {
super.onResume();
// get current date and time,
// and determine if daylight savings time is in effect.
//...600 lines of code
// output both the chart and report
//
image.setImageBitmap(heightChart);
report.setImageBitmap(reportBitmap);
}
下一步是收集用户输入,告诉我对其进行了哪些更改 报告用户的意愿。 (它可能是新位置,新日期或新显示样式等)。这样做如下:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final int STATION_REQUEST = 1;
int test = 1;
switch (item.getItemId()) {
case R.id.refresh: {
userDateSet = false;
onResume();
return true;
} // come to the present.
//...200 lines of code
default:
return super.onOptionsItemSelected(item);
}
}
如示例所示,在确定新用户命令后,通过调用onResume()
重新生成输出。这是不好的做法,我已经知道了!!然而,就我所确定的而言,它运作良好,老实说我不明白它的问题。
我的解决方案是将600行代码收集到一个单独的例程中,然后在onResume()
内和onOptionsItemSelected()
@Override
public void onResume() {
super.onResume();
myOnResumeCode();
}
在onOptionsItemSelected()
里面做这个
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final int STATION_REQUEST = 1;
int test = 1;
switch (item.getItemId()) {
case R.id.refresh: {
userDateSet = false;
myOnResumeCode();
return true;
} // come to the present.
... // Other statements
}
这种方法可以接受吗?如果没有,任何缺少“重写整个事情”的建议对我都非常有帮助。我已经广泛搜索了一个干净的解决方案,但找不到我能理解的解决方案。谢谢。
答案 0 :(得分:3)
然而就我所确定的而言,它运作良好,老实说,我不明白它的问题。
您假设在您手动调用super.onResume()
的情况下调用onResume()
是合适的。这不是一个安全的假设。
这种方法是否可以接受
这肯定是一种改进,值得做。
600行代码是真正的长方法。您将无法进行许多代码审查,审阅者会要求您重构该代码以使其更易于维护。此外,根据您在这600行中的操作,将该逻辑移动到后台线程可能更好。
答案 1 :(得分:3)
考虑每次调用super.onResume()
时执行的Activity
's onResume()
source code:
protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
mActivityTransitionState.onResume();
mCalled = true;
}
其中mActivityTransitionState.onResume()
通过对窗口中的视图采取进一步操作来调用resetViews()
。因此,当您体验到它的工作原理时,所有方法调用都会浪费CPU时间,实际上是多余的,从而得出结论第一种方法效率低下。
另一方面,在不调用myOnResumeCode()
的情况下使用super.onResume()
的意图避免了不必要的方法调用,并且是一种更优化的解决方案。
此外,600行代码相当多。如果这些行在主线程上运行,它会冻结UI,使应用程序看起来响应性降低。最好在后台线程上进行计算,并在主线程上发布视图更改。
我没有听到过在我的代码中没有调用super的担心。
似乎是对Activity
生命周期方法意图的误解。这些方法是系统用来向听众通知其中发生的事件的回调。一旦系统调用了onResume()
,您就会收到这样的通知。如果您删除super.onResume()
,您将收到例外情况,它会在链接的源代码中明确说明,并且是系统在调用Ativity
时“希望”onResume()
执行的唯一请求。它适用于所有其他生命周期方法 - 由操作系统提供信息。系统无需关心Activity
是否“手动”再次调用它们。虽然Activity
位于前台,但您可以根据需要尽可能多地调用onResume()
浪费CPU时间,并使您的应用对用户的响应能力降低。
同样,被覆盖的onResume()
是一个回调(“监听器”)并且不能影响系统行为,例如,影响系统行为的finish()
方法说:“嘿,系统,我已经完成并想要被你杀死”。这些方法可以被视为对系统的请求。
<强>更新强>
他们甚至会告诉您将应用程序代码放在何处?
您可以随意将代码放在任何地方。例如,当您的内容对用户可见或隐藏时,系统会通知您生命周期方法调用。所以这是一个根据生命周期事件将代码放在合理“位置”的问题。
这是否可以直接调用onResume()?有强烈声明禁止表达的禁令。
这是毫无意义的,但正如你所目睹的那样有效。 “你不应该在星期五吃肉”,但谁说你不能? :)
答案 2 :(得分:3)
老实说,我不明白它的问题。
您的onResume()
方法实现本身是无害的。但是调用它的超级方法super.onResume();
会让系统认为它是恢复事件的另一种情况。这将导致刷新视图和类似内部工作的不必要的资源使用。因此,在任何情况下都必须避免显式调用生命周期回调方法。
这种方法可以接受吗?
代码行数不能接受或不接受。 这是一个你需要问自己的问题。如果您认为整个代码将在该事件中执行,那么您应该这样做。否则你可以节省一些资源。
如果您正在做这样的事情
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.mnuEnableSomething:
{
refreshTheWholeUi();
return true;
}
case R.id.mnuClearList:
{
refreshTheWholeUi();
return true;
}
}
}
public void onResume() {
super.onResume();
refreshTheWholeUi();
}
然后将其更改为此值得。
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.mnuEnableSomething:
{
enableIt();
return true;
}
case R.id.mnuClearList:
{
justClearTheList();
return true;
}
}
}
public void onResume() {
super.onResume();
refreshTheWholeUi();
}
在你回复之后,我仔细研究了你的问题,这让我大吃一惊。
我的计划是将这600行移到一个单独的类文件中。那会的 当我使用命令解码器时,让它们远离损坏 活动源文件
实际上并非如此。但你真的很亲密。忘掉活动生命周期,方法,类等所有复杂性,只关注计算机程序的最基本执行级别。
程序总是逐行执行。如何安排代码并没有什么不同。将程序正确地构造成方法,类等是为了方便程序员。对于系统来说,它始终是一系列的线条。因此,在执行繁重的任务时,UI可能会变得无法响应,因为它必须等到轮到它。
然后如何并行工作?
多线程...!
听起来并不复杂。
您必须找到代码中最关键的部分,它会更多地使用资源并将其移动到不同的线程。
我已经说明了如何在这里进行多线程。
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.mnuProceessImageAction:
{
//Let user know that a background operation is running
//with a progressbar or something
processImage(mImage);
return true;
}
}
}
private void processImage(Object image) {
new Thread(new Runnable(){
public void run() {
//Doing all the heavy duty here.
//.............................
//Now you have the result. Use it to update the UI.
//(UI can be updated only from the UI thread)
runOnUiThread(new Runnable(){
public void run() {
updateTheUiWithTheImage(proccessedImage);
}
});
}
}).start();
}
private void updateTheUiWithTheImage(Object image) {
try {
//Hide progressbar if you have one
//Now it wont make the UI to struggle to use it.
} catch(NullPointerException e) {
e.printStackTrace;
}
}
这是最基本的形式。当然还有其他选择(比如 AsyncTask )。您可以在线轻松找到更多相关信息(尝试搜索&#34; Android中的多线程和#34;)。随意问更多。
答案 3 :(得分:1)
然而就我所确定的而言,它运作良好,老实说,我没有 了解它的问题。
我认为@CommonsWare和其他人已经指出了在根据用户交互再次更新UI元素的同时调用onResume
函数时将遇到的问题。
这种方法可以接受吗?如果没有,任何建议都缺少&#34;重写 整件事&#34;对我很有帮助。
总是无法维护600行代码。您可以考虑将它们分解为多个功能。但是,从我的观点来看,将所有事物从一个地方拉到一起仍然是一项艰巨的任务。
我强烈建议您在案例中使用ViewModel
。实施和管理将变得更加简单。我正在附加developer documentation的示例实现。
public class UserActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_activity_layout);
final UserModel viewModel = ViewModelProviders.of(this).get(UserModel.class);
viewModel.userLiveData.observer(this, new Observer() {
@Override
public void onChanged(@Nullable User data) {
// update ui.
}
});
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewModel.doAction();
}
});
}
}
ViewModel
会是这样的。
public class UserModel extends ViewModel {
public final LiveData<User> userLiveData = new LiveData<>();
public UserModel() {
// trigger user load.
}
void doAction() {
// depending on the action, do necessary business logic calls and update the
// userLiveData.
}
}
关于您ViewModel
中的某些数据的操作,我们已经实现了回调函数onChange
,因此会更新UI。
实现回调函数的想法可以通过多种方式完成(例如,定义interface
,然后覆盖函数)。如果能够正确实现代码,它会使代码更加清晰。
来自ViewModel
...
ViewModel
也可以用作之间的通信层Fragments
的不同Activity
。每个Fragment
都可以获得ViewModel
通过Activity
使用相同的密钥。这允许 片段之间以解耦方式进行通信,使它们成为可能 永远不需要直接与其他Fragment
交谈。
public class MyFragment extends Fragment {
public void onStart() {
UserModel userModel = ViewModelProviders.of(getActivity()).get(UserModel.class);
}
}
现在我想,你的问题变得更加简单了。您可能还会考虑在几个Fragment
中分解您的UI元素,并使用不同的生命周期元素处理更新。
希望有所帮助!
答案 4 :(得分:1)
这是我的最终编码,感谢Ahamad的出色指导。 我现在从不打电话给onResume()。在各个地方,我调用myOnResume()。 part1()代码是所有扩展计算。 part2()代码是 所有输出操作。
@Override
public void onResume()
{ super.onResume();//
myOnResume();
}// end: onResume.
void myOnResume()
{ new Thread(new Runnable()
{ public void run() //run #1
{ part1(); // do all the calculations in background.
runOnUiThread(new Runnable()
{ public void run() //run #2
{ part2(); // do the display in the UI thread.
} //end of run#2
}); //end of runOnUiThread
} //end of run#1
}).start();
} //end: myOnResume()
答案 5 :(得分:0)
这是开发人员习惯使用生命周期方法执行某些任务的一种常见习惯,因为它方便。
但实际代码必须正确模块化。
由于您正在重写代码,我建议您迁移到MVVM或MVP体系结构,因为使用这些体系结构管理您提到的案例会更好。
无论您是否使用和体系结构,最好根据目的拆分代码。
例如,onResume()
表示您在Activity/Fragment
恢复时所执行的操作。同样适用于onCreate()
,onDestroy()
等。
一般而言,
1.我们在onCreate
中初始化非变化变量,并在onDestroy
中释放它们
2.我们从后端获取数据或刷新onResume()
中的UI
3.我们暂停任何正在进行的过程,例如onPause()
等
根据您的代码示例,您提到了大约600行,我认为这些行不执行相同的任务。
因此,您必须根据任务
拆分代码private void refreshDayLightTime(){
//refresh your time
}
private void performRefreshTasks(){
//series of codes that are to be executed one after the other
//ideally this method should call methods which perform specific tasks.
}
private void updateLaunchViews(Bitmap heightChart, Bitmap reportBitmap){
image.setImageBitmap(heightChart);
report.setImageBitmap(reportBitmap);
}
使用此方法可以保持代码清洁。主要是你最终不会打破应用程序的生命周期。您可以控制从应用程序的哪个部分调用哪个操作。
答案 6 :(得分:0)
始终建议使用任何易于使用/可维护的代码。
我建议不仅将代码移动到可维护的部分,而且通过遵循将表示层与逻辑层分开的任何方法重构实现
例如Android Model View Presenter / MVP with working example
现在,如果您可以进行更简单的解释(Simpler explanation for MVP),那么更容易调试,单元测试和可维护代码< / em>很明显。
来到你的观点(已经是@CommonsWare)已经解释了很多,将所有600行代码移到Background Thread或Async task将提高你的应用程序的性能。现在你不会再看到如下信息了。
老实说,我不明白它的问题
语句参考onResume()
onResume
系统应该通过调用超级因此,在UI线程中运行的任何方法都应该尽可能少 尽可能在该线程上工作。特别是,活动应该做 尽可能少地设置关键的生命周期方法,如 onCreate()和onResume()。可能长时间运行的操作如 网络或数据库操作,或计算上昂贵 调整位图大小等计算应该在worker中完成 线程(或者在数据库操作的情况下,通过异步 请求)
onPause
/ super onResume()
来调用 developer.android。这允许系统分配/释放资源。当然,我们可以通过在onPause()
,existing package by the same name with a conflicting signature is already installed
等内部调用子方法来扩展可用性。但是在这些方法中保留业务逻辑并调用这些方法根本不可取。
如果是Android life methods,下面是可以遵循的公会线。 截至目前尚无标准/固定定义,如何实现相同。但我提供的样本仍然是一个很好的起点。