java android:立即启动一个活动,然后加载内容
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36385523/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
android: Instantly start an activity and then load content
提问by John Sardinha
I've looked into other questions, blogs and the documention and can't seem to find the right answer to my needs. I have two activities, A and B. When I start activity B (from A) I want it to open instantly and then load all the content while showing a progress bar, instead of only opening the activity when the content is loaded, making it seem like it froze for two seconds. An exemple would be the Youtube app or the Play Store.
我查看了其他问题、博客和文档,但似乎无法找到满足我需求的正确答案。我有两个活动,A 和 B。当我开始活动 B(从 A)时,我希望它立即打开,然后在显示进度条的同时加载所有内容,而不是仅在加载内容时打开活动,使其成为好像冻结了两秒钟。一个例子是 Youtube 应用程序或 Play 商店。
That's what i got:
这就是我得到的:
Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent goB = new intent(ActivityA.this, ActivityB.class);
startActivity(goB);
}
});
This is the activity I'm loading:
这是我正在加载的活动:
public class ActivityB extends AppCompatActivity implements OnDateSelectedListener, OnMonthChangedListener {
private static final DateFormat FORMATTER = SimpleDateFormat.getDateInstance();
@Bind(R.id.calendarView) MaterialCalendarView widget;
@Bind(R.id.textView) TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_c_calendar);
ButterKnife.bind(this);
widget.setOnDateChangedListener(this);
widget.setOnMonthChangedListener(this);
textView.setText(getSelectedDatesString());
}
@Override
public void onDateSelected(@NonNull MaterialCalendarView widget, @Nullable CalendarDay date, boolean selected) {
textView.setText(getSelectedDatesString());
}
private String getSelectedDatesString() {
CalendarDay date = widget.getSelectedDate();
if (date == null) {
return "No Selection";
}
return FORMATTER.format(date.getDate());
}
@Override
public void onMonthChanged(MaterialCalendarView widget, CalendarDay date) {
}
}
I'm not an expert, so detailed explanations will be welcomed.
我不是专家,所以欢迎详细解释。
Note: What I'm loading in the activity is this calendar: https://github.com/prolificinteractive/material-calendarview
注意:我在活动中加载的是这个日历:https: //github.com/prolificinteractive/material-calendarview
Question:How to load setContentView()
on the background?
问:如何setContentView()
在后台加载?
Update:I followed Hitesh Sahu's advice and now I only have one activity with one container that gets replaced for each fragment, I'm assuming the way to load the xml content in the background will be the same for a fragment and an activity, but if there is any difference please do mention.
更新:我遵循了 Hitesh Sahu 的建议,现在我只有一个带有一个容器的活动,每个片段都会被替换,我假设在后台加载 xml 内容的方式对于片段和活动是相同的,但是如果有任何不同,请务必提及。
回答by Hitesh Sahu
Possible solution
可能的解决方案
From "I am not an expert"my guess is you might be creating new activity on every screen switching and possibly not clearing older one or reusing existing activity. Again this is my guess I have not seen your code but I have seen developers doing this kind of mistakes .Soon your App's performance will degrade over time and your app will end up eating memory.
How to fix this:- Replace activitieswith fragmentswitching fragment is relatively faster than switching activities plus you can reuse them (more about this).
You might be doing some heavy task on Main Ui thread look for choreographerlogs like -
skipped n number of frames app may be doing too much work on main thread
How to fix this:- already explained in other answers.
从“我不是专家”我的猜测是,您可能会在每次屏幕切换时创建新活动,并且可能不会清除旧活动或重用现有活动。再次,这是我的猜测,我没有看到您的代码,但我看到开发人员犯了这种错误。很快您的应用程序的性能会随着时间的推移而下降,您的应用程序最终会吃掉内存。
如何解决这个问题:-用片段切换片段替换活动比切换活动更快,而且你可以重用它们(更多关于这个)。
您可能会在 Main Ui 线程上执行一些繁重的任务,查找编舞日志,例如 -
skipped n number of frames app may be doing too much work on main thread
如何解决这个问题:- 已经在其他答案中解释过。
回答by Wackaloon
Your activity B should have AsyncTask for loading data and then displaying it.
Also you can load some default data in view inside of OnPreExecute()
你的活动 B 应该有 AsyncTask 来加载数据然后显示它。您也可以在视图中加载一些默认数据OnPreExecute()
@Override
protected void onCreate(Bundle savedInstanceState) {
setupViews();
}
private void setupViews(){
someView1 = (TextView) findViewById(R.id.some_view_id1);
someView2 = (TextView) findViewById(R.id.some_view_id2);
someView3 = (ImageView) findViewById(R.id.some_view_id3);
progressBar = (ProgressBar) findViewById(R.id.progress_bar_id);
new LoadDataForActivity().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private class LoadDataForActivity extends AsyncTask<Void, Void, Void> {
String data1;
String data2;
Bitmap data3;
@Override
protected void onPreExecute() {
progressBar.setVisibility(View.VISIBLE);
}
@Override
protected Void doInBackground(Void... params) {
data1 = loadData1();
data2 = loadData2();
data3 = loadData3();
}
@Override
protected void onPostExecute(Void result) {
someView1.setText(data1);
someView2.setText(data2);
someView3.setImageBitmap(data3);
progressBar.setVisibility(View.GONE);
}
}
回答by Max
You need to use AsyncTask
for loading data and RelativeLayout
for displaying Rounding Circle in ActivityB
.
您需要AsyncTask
用于加载数据和RelativeLayout
在ActivityB
.
First initialize variable
首先初始化变量
private RelativeLayout mRelativeLayout;
and in onCreate
of your activity execute AsyncTask
like this
在onCreate
你的活动中AsyncTask
像这样执行
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRelativeLayout = (RelativeLayout) findViewbyID(R.id.loadingCircle);
new PrepareData().execute();
}
put this AsyncTask
class in ActivityB
把这个AsyncTask
类放在ActivityB
private class PrepareData extends AsyncTask<Void, Void, Void> {
protected void onPreExecute(Void param) {
// THIS WILL DISPLAY THE PROGRESS CIRCLE
mRelativeLayout.setVisibility(View.VISIBLE)
}
protected Void doInBackground(Void... param) {
// PUT YOUR CODE HERE TO LOAD DATA
return null;
}
protected void onPostExecute(Void param) {
// THIS WILL DISMISS CIRCLE
mRelativeLayout.setVisibility(View.GONE)
}
and in XML
include this layout
并XML
包含此布局
In order to get the ProgressBar
without dialog is to use this
为了获得ProgressBar
无对话框是使用这个
<RelativeLayout
android:id="@+id/loadingCircle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:gravity="center" >
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</RelativeLayout>
and set the visibility of the this RelativeLayout
in onPreExecute
and onPostExecute
respectively like I have shown in example.
并设置这个的可见性RelativeLayout
在onPreExecute
与onPostExecute
分别像我已经示例中所示。
UPDATE:
更新:
you need to update your Ui
in UiThread
like this
你需要更新你Ui
在UiThread
这样的
runOnUiThread(new Runnable() {
@Override
public void run() {
//put the code here that is giving exception
}
});
回答by Akhil Soman
You could use an AsyncTask.
您可以使用 AsyncTask。
Eg : Add this in your activity page(outside onCreate()).
例如:将其添加到您的活动页面中(在 onCreate() 之外)。
class OnLoading extends AsyncTask<Void,Void,Void>{
ProgressDialog pd;
@Override
protected void onPreExecute() {
super.onPreExecute();
pd=new ProgressDialog(Main2Activity.this);
pd.setTitle("Title");
pd.setMessage("Message");
pd.setCancelable(false);
pd.show();
}
@Override
protected Void doInBackground(Void... params) {
//
//Do all your loading stuff here
//
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
pd.dismiss();
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
This class is executed by calling
这个类是通过调用来执行的
new OnLoading().execute();
On executing this code the first function executed will be onPreExecute->doInBackGround->onPostExecute.. Progress update can be used to show some progress from the doInBackGround function by calling
执行此代码时,执行的第一个函数将是onPreExecute->doInBackGround->onPostExecute。. 进度更新可用于通过调用显示来自 doInBackGround 函数的一些进度
publishProgress(value);
Here first the ProgressDialog will be shown. Provide the code to load the datas etc in the doInBackground. As the name implies anything you write in this function will be executed in the background. After this function completes execution, the progress dialog will be dismissed in the onPostExecute().
这里首先将显示 ProgressDialog。提供代码以在 doInBackground 中加载数据等。顾名思义,您在此函数中编写的任何内容都将在后台执行。此函数执行完成后,将在 onPostExecute() 中关闭进度对话框。
回答by Andre99
Just put this code:
只需输入以下代码:
Intent goB = new intent(ActivityA.this, ActivityB.class);
startActivity(goB);
In A's onCreate. Then create a ProgressDialog like the one shown here: http://www.tutorialspoint.com/android/android_progressbar.htm
在 A 的 onCreate 中。然后创建一个 ProgressDialog,如下所示:http: //www.tutorialspoint.com/android/android_progressbar.htm
This will show the progress of B loading. You'll call
这将显示 B 加载的进度。你会打电话
progress.setProgress(int)
in B's onCreate, after doing something.
在 B 的 onCreate 中,做了一些事情之后。
For example:
例如:
public class B extends Activity {
public void onCreate(Bundle bundle) {
progress=new ProgressDialog(this);
progress.setMessage("Downloading Music");
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setIndeterminate(true);
progress.setProgress(0);
progress.show();
//do something
progress.setProgress(1);
//do something
progress.setProgress(2);
//do something different
progress.setProgress(3);
}
.....
EDIT
编辑
Here is how you can do it using a ProgressBar:
以下是使用 ProgressBar 的方法:
- add a
ProgressBar
to B layout - get a reference to this
ProgressBar
in B'sonCreate
(usingfindViewById()
- update your
ProgressBar
withsetProgress(int)
everytime you want(as shown in the first part of the question forProgressDialog
) - hide your
ProgressBar
using yourProgressBar.setVisibility(View.GONE)
- 添加 A
ProgressBar
到 B 布局 ProgressBar
在 B 中获取对此的引用onCreate
(使用findViewById()
- 更新你
ProgressBar
与setProgress(int)
你想每次(如图对这个问题的第一部分ProgressDialog
) - 隐藏你的
ProgressBar
使用你的ProgressBar.setVisibility(View.GONE)
回答by Gooey
Sounds like you are doing everything (including the heavy loading stuff) in the onCreate
function. Take a look at the Activity life cycle and consider putting code in e.g. the onStart
or onResume
. Also, heavy stuff can be put on a worker threadfor example. This keeps your UI responsiveand the user more happy.
听起来你正在onCreate
函数中做所有事情(包括重载的东西)。查看Activity 生命周期并考虑将代码放入例如onStart
or 中onResume
。此外,例如,可以将重物放在工作线程上。这可以使您的 UI 保持响应并且用户更满意。
回答by Akash Raghav
Firstly start your activity as
首先开始你的活动
startActivity(new intent(A.this, B.class));
from whatever event you have chosen, then here is how your Activity B should work.
从您选择的任何事件来看,这就是您的活动 B 应该如何工作。
class B extends AppCompatActivity implements OnDateSelectedListener, OnMonthChangedListener {
private static final DateFormat FORMATTER = SimpleDateFormat.getDateInstance();
@Bind(R.id.calendarView) MaterialCalendarView widget;
@Bind(R.id.textView) TextView textView;
ProgressDialog progressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
if(!B.this.isFinishing() && progressDialog != null && !progressDialog.isShowing()) {
progressDialog.show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
ButterKnife.bind(B.this);
widget.setOnDateChangedListener(B.this);
widget.setOnMonthChangedListener(B.this);
textView.setText(getSelectedDatesString());
if(!B.this.isFinishing() && progressDialog != null && progressDialog.isShowing()) {
progressDialog.hide();
}
}, 1500);
}
@Override
public void onDateSelected(@NonNull MaterialCalendarView widget, @Nullable CalendarDay date, boolean selected) {
textView.setText(getSelectedDatesString());
}
private String getSelectedDatesString() {
CalendarDay date = widget.getSelectedDate();
if (date == null) {
return "No Selection";
}
return FORMATTER.format(date.getDate());
}
@Override
public void onMonthChanged(MaterialCalendarView widget, CalendarDay date) {
}
}
Edit: as @Andre99 showed using progressbar :
编辑:如@Andre99 所示,使用 progressbar :
-add a ProgressBar to B layout
- 将 ProgressBar 添加到 B 布局
-get a reference to this ProgressBar in B's onCreate (using findViewById()
- 在 B 的 onCreate 中获取对此 ProgressBar 的引用(使用 findViewById()
-update your ProgressBar with setProgress(int) everytime you want(as shown in the first part of the question for ProgressDialog)
- 每次需要时使用 setProgress(int) 更新您的 ProgressBar(如 ProgressDialog 问题的第一部分所示)
-hide your ProgressBar using yourProgressBar.setVisibility(View.GONE)
- 使用 yourProgressBar.setVisibility(View.GONE) 隐藏你的 ProgressBar
回答by fractalwrench
You should use a ViewStubfor everything you don't immediately need displayed. Inflating views from XML layouts can be quite an expensive operation, particularly if you have multiple nested ViewGroups. A ViewStub works by offsetting unnecessarylayout inflation from onCreate() to a place of your choosing, which translates to your activity appearing on screen quicker.
对于不需要立即显示的所有内容,您应该使用ViewStub。从 XML 布局扩充视图可能是一项非常昂贵的操作,尤其是当您有多个嵌套的 ViewGroup 时。ViewStub 通过将不必要的布局膨胀从 onCreate()抵消到您选择的位置来工作,这意味着您的活动更快地出现在屏幕上。
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ProgressBar
android:id="@+id/progressbar"
android:layout_width="match_parent"
android:indeterminate="true"
android:layout_height="match_parent"/>
<ViewStub
android:id="@+id/view_stub"
android:inflatedId="@+id/calendarView"
android:layout="@layout/my_expensive_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Now that the ProgressBar is displayed on screen, we can inflate the ViewStub in a lifecycle call after onCreate(), such as onPostCreate() or onResume(). You can achieve that using the following:
现在 ProgressBar 显示在屏幕上,我们可以在 onCreate() 之后的生命周期调用中对 ViewStub 进行膨胀,例如 onPostCreate() 或 onResume()。您可以使用以下方法实现这一点:
viewStub.setOnInflateListener(new OnInflateListener() {
void onInflate(ViewStub stub, View inflated) {
calendarView = (MaterialCalendarView) inflated.findViewById(R.id.calendarView);
// perform any calendar setup here
progressBar.setVisibility(View.GONE); // hide progressbar, no longer needed
}
});
viewStub.inflate();
It would definitely be worth inspecting your View hierarchy, and simplifying any nested ViewGroups where possible, as this can really cause a hit when it comes to view performance. If your entire app is slow, it might indicate greater problems such as a memory leak, which you can detect with LeakCanary.
绝对值得检查您的视图层次结构,并在可能的情况下简化任何嵌套的视图组,因为这确实会影响视图性能。如果您的整个应用程序运行缓慢,则可能表明存在更大的问题,例如内存泄漏,您可以使用LeakCanary检测到。
回答by fractalwrench
You can try like below code:
您可以尝试像下面的代码:
Intent intent= new Intent(currentActivity.this, targetActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Hope, It will work properly. Best of luck.
希望,它会正常工作。祝你好运。