Luncurkan kembali secara terprogram / buat ulang aktivitas?

121

Setelah saya melakukan beberapa perubahan dalam database saya, yang melibatkan perubahan signifikan dalam pandangan saya, saya ingin menggambar ulang, menjalankan ulang onCreate.

Bagaimana mungkin?

Pentium10
sumber

Jawaban:

129

UPDATE : Android SDK 11 menambahkan recreate()metode ke aktivitas.


Saya telah melakukannya dengan hanya menggunakan kembali maksud yang memulai aktivitas. Tentukan maksud starterIntentdi kelas Anda dan tetapkan dalam onCreate()penggunaan starterIntent = getIntent();. Kemudian saat Anda ingin memulai kembali aktivitas, panggilfinish(); startActivity(starterIntent);

Ini bukanlah solusi yang sangat elegan, tetapi ini adalah cara sederhana untuk memulai kembali aktivitas Anda dan memaksanya untuk memuat ulang semuanya.

Steve Haley
sumber
8
sebenarnya saya pikir ketika orientasi perangkat berubah saat pembuatan aktivitas dipanggil dengan cara yang mirip .. jadi saya tidak keberatan melakukan ini. startActivity (getIntent ()); selesai();
Raja
tidak pintar melakukan startActivity (getIntent ()) karena ini hanya akan melapisi aktivitas di atas aktivitas. Harus mengakhiri aktivitas lama
Fallenreaper
8
@Fallenreaper Saya menyarankan untuk menelepon finish()segera setelah startActivity()alasan itu ...
Steve Haley
7
Aku mencapai itu menelepon pertama finish();kemudianstartActivity(starterIntent);
Carlo Rodríguez
3
Jadi yang mana? finish () dan Then startActivity? Atau sebaliknya?
Jeff Padgett
92

Panggil metode rekonstruksi dari aktivitas tersebut.

FernandoEscher
sumber
19
Tidak masalah jika aplikasi Anda hanya menargetkan SDK level 11 ke atas. Kalau tidak, saya akan memilih pendekatan Steve Haley.
TalkLittle
1
@FernandoEscher Sayangnya itu hanya tersedia di perangkat Honeycomb dan yang lebih baru.
IgorGanapolsky
2
tempat memanggil metode membuat ulang
SAndroidD
1
membuat ulang panggilan metode secara berulang-ulang tutup aplikasi dengan baik
SAndroidD
Saya dulu menggunakan recreate()tetapi sekarang saya melihat masalah aneh di mana tombol radio tidak diatur ulang saat membuat ulang, tetapi mereka melakukannya ketika finish(); startActivity(getIntent());jadi saya menggunakan ini untuk saat ini dan melihat cara kerjanya selama beberapa hari atau minggu berikutnya.
Ben
35

Menggabungkan beberapa jawaban di sini Anda dapat menggunakan sesuatu seperti berikut ini.

class BaseActivity extends SherlockFragmentActivity
{
    // Backwards compatible recreate().
    @Override
    public void recreate()
    {
        if (android.os.Build.VERSION.SDK_INT >= 11)
        {
            super.recreate();
        }
        else
        {
            startActivity(getIntent());
            finish();
        }
    }
}

Menguji

Saya mengujinya sedikit, dan ada beberapa masalah:

  1. Jika aktivitasnya adalah yang terendah di tumpukan, memanggil startActivity(...); finish();hanya ada aplikasi dan tidak memulai ulang aktivitas.
  2. super.recreate()sebenarnya tidak bertindak dengan cara yang sama seperti membuat ulang aktivitas secara total. Hal ini setara dengan memutar perangkat jadi jika Anda memiliki Fragments dengan setRetainInstance(true)mereka tidak akan diciptakan; hanya berhenti dan melanjutkan.

Jadi saat ini saya tidak percaya ada solusi yang dapat diterima.

Timmmm
sumber
5
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMBalih-alih menggunakan11
S.Thiongane
4
11 adalah rigth, .HONEYCOMB tidak benar, karena kode Anda di SDK <11 tidak tahu apa itu HONEYCOMB.
Tapa Simpan
6
ganti startActivity(getIntent());finish();kefinish();startActivity(getIntent());
ahmed hamdy
Tidak, menurut rekomendasi Anda harus menargetkan SDK tertinggi yang tersedia, jadi honeycomb akan tersedia pada waktu kompilasi, dan konstanta int dibawa dalam aplikasi Anda. Saya percaya itu adalah pola umum untuk menggunakan sdk int lebih besar dari minimum sdk int.
Hai Zhang
32

Pilihan 1

Hubungi recreate()Anda Activity. Namun metode ini menyebabkan layar hitam berkedip muncul selama pembuatan ulang aktivitas.

pilihan 2

finish();
startActivity(getIntent());

Tidak ada layar hitam "berkedip" di sini, tetapi Anda akan melihat transisi antara yang lama dan yang baru dengan latar belakang hitam yang tidak terlalu menyenangkan. Kami bisa lebih baik.

Opsi 3

Untuk mengatasinya, kita dapat menambahkan panggilan ke overridePendingTransition():

finish();
startActivity(getIntent());
overridePendingTransition(0, 0);

Selamat tinggal layar hitam, tetapi dalam kasus saya, saya masih melihat semacam transisi (animasi pudar), pada latar belakang berwarna kali ini. Itu karena Anda menyelesaikan instance aktivitas Anda saat ini sebelum yang baru dibuat dan menjadi terlihat sepenuhnya, dan warna di antaranya adalah nilai windowBackgroundatribut tema.

Pilihan 4

startActivity(getIntent());
finish();

Menelepon finish() setelah startActivity() akan menggunakan transisi default antar aktivitas, seringkali dengan sedikit animasi geser ke dalam. Tetapi transisi masih terlihat.

Pilihan 5

startActivity(getIntent());
finish();
overridePendingTransition(0, 0);

Bagi saya, ini adalah solusi terbaik karena memulai ulang aktivitas tanpa transisi yang terlihat, seperti jika tidak ada yang terjadi.

Ini bisa berguna jika, misalnya, di aplikasi Anda, Anda menunjukkan cara untuk mengubah bahasa tampilan secara independen dari bahasa sistem. Dalam kasus ini, setiap kali pengguna mengubah bahasa aplikasi Anda, Anda mungkin ingin memulai kembali aktivitas tanpa transisi, sehingga peralihan bahasa terlihat seketika.

cacat
sumber
1
Masalah dengan opsi 5 adalah menambahkan aktivitas sebelumnya ke backstack. Sebut ini beberapa kali dan pengguna Anda harus mengklik kembali beberapa kali untuk membuka halaman sebelumnya yang sebenarnya.
Ollie
23

Ketika saya perlu memulai kembali suatu aktivitas, saya menggunakan kode berikut. Padahal itu tidak disarankan.

Intent intent = getIntent();
finish();
startActivity(intent);
Ayush Goyal
sumber
1
Solusi yang sangat bersih dan elegan. Berfungsi dengan baik pada perangkat pra-sdk 11.
IgorGanapolsky
Memiliki masalah dengan metode super.recreate (), namun ini berfungsi dengan baik di Lollipop
6

untuk API sebelum 11 Anda tidak dapat menggunakan reinate (). Saya menyelesaikannya dengan cara ini:

Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();

dan di onCreate ..

@Override
public void onCreate(Bundle savedInstanceState) {

    if (getIntent().hasExtra("bundle") && savedInstanceState==null){
        savedInstanceState = getIntent().getExtras().getBundle("bundle");
    }

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //code

}
Francesco Ditrani
sumber
3

Setelah mencari implementasi untuk roti jahe recreate, saya ingin menggunakan kode berikut (untuk roti jahe):

activity.mMainThread.mAppThread.scheduleRelaunchActivity(activity.mToken, null, null, 0, false, null);

Untuk kode-kode ini, itu dari implementasi di api yang lebih tinggi.

public void recreate() {
    if (mParent != null) {
        throw new IllegalStateException("Can only be called on top-level activity");
    }
    if (Looper.myLooper() != mMainThread.getLooper()) {
        throw new IllegalStateException("Must be called from main thread");
    }
    mMainThread.requestRelaunchActivity(mToken, null, null, 0, false, null, false);
}

Api-10 tidak memiliki requestRelaunchActivity, namun, dari diff, saya menemukan ini:

             public final void scheduleRelaunchActivity(IBinder token,
                     List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
                     int configChanges, boolean notResumed, Configuration config) {
    -            ActivityClientRecord r = new ActivityClientRecord();
    -
    -            r.token = token;
    -            r.pendingResults = pendingResults;
    -            r.pendingIntents = pendingNewIntents;
    -            r.startsNotResumed = notResumed;
    -            r.createdConfig = config;
    -
    -            synchronized (mPackages) {
    -                mRelaunchingActivities.add(r);
    -            }
    -
    -            queueOrSendMessage(H.RELAUNCH_ACTIVITY, r, configChanges);
    +            requestRelaunchActivity(token, pendingResults, pendingNewIntents,
    +                    configChanges, notResumed, config, true);
             }

Jadi saya pikir saya bisa menggunakan scheduleRelaunchActivitybukan requestRelaunchActivity.

Dan saya telah menuliskannya menggunakan refleks:

package me.piebridge.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Build;
import android.os.IBinder;

public class GingerBreadUtil {

    private static Field scanField(Class<?> clazz, String... names) {
        for (String name : names) {
            Field field;
            try {
                field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                return field;
            } catch (NoSuchFieldException e) {
            }
            try {
                field = clazz.getField(name);
                field.setAccessible(true);
                return field;
            } catch (NoSuchFieldException e) {
            }
        }
        return null;
    }

    public static void recreate(Activity activity) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) {
            recreateHC(activity);
        } else {
            try {
                recreateGB(activity);
            } catch (InvocationTargetException e) {
                e.getTargetException().printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private static void recreateHC(Activity activity) {
        ((Activity) activity).recreate();
    }

    private static void recreateGB(Activity activity) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Field Activity$mToken = scanField(Activity.class, "mToken");
        IBinder mToken = (IBinder) Activity$mToken.get(activity);
        Field Activity$mMainThread = scanField(Activity.class, "mMainThread");
        Object mMainThread = Activity$mMainThread.get(activity);
        Field ActivityThread$mAppThread = scanField(mMainThread.getClass(), "mAppThread");
        Object mAppThread = ActivityThread$mAppThread.get(mMainThread);
        Method method = mAppThread.getClass().getMethod("scheduleRelaunchActivity",
            IBinder.class, List.class, List.class, int.class, boolean.class, Configuration.class);
        method.invoke(mAppThread, mToken, null, null, 0, false, null);
    }

}

Saya menggunakan kode ini untuk porting belakang kerangka xposed.

liudongmiao
sumber
Pekerjaan yang fantastis! Saya mengujinya di emulator, dan pendekatan ini kompatibel ke belakang ke Build.VERSION_CODES.ECLAIR_MR1(v7). Ini mungkin bekerja pada versi yang lebih lama juga.
Tim Cooke
3

Panggil recreate() metode dari tempat Anda ingin membuat ulang aktivitas Anda. Metode ini akan menghancurkan instance Aktivitas saat ini dengan onDestroy()dan kemudian membuat ulang aktivitas dengan onCreate().

neo
sumber
1

Jika ini adalah masalah Anda, Anda mungkin harus mengimplementasikan cara lain untuk mengisi tampilan di Aktivitas Anda. Alih-alih menjalankan kembali onCreate()Anda harus membuatnya sehingga onCreate()memanggil metode pengisian Anda dengan beberapa argumen. Ketika data berubah, metode pengisian harus dipanggil dengan argumen lain.

MrSnowflake
sumber
1

Cara saya mengatasinya adalah dengan menggunakan Fragmen . Ini kompatibel mundur hingga API 4 dengan menggunakan pustaka dukungan.

Anda membuat tata letak "pembungkus" dengan FrameLayout di dalamnya.

Contoh:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical" >

     <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/fragment_container"
          android:layout_width="match_parent"
          android:layout_height="match_parent" />
</LinearLayout>

Kemudian Anda membuat FragmentActivity di mana Anda dapat mengganti FrameLayout kapan pun Anda mau.

Contoh:

public class SampleFragmentActivity extends FragmentActivity
{

     @Override
 public void onCreate(Bundle savedInstanceState)
 {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.wrapper);

    // Check that the activity is using the layout version with
    // the fragment_container FrameLayout
    if (findViewById(R.id.fragment_container) != null)
    {

        // However, if we're being restored from a previous state,
        // then we don't need to do anything and should return or else
        // we could end up with overlapping fragments.
        if (savedInstanceState != null)
        {
            return;
        }
        updateLayout();
     }
  }

  private void updateLayout()
  {
     Fragment fragment = new SampleFragment();
     fragment.setArguments(getIntent().getExtras());

     // replace original fragment by new fragment
     getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
  }

Di Fragmen yang Anda kembangkan / ganti, Anda bisa menggunakan onStart dan onCreateView seperti biasanya Anda menggunakan onCreate dari suatu aktivitas.

Contoh:

public class SampleFragment extends Fragment
{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        return inflater.inflate(R.layout.yourActualLayout, container, false);
    }

    @Override
    public void onStart()
    {
        // do something with the components, or not!
        TextView text = (TextView) getActivity().findViewById(R.id.text1);

        super.onStart();
    }
}
Spikey
sumber
1

Juga tergantung pada situasi Anda, Anda mungkin perlu getActivity().recreate();daripada hanya recreate().

Misalnya, Anda harus menggunakannya jika Anda melakukan recreate()di kelas yang telah dibuat di dalam kelas aktivitas.

danyapd
sumber
0

Saya pernah membuat aplikasi uji coba yang mengupload, menghapus, lalu mendownload ulang file database menggunakan penyimpanan cloud firebase. Untuk menampilkan data dalam database, kode berikut adalah satu-satunya solusi yang saya temukan. Baik recreate()atau finish()bekerja dalam kasus ini.

Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
System.exit(0);
Hasan El-Hefnawy
sumber
0

Saya menemukan cara terbaik untuk menyegarkan Fragmen Anda saat data berubah

jika Anda memiliki tombol "cari", Anda harus menginisialisasi daftar ARRAY Anda di dalam tombol tersebut

mSearchBtn.setOnClickListener (baru View.OnClickListener () {

@Override public void onClick (Tampilan v) {

mList = new ArrayList<Node>();

firebaseSearchQuery.addValueEventListener(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot dataSnapshot) {


      for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {

        Node p = dataSnapshot1.getValue(Node .class);
        mList.add(p);
      }
      YourAdapter = new NodeAdapter(getActivity(), mList);
      mRecyclerView.setAdapter(YourAdapter );

    }
Francis Eyogo
sumber
-2

Jika Anda ingin meneruskan parameter ke onCreate () maka Anda harus membuat maksud baru dengan menambahkan ekstra dan memanggil StartActivity dengannya. Berikut adalah contoh sederhana yang saya lakukan dengan cara ini.

              String eczSabit = sa.getItem(position).getValue();
              if(!Util.IsNullOrEmpty(eczSabit)){
                  sabit = Long.parseLong(eczSabit);
                  Intent intent = new Intent(eczaneSegmentasyon.this,eczaneSegmentasyon.class);
                  intent.putExtra("sabit", sabit);
                  startActivity(intent);
              }
Mustafa Güven
sumber
konvensi penamaan yang buruk, nama variabel yang buruk, kode yang sangat membingungkan ... -1
Ahmed Adel Ismail
-4

Jika Anda hanya ingin mengulang pandangan Anda, saya mengalami masalah yang persis sama. Dalam onResumefungsinya coba letakkan ini:

mView = new AndroidPinballView(getApplication());

Ini juga ada di saya onCreate(), jadi meletakkan ini di onResumeberhasil untuk saya :)

Scumble373
sumber