Gọi startActivity () từ bên ngoài bối cảnh Hoạt động


367

Tôi đã thực hiện một ListViewtrong ứng dụng Android của mình. Tôi liên kết với điều này ListViewbằng cách sử dụng một lớp con tùy chỉnh của ArrayAdapterlớp. Trong ArrayAdapter.getView(...)phương thức ghi đè , tôi gán một OnClickListener. Trong onClickphương thức của OnClickListener, tôi muốn khởi chạy một hoạt động mới. Tôi nhận được ngoại lệ:

Calling startActivity() from outside of an Activity  context requires the  
FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

Làm thế nào tôi có thể có được Contextrằng ListView(hiện tại Activity) đang làm việc theo?


1
Tôi nghĩ rằng câu trả lời của Alex phải là giải pháp 'được chấp nhận' cho vấn đề của bạn, vì nó khắc phục lỗi bạn đã đề cập theo cách chung chung hơn
devanshu_kaushik

10
Tôi thích rằng "Đây thực sự là những gì bạn muốn?" ... Tôi đã có một tin nhắn trước đó nói rằng "Bạn có chắc là bạn không quên hủy đăng ký một máy thu phát sóng ở đâu đó không?" TUYỆT VỜI! Ngả mũ trước bất cứ ai đặt tất cả những thông điệp nhỏ này vào để giúp chúng tôi tập trung.
Nerdy Bunz

1
Tôi đã gặp vấn đề này. khi tôi cập nhật targetSdkVersion thành 28.
illusionJJ

Câu trả lời:


574

Hoặc

  • lưu trữ đối tượng Ngữ cảnh thông qua hàm tạo trong bộ điều hợp của bạn hoặc
  • có được nó từ quan điểm của bạn.

Hoặc như là một phương sách cuối cùng,

  • thêm - cờ FLAG_ACTIVITY_NEW_TASK theo ý định của bạn:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Chỉnh sửa - tôi sẽ tránh đặt cờ vì nó sẽ cản trở luồng thông thường của ngăn xếp sự kiện và lịch sử.


6
Còn tính năng autoLink của TextView mà tôi không thể điều khiển Intent (và do đó là cờ) do hệ thống tạo ra thì sao?
Alex Semeniuk

75
Tôi đã nhận được ngoại lệ này khi tôi đã làm một cái gì đó như thế này context.startActivity(intent);tôi chỉ thay đổi contexttừ ApplicationContextđể Activityloại. Điều này đã khắc phục vấn đề.
Sufian

@AlexSemeniuk bao giờ tìm ra giải pháp?

@AlexSemeniuk - autoLink sẽ hoạt động miễn là bạn chuyển hoạt động dưới dạng bối cảnh sang bộ điều hợp
Georges

Tôi đã truyền đối tượng Context qua constructor nhưng nó không hoạt động. nhưng FLAG_ACTIVITY_NEW_TASK hoạt động rất tốt đối với tôi cảm ơn.
Hiren

100

Bạn có thể đạt được nó với addFlags thay vìsetFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Theo tài liệu này:

Thêm cờ bổ sung cho ý định (hoặc với giá trị cờ hiện có).


BIÊN TẬP

Hãy lưu ý nếu bạn đang sử dụng các cờ mà bạn thay đổi ngăn xếp lịch sử như câu trả lời của Alex Volovoy nói:

... tránh đặt cờ vì nó sẽ cản trở luồng thông thường của ngăn xếp sự kiện và lịch sử.


1
Tôi có một vấn đề rất tương tự. Bạn đã trải qua bất kỳ vấn đề với ngăn xếp lịch sử hoặc bất cứ điều gì khác như câu trả lời trên suggEST?
Einar Sundgren

1
Tôi không chắc chắn chính xác những gì bạn đang tìm kiếm nhưng bạn có thể bắt đầu một hoạt động mà không có lịch sử như thế: Ý định = Ý định mới (Intent.ACTION_VIEW, "http: \\ www.google.com")); ý định. addFlags (Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity (ý định);
Bruno Bieri

Tại sao nó không được khuyến nghị để thêmFlags ở đây? Làm thế nào quan trọng là nó can thiệp vào dòng chảy bình thường của sự kiện và ngăn xếp lịch sử?
Jason Krs

@JasonKrs bạn có thể sử dụng addFlags. Chỉ cần lưu ý rằng bạn có thể thay đổi ngăn xếp lịch sử tùy thuộc vào cờ bạn thêm. FLAG_ACTIVITY_NEW_TASK có thể được sử dụng trong tình huống này. Để biết thêm chi tiết, hãy đọc: developer.android.com/reference/android/content/
trộm


40

Nếu bạn gặp lỗi vì sử dụng trình tạo chọn như bên dưới:

Intent sharingIntent = new Intent(Intent.ACTION_VIEW);
sharingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sharingIntent.setData(Uri.parse("http://google.com"));
startActivity(Intent.createChooser(sharingIntent, "Open With"));

Đặt cờ để tạo trình chọn như thế này:

Intent sharingIntent = new Intent(Intent.ACTION_VIEW);
sharingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sharingIntent.setData(Uri.parse("http://google.com"));

Intent chooserIntent = Intent.createChooser(sharingIntent, "Open With");
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(chooserIntent);

4
Nó rất hữu ích. Chính xác ý định chọn nên có cờ này!
Mahdi

2
Đây là sự giải quyết chính xác và chính xác những gì phải làm, new_task trong ý định.chooser
Rafael Guimarães

15

Ngoài ra: nếu bạn hiển thị các liên kết trong listview trong đoạn , đừng tạo liên kết như thế này

adapter = new ListAdapter(getActivity().getApplicationContext(),mStrings);

thay vì gọi

adapter = new ListAdapter(getActivity(),mStrings);

bộ điều hợp hoạt động tốt trong cả hai trường hợp, nhưng các liên kết chỉ hoạt động trong cái cuối cùng.


@ user2676468: điều này đã giải quyết vấn đề autolink cho tôi.
Head Geek

Đây phải là một câu trả lời được chấp nhận, thay vì sử dụng cờ thì điều này tốt hơn !!
Gastón Saillén

@ GastónSaillén, tôi không sử dụng getApplicationContext()(ngoại trừ khởi tạo ứng dụng), nhưng đã bắt gặp ngoại lệ này. Vì vậy, các tình huống có thể khác nhau.
CoolMind

Đây là vấn đề của tôi, tôi đã sử dụng getApplicationContext () cho ngữ cảnh. Đặt thislàm bối cảnh hoạt động vì nó liên quan đến hoạt động hiện tại.
Brlja

14

Tôi nghĩ rằng có thể bạn đang triển khai OnClickListener không đúng chỗ - thông thường bạn chắc chắn nên triển khai OnItemClickListener trong Hoạt động của mình và đặt nó trên ListView thay vào đó, hoặc bạn sẽ gặp vấn đề với các sự kiện của mình ...


2
Bạn dẫn tôi đến giải pháp. Tôi cần sử dụng OnItemClickListener, được gán cho ListView. Dưới đây là một số liên kết cho bất cứ ai khác: developer.android.com/reference/android/widget/ khăn androidpeople.com / Cảm ơn sự giúp đỡ.
Sako73

Vui lòng cung cấp câu trả lời chung chung. Câu trả lời của Alex Volovoy dưới đây giải quyết vấn đề một cách chung chung.
devanshu_kaushik

Đối với hậu thế: Nếu bạn trực tiếp định nghĩa nó là setListener (Trình nghe mới) trên một thành phần yêu cầu Ngữ cảnh, bạn tạo một tham chiếu ngầm cho toàn bộ hoạt động sẽ rò rỉ bộ nhớ như bạn không tin. Điều này có thể được phá vỡ bằng cách tạo một trình lắng nghe lớp bên trong tĩnh hoặc bằng cách di chuyển người nghe sang một lớp riêng nếu nó cần có khả năng xử lý các đầu vào từ nhiều hơn một nguồn gốc.
G_V

9
CustomAdapter mAdapter = new CustomAdapter( getApplicationContext(), yourlist);

hoặc là

Context mContext = getAppliactionContext();
CustomAdapter mAdapter = new CustomAdapter( mContext, yourlist);

thay đổi bên dưới

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

8

Tại Android 28(Android P)startActivity

if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
        && (targetSdkVersion < Build.VERSION_CODES.N
                || targetSdkVersion >= Build.VERSION_CODES.P)
        && (options == null
                || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
    throw new AndroidRuntimeException(
            "Calling startActivity() from outside of an Activity "
                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                    + " Is this really what you want?");
}

Vì vậy, cách tốt nhất là thêm FLAG_ACTIVITY_NEW_TASK

Intent intent = new Intent(context, XXXActivity.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);

Điều này là cần thiết cho 28 thiết bị trở lên.
Md Mohsin

7

Xem, nếu bạn đang tạo một ý định trong một listiner trong một số phương thức

override onClick (View v).

sau đó gọi bối cảnh thông qua quan điểm này là tốt:

v.getContext ()

Thậm chí sẽ không cần SetFlags ...


Và tình huống sai là gì? v.getApplicationContext ()?
CoolMind

3

Đối với bất kỳ ai nhận được điều này trên Xamarin.Android (MonoDroid) ngay cả khi StartActivity được gọi từ hoạt động - đây thực sự là lỗi Xamarin với thời gian chạy ART mới, hãy xem https://ormszilla.xamarin.com/show_orms.cgi?id=17630


Vâng, bạn chỉ cần làm như những gì đã được mô tả ở trên, nhưng từ ngữ đã thay đổi ... ý định.SetFlags (ActivityFlags.NewTask);
Luke Alderton

3

Xây dựng câu trả lời của Alex Volovoy thêm một chút -

trong trường hợp bạn gặp vấn đề này với các đoạn, getActivity () hoạt động tốt để lấy bối cảnh

Trong các trường hợp khác:

Nếu bạn không muốn sử dụng-

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//not recommend

sau đó tạo một hàm như thế này trong InsideClass của bạn -

public void gettingContext(Context context){
    real_context = context;//where real_context is a global variable of type Context
}

Bây giờ, trong hoạt động chính của bạn khi bạn thực hiện một InsideClass mới, hãy gọi phương thức trên ngay lập tức sau khi bạn xác định InsideClass đưa ra bối cảnh của hoạt động làm đối số. Ngoài ra trong hoạt động chính của bạn làm cho một chức năng-

public void startNewActivity(final String activity_to_start) {
    if(activity_to_start.equals("ACTIVITY_KEY"));
    //ACTIVITY_KEY-is a custom key,just to
    //differentiate different activities
    Intent i = new Intent(MainActivity.this, ActivityToStartName.class);
    activity_context.startActivity(i);      
}//you can make a if-else ladder or use switch-case

bây giờ hãy quay lại InsideClass của bạn và để bắt đầu hoạt động mới, hãy làm một cái gì đó như thế này-

@Override
public void onClick(View v) {
........
case R.id.any_button:

            MainActivity mainAct = (MainActivity) real_context;             
            mainAct.startNewActivity("ACTIVITY_KEY");                   

        break;
    }
........
}

Bằng cách này, bạn sẽ có thể bắt đầu các hoạt động khác nhau được gọi từ các lớp ngoài khác nhau mà không làm rối cờ.

Lưu ý - Cố gắng không lưu trữ đối tượng bối cảnh thông qua hàm tạo cho đoạn (với bộ điều hợp, nó ổn). Một đoạn nên có một hàm tạo trống nếu không ứng dụng gặp sự cố trong một số trường hợp.

nhớ gọi

OutsideClass.gettingContext(Context context);

trong hàm onResume () là tốt.


3

Lỗi này xảy ra khi tính khởi động không biết đó là hoạt động của anh ta. Vì vậy, bạn phải thêm hoạt động trước khi startActivity ()

bạn phải đặt

context.startActivity(yourIntent);

Nếu bạn gọi startActivitytừ Fragment, một người gọi thường có thể là một mảnh, không phải là một hoạt động.
CoolMind

2

Theo tôi, tốt hơn là sử dụng phương pháp startActivity()chỉ trong mã của bạn Activity.class. Nếu bạn sử dụng nó trong lớp Adapterhoặc lớp khác, nó sẽ dẫn đến điều đó.


2

Tôi cũng gặp vấn đề tương tự. Kiểm tra tất cả các bối cảnh mà bạn đã vượt qua. Đối với ' liên kết ', nó cần Hoạt động bối cảnh chứ không phải bối cảnh Ứng dụng .

Đây là nơi bạn nên kiểm tra:

1.) Nếu bạn đã sử dụng LayoutInflater thì hãy kiểm tra xem bạn đã vượt qua bối cảnh nào.

2.) Nếu bạn đang sử dụng bất kỳ Bộ điều hợp nào, hãy kiểm tra bối cảnh bạn đã vượt qua.


2

Tôi đã từng gặp vấn đề tương tự. Vấn đề là với bối cảnh. Nếu bạn muốn mở bất kỳ liên kết nào (ví dụ: chia sẻ bất kỳ liên kết nào thông qua trình chọn), hãy chuyển ngữ cảnh hoạt động, không phải bối cảnh ứng dụng.

Đừng quên thêm myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)nếu bạn không hoạt động.


2

Sử dụng mã này trong Adapter_Activity của bạn và sử dụng context.startActivity(intent_Object)intent_Object.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Như thế này:

Intent n_act = new Intent(context, N_Activity.class);
n_act.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(n_act);

Nó hoạt động ....


1
Intent viewIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);    
viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);    
startActivity(viewIntent);   

tôi hy vọng điều này sẽ làm việc


1

Đối mặt với cùng một vấn đề sau đó thực hiện

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

và đã giải quyết vấn đề.

Có thể có một lý do khác liên quan đến bộ điều hợp xem danh sách.
Bạn có thể xem blog này , mô tả nó rất tốt.


Blog hữu ích, Cảm ơn bạn. :)
Rucha Bhatt Joshi

1

Sử dụng mã này. Hoạt động tốt cho tôi. Chia sẻ điều gì đó từ bên ngoài của một hoạt động:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");

// Append Text
String Text = "Your Text Here"

intent.putExtra(Intent.EXTRA_TEXT, Text);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Intent shareIntent = Intent.createChooser(intent,"Share . . . ");
shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
G.context.getApplicationContext().startActivity(shareIntent);

Thiết lập cờ làm rối lịch sử stacktrace
Ezio

1

Vì việc thêm cờ ảnh hưởng event_flowstack_historytốt hơn là chuyển 'bối cảnh ứng dụng' sang phi hoạt động từ nơi bạn cần gọi một lớp hoạt động theo cách sau:

"ActivityClassName.this" (Trong khi bạn chuyển ngữ cảnh theo cách này, nó sẽ chứa tất cả các chi tiết và thông tin mà bạn cần để gọi một Hoạt động từ một kịch bản không hoạt động)

Vì vậy, không cần phải thiết lập hoặc thêm cờ, điều này sẽ hoạt động tốt trong mọi trường hợp.


0
Intent i= new Intent(context, NextActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);

0

Nếu bạn đang gọi chia sẻ Ý định trong plugin Cordova, việc đặt Cờ sẽ không có ích. Thay vào đó hãy sử dụng cái này -

cordova.getActivity().startActivity(Intent.createChooser(shareIntent, "title"));

0

Tình huống của tôi hơi khác một chút, tôi đang thử nghiệm ứng dụng của mình bằng cách sử dụng Espressovà tôi phải khởi chạy Hoạt động của mình ActivityTestRuletừ thiết bị Context(không phải là ứng dụng đến từ một Activity).

fun intent(context: Context) = 
    Intent(context, HomeActivity::class.java)
        .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

Tôi đã phải thay đổi các cờ và thêm một orbitwise ( |bằng Java) vớiIntent.FLAG_ACTIVITY_NEW_TASK

Vì vậy, nó dẫn đến:

fun intent(context: Context) = 
    Intent(context, HomeActivity::class.java)
        .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)

0

Phiên bản Kotlin

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.