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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 01:22:13  来源:igfitidea点击:

android: Instantly start an activity and then load content

javaandroidandroid-activity

提问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 AsyncTaskfor loading data and RelativeLayoutfor displaying Rounding Circle in ActivityB.

您需要AsyncTask用于加载数据和RelativeLayoutActivityB.

First initialize variable

首先初始化变量

private RelativeLayout mRelativeLayout;

and in onCreateof your activity execute AsyncTasklike 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 AsyncTaskclass 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 XMLinclude this layout

XML包含此布局

In order to get the ProgressBarwithout 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 RelativeLayoutin onPreExecuteand onPostExecuterespectively like I have shown in example.

并设置这个的可见性RelativeLayoutonPreExecuteonPostExecute分别像我已经示例中所示。

UPDATE:

更新:

you need to update your Uiin UiThreadlike this

你需要更新你UiUiThread这样的

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 ProgressBarto B layout
  • get a reference to this ProgressBarin B's onCreate(using findViewById()
  • update your ProgressBarwith setProgress(int)everytime you want(as shown in the first part of the question for ProgressDialog)
  • hide your ProgressBarusing your ProgressBar.setVisibility(View.GONE)
  • 添加 AProgressBar到 B 布局
  • ProgressBar在 B 中获取对此的引用onCreate(使用findViewById()
  • 更新你ProgressBarsetProgress(int)你想每次(如图对这个问题的第一部分ProgressDialog
  • 隐藏你的ProgressBar使用你的ProgressBar.setVisibility(View.GONE)

回答by Gooey

Sounds like you are doing everything (including the heavy loading stuff) in the onCreatefunction. Take a look at the Activity life cycle and consider putting code in e.g. the onStartor onResume. Also, heavy stuff can be put on a worker threadfor example. This keeps your UI responsiveand the user more happy.

听起来你正在onCreate函数中做所有事情(包括重载的东西)。查看Activity 生命周期并考虑将代码放入例如onStartor 中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.

希望,它会正常工作。祝你好运。