Câu trả lời:
CẬP NHẬT : Android SDK 11 đã thêm một recreate()phương thức vào các hoạt động.
Tôi đã thực hiện điều đó bằng cách đơn giản sử dụng lại ý định bắt đầu hoạt động. Xác định một ý định starterIntenttrong lớp của bạn và chỉ định onCreate()sử dụng nó starterIntent = getIntent();. Sau đó, khi bạn muốn khởi động lại hoạt động, hãy gọifinish(); startActivity(starterIntent);
Đó không phải là một giải pháp rất thanh lịch, nhưng đó là một cách đơn giản để khởi động lại hoạt động của bạn và buộc nó tải lại mọi thứ.
finish()ngay sau startActivity()đó vì lý do chính xác đó ...
finish();sau đóstartActivity(starterIntent);
Gọi phương thức tái tạo của hoạt động.
recreate()nhưng bây giờ tôi thấy một vấn đề kỳ lạ khi các nút radio không được đặt lại khi tạo lại, nhưng chúng thực hiện khi finish(); startActivity(getIntent());tôi đang sử dụng tính năng này bây giờ và xem nó hoạt động như thế nào trong những ngày hoặc tuần tiếp theo.
Kết hợp một số câu trả lời ở đây bạn có thể sử dụng một cái gì đó như sau.
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();
}
}
}
Tôi đã thử nghiệm nó một chút, và có một số vấn đề:
startActivity(...); finish();chỉ tồn tại ứng dụng và không khởi động lại hoạt động.super.recreate()không thực sự hoạt động theo cách tương tự như hoàn toàn tái tạo hoạt động. Nó tương đương với việc xoay thiết bị, vì vậy nếu bạn có bất kỳ Fragments nào vớisetRetainInstance(true) họ sẽ không được tái tạo; chỉ dừng lại và tiếp tục.Vì vậy, hiện tại tôi không tin có một giải pháp chấp nhận được.
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMBthay vì sử dụng11
startActivity(getIntent());finish();chofinish();startActivity(getIntent());
Gọi recreate()về của bạn Activity. Tuy nhiên phương pháp này khiến màn hình đen nhấp nháy xuất hiện trong quá trình tạo lại hoạt động.
finish();
startActivity(getIntent());
Không có màn hình đen "nhấp nháy" ở đây, nhưng bạn sẽ thấy một sự chuyển đổi giữa các trường hợp cũ và mới với một nền đen không dễ chịu lắm. Chúng ta có thể làm tốt hơn.
Để khắc phục điều này, chúng tôi có thể thêm một cuộc gọi đến overridePendingTransition():
finish();
startActivity(getIntent());
overridePendingTransition(0, 0);
Tạm biệt màn hình đen, nhưng trong trường hợp của tôi, tôi vẫn thấy một loại chuyển tiếp (hoạt hình mờ dần), trên nền màu lần này. Đó là bởi vì bạn đang hoàn thành phiên bản hiện tại của hoạt động trước khi hoạt động mới được tạo và hiển thị đầy đủ và màu ở giữa là giá trị của windowBackgroundthuộc tính chủ đề.
startActivity(getIntent());
finish();
Gọi finish() sau startActivity() sẽ sử dụng chuyển đổi mặc định giữa các hoạt động, thường với một hoạt hình trượt nhỏ. Nhưng quá trình chuyển đổi vẫn có thể nhìn thấy.
startActivity(getIntent());
finish();
overridePendingTransition(0, 0);
Đối với tôi, đây là giải pháp tốt nhất vì nó khởi động lại hoạt động mà không có bất kỳ sự chuyển đổi rõ ràng nào, giống như nếu không có gì xảy ra.
Nó có thể hữu ích nếu, ví dụ, trong ứng dụng của bạn, bạn đưa ra một cách để thay đổi ngôn ngữ hiển thị độc lập với ngôn ngữ của hệ thống. Trong trường hợp này, bất cứ khi nào người dùng thay đổi ngôn ngữ của ứng dụng, bạn có thể muốn khởi động lại hoạt động của mình mà không cần chuyển đổi, làm cho việc chuyển đổi ngôn ngữ trở nên tức thời.
Khi tôi cần khởi động lại một hoạt động, tôi sử dụng mã sau đây. Mặc dù nó không được khuyến khích.
Intent intent = getIntent();
finish();
startActivity(intent);
đối với API trước 11, bạn không thể sử dụng tái tạo (). Tôi đã giải quyết theo cách này:
Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();
và trong 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
}
Sau khi tìm kiếm triển khai bánh gừng cho recreate, tôi muốn sử dụng các mã sau (cho bánh gừng):
activity.mMainThread.mAppThread.scheduleRelaunchActivity(activity.mToken, null, null, 0, false, null);
Đối với các mã này, đó là từ việc thực hiện trong api cao hơn.
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 không có requestRelaunchActivity, tuy nhiên, từ diff, tôi đã tìm thấy điều này:
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);
}
Vì vậy, tôi nghĩ rằng tôi có thể sử dụng scheduleRelaunchActivitythay vì requestRelaunchActivity.
Và tôi đã viết chúng bằng phản ánh:
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);
}
}
Tôi đang sử dụng các mã này để chuyển ngược lại khung xposed.
Build.VERSION_CODES.ECLAIR_MR1(v7). Nó có thể hoạt động trên các phiên bản cũ là tốt.
Nếu đây là vấn đề của bạn, có lẽ bạn nên thực hiện một cách khác để thực hiện chế độ xem điền vào Hoạt động của mình. Thay vì chạy lại, onCreate()bạn nên làm cho nó onCreate()gọi phương thức điền của bạn với một số đối số. Khi dữ liệu thay đổi, phương thức điền sẽ được gọi với một đối số khác.
Cách tôi giải quyết là bằng cách sử dụng Fragment . Chúng tương thích ngược cho đến API 4 bằng cách sử dụng thư viện hỗ trợ.
Bạn tạo bố cục "trình bao bọc" với FrameLayout trong đó.
Thí dụ:
<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>
Sau đó, bạn tạo một FragmentActivity trong đó bạn có thể thay thế FrameLayout bất cứ lúc nào bạn muốn.
Thí dụ:
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();
}
Trong Fragment bạn thổi phồng / thay thế, bạn có thể sử dụng onStart và onCreateView giống như bạn Normaly sẽ sử dụng onCreate của một hoạt động.
Thí dụ:
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();
}
}
Tôi đã từng tạo một ứng dụng thử nghiệm tải lên, xóa và sau đó tải lại tệp cơ sở dữ liệu bằng cách sử dụng lưu trữ đám mây firebase. Để hiển thị dữ liệu trong cơ sở dữ liệu, đoạn mã sau là giải pháp duy nhất tôi tìm thấy. Không recreate()phải cũng không finish()làm việc trong trường hợp này.
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
System.exit(0);
tôi đã tìm ra cách tốt nhất để làm mới Fragment của bạn khi dữ liệu thay đổi
nếu bạn có nút "tìm kiếm", bạn phải khởi tạo danh sách ARRAY của mình bên trong nút
mSearchBtn.setOnClickListener (Chế độ xem mới.OnClickListener () {
@Override void công khai trênClick (Xem 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 );
}
Nếu bạn muốn truyền tham số cho onCreate () thì bạn phải tạo một ý định mới bằng cách thêm phụ và gọi StartActivity với nó. Đây là một ví dụ đơn giản mà tôi đã sử dụng theo cách này.
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);
}
Nếu bạn chỉ muốn làm lại quan điểm của mình, tôi đã có cùng một vấn đề. Trong onResumehàm thử đặt cái này:
mView = new AndroidPinballView(getApplication());
Điều này cũng là của tôi onCreate(), vì vậy việc đưa nó vào onResumelàm việc cho tôi :)