Im using a fragment that is supposed to display a webview. When I try to instantiate it from the class that uses it I get the following warning in my logcat.
02-21 23:26:46.843: W/System.err(32468): android.content.ActivityNotFoundException: Unable to find explicit activity class {get.scanner/get.scanner.WebFrag}; have you declared this activity in your AndroidManifest.xml?
Im just learning how to use fragments and Ive never tried declaring them in my manifest and I havent seen anywhere telling you to do so.
Heres the WebFrag class.
public class WebFrag extends Fragment{
private WebView viewer = null;
// if we weren't just using the compat library, we could use WebViewFragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
viewer = (WebView) inflater
.inflate(R.layout.webview, container, false);
WebSettings settings = viewer.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDefaultZoom(ZoomDensity.FAR);
return viewer;
}
#Override
public void onPause() {
if (viewer != null) {
viewer.onPause();
}
super.onPause();
}
#Override
public void onResume() {
super.onResume();
if (viewer != null) {
viewer.onResume();
}
}
public void updateUrl(String newUrl) {
if (viewer != null) {
viewer.loadUrl(newUrl);
}
}
}
EDIT: adding WebFrag as an activity to the manifest causes the following error
02-22 00:17:55.711: E/AndroidRuntime(2524): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{get.scanner/get.scanner.WebFrag}: java.lang.ClassCastException: get.scanner.WebFrag
EDIT: Heres the main fragmentactivity where Im trying to use my class
public class GetScannerActivity extends FragmentActivity {
private String mUrl = "http://www.yahoo.com/";
Button scanButton;
Button paint;
Button compTrans;
String yurl = "http://www.yahoo.com/";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
compTrans = (Button) findViewById(R.id.checkCurrentDeals);
compTrans.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
WebFrag viewer = (WebFrag) getSupportFragmentManager()
.findFragmentById(R.id.web_frag);
try{
if (viewer == null || !viewer.isInLayout()) {
Intent showContent = new Intent(getApplicationContext(),
WebFrag.class);
showContent.setData(Uri.parse(yurl));
try{
startActivity(showContent);
}catch(ActivityNotFoundException e){
e.printStackTrace();
}
} else {
viewer.updateUrl(yurl);
}
}catch(Exception e){
e.printStackTrace();
}
}
});
}
}
No don't add it to your manifest. You never need to add fragments to your manifest.
Do you create an Intent somewhere to start the WebActivity? How is it brought to the screen, that is probably where your problem lies.
EDIT
This is your problem:
Intent showContent = new Intent(getApplicationContext(),
WebFrag.class);
startActivity(showContent);
You can't start a Fragment as an Activity, you'll have to wrap the fragment in an Activity that extends FragmentActivity
if you want to go back from activity to Fragment try this
proToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Note: you must give an id to the Main layout of your activity e.g : searchVehicles
((ConstraintLayout) findViewById(R.id.searchVehicles)).removeAllViews();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragment_nearby_vehicles fnv = new fragment_nearby_vehicles();
fragmentTransaction.add(R.id.searchVehicles, fnv).commit();
}
});
Related
Currently I'm coding an android project using Android Studio 3.1.2 and SDK 19.
When I refactored almost my whole code and replaced a lot of getContext() calls with requireContext() and getActivity() with requireActivity() i came across the problem, that the app crashes already at the launcher activity. I know that there are several posts related to the same problem of getting IllegalStateException: Fragment myFragment not attached to a contextbut they're all very project-specific so it doesn't actually show me the step i missed to do. So i hereby show you my example of code and pray for a merciful programmer that enlightens me, what I have to do, to solve this problem just in the suiting way.
This is my SplashActivity (the launcher activity):
public class SplashActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
Fragment fragmentToDisplay = null;
if (!(getIntent().getBooleanExtra("isLaunch", true))) {
fragmentToDisplay = new LoginFragment();
} else {
if (savedInstanceState == null) {
fragmentToDisplay = new SplashFragment();
}
}
if (fragmentToDisplay.isAdded()) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragmentToDisplay).commit();
}
}
}
This is the SplashFragment which gets loaded initially:
public class SplashFragment extends RequestingFragment {
private Handler delayHandler = new Handler();
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.fragment_splash, container, false);
requestQueue = Volley.newRequestQueue(this.requireContext());
requestParams.add(SessionHandler.getAppInstanceID(this.getContext()));
startRequest(RequestOperation.SESSION_CHECK);
onSuccess(new JSONObject(), "");
return fragmentView;
}
#Override
public void onDestroy() {
super.onDestroy();
delayHandler.removeCallbacksAndMessages(null);
}
#Override
public void onSuccess(final JSONObject json, String parsingKey) {
delayHandler.postDelayed(new Runnable() {
#Override
public void run() {
//parsing stuff
}
}, 2000);
}
#Override
public void onError() {
showErrorDialog();
}
private void showErrorDialog() {
//show a horrifying dialog
}
}
I would be very thankful, if someone could explain to me, what in particular is causing the exception and how do I do it correctly. Thanks in advance.
Below is the MainActivity class that I'm using. The code checks to see if the phone is in landscape or portrait. If it's in portrait, it will show the main fragment in the main activity only (the main fragment is a static fragment in the main_activity.xml file). Then if a "Recipe" is clicked it will open a detail activity with its own fragment. If the phone is in landscape mode, it will show the main fragment and the detail fragment side by side. Everything works perfectly fine however when I follow the procedure below I get a white screen instead of the main activity:
Procedure:
Switch to landscape
Switch back to portrait
Choose an item and wait for the detail activity to open
Press back
Here instead of the main activity window I get a white screen
If I don't switch to landscape and just start with the portrait mode everything is fine. It seems like switching to landscape does something that causes the problem and I can't figure out what. Any tip on what's going on or where to look would be much appreciated.
public class MainActivity extends AppCompatActivity implements RecipesFragment.OnRecipeClickListener {
private String RECIPE_PARCEL_KEY;
private boolean mTwoPane;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RECIPE_PARCEL_KEY = getString(R.string.ParcelKey_RecipeParcel);
if (findViewById(R.id.linearLayoutTwoPane) != null) {
mTwoPane = true;
if (savedInstanceState == null) {
RecipeFragment recipeFragment = new RecipeFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.recipeFrameForTwoPane, recipeFragment)
.commit();
}
} else {
mTwoPane = false;
}
}
#Override
public void OnRecipeClick(Recipe recipe) {
if (mTwoPane) {
RecipeFragment recipeFragment = new RecipeFragment();
recipeFragment.setRecipe(recipe);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.recipeFrameForTwoPane, recipeFragment)
.commit();
} else {
Class destinationClass = DetailActivity.class;
Intent intentToStartDetailActivity = new Intent(this, destinationClass);
intentToStartDetailActivity.putExtra(RECIPE_PARCEL_KEY, recipe);
startActivity(intentToStartDetailActivity);
}
}
}
EDIT:
Adding RecipeFragment's code below:
public class RecipeFragment extends Fragment {
private Recipe mRecipe;
#BindView(R.id.tv_recipeName) TextView recipeNameTextView;
public RecipeFragment(){
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.recipe_fragment,container,false);
ButterKnife.bind(this,view);
if(mRecipe!=null) {
recipeNameTextView.setText(mRecipe.getName());
}else{
recipeNameTextView.setText(getString(R.string.messageSelectARecipe));
}
return view;
}
public void setRecipe(Recipe recipe){
mRecipe = recipe;
}
}
EDIT:
I followed #mt0s's advice and created different background colors for the fragments and activities and finally narrowed down the problem to a line in my recyclerview adapter code. My adapter code is below. Inside loadInBackground() on line URL url = new URL(getString(R.string.URL_RecipeJSON)); I get a Fragment RecipesFragment{96e9b6a} not attached to Activity exception. I don't understand why I'm getting this exception and what the best way to resolve this is. Have I placed the right code in the right fragment methods (ie OnCreate vs OnActivityCreated vs OnCreateView vs etc)?
public class RecipesFragment extends Fragment
implements RecipeAdapter.RecipeAdapterOnClickHandler,
LoaderManager.LoaderCallbacks<ArrayList<Recipe>> {
#BindView(R.id.rv_recipes) RecyclerView mRecyclerView;
private RecipeAdapter mRecipeAdapter;
private static final int LOADER_ID = 1000;
private static final String TAG = "RecipesFragment";
private OnRecipeClickListener mOnRecipeClickListener;
public RecipesFragment(){
}
public interface OnRecipeClickListener {
void OnRecipeClick(Recipe recipe);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.recipes_fragment, container, false);
ButterKnife.bind(this, view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mRecipeAdapter = new RecipeAdapter(this);
mRecyclerView.setAdapter(mRecipeAdapter);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void OnClick(Recipe recipe) {
mOnRecipeClickListener.OnRecipeClick(recipe);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
mOnRecipeClickListener = (OnRecipeClickListener) context;
} catch (ClassCastException e){
Log.e(TAG, "onAttach: Host activity class must implement OnRecipeClickListener.");
}
}
#Override
public Loader<ArrayList<Recipe>> onCreateLoader(int i, Bundle bundle) {
return new AsyncTaskLoader<ArrayList<Recipe>>(getActivity()) {
#Override
protected void onStartLoading() {
super.onStartLoading();
forceLoad();
}
#Override
public ArrayList<Recipe> loadInBackground() {
String response;
ArrayList<Recipe> recipes = null;
try {
URL url = new URL(getString(R.string.URL_RecipeJSON)); //***I get an exception here***
response = NetworkUtils.getResponseFromHttpUrl(url, getActivity());
recipes = RecipeJsonUtils.getRecipeFromJson(getActivity(), response);
} catch (Exception e) {
Log.e(TAG, "loadInBackground: " + e.getMessage());
}
return recipes;
}
};
}
#Override
public void onLoadFinished(Loader<ArrayList<Recipe>> loader, ArrayList<Recipe> recipes) {
mRecipeAdapter.setRecipeData(recipes);
}
#Override
public void onLoaderReset(Loader<ArrayList<Recipe>> loader) {
}
}
I finally figured out the problem and the solution. The problem is that onStartLoading() in the AsyncTaskLoader anonymous class in RecipesFragment class gets called every time the fragment is resumed whether the enclosing Loader is called or not. This causes the problem. I need to have control over when onStartLoading() is being called and I only want it to be called if and only if the enclosing Loader is being initialized or restarted. As such, I destroyed the loader in onPause() of the fragment and restarted it in onResume(). Hence, I added the following code to the RecipesFragment class:
#Override
public void onPause() {
super.onPause();
getLoaderManager().destroyLoader(LOADER_ID);
}
#Override
public void onResume() {
super.onResume();
getLoaderManager().restartLoader(LOADER_ID, null, this);
}
I also removed initLoader() from onCreate(). This way, every time the fragment is resumed (or created) onStartLoading() will be called. I tried this and it solves my problem.
When you switch from the landscape to portrait or the opposite the Android OS destroy your activity and recreate it again. this what probably trigger your problem
I have an android application in which I used webview fragment. From that fragment, i am going to take the current url by using the below code. But the problem is that I want to access String webUrl from the MainActivity.
How can I get it? What I actually planned to do is creating a favorite url according to the wish of the user from the fragment.
final String webUrl = view.getUrl();
Create Interface :
public interface HomeListener {
void onHomeClick(String url);
}
Now in Fragment:
HomeListener mCallback;
#Override
public void onAttach(Context con) {
super.onAttach(con);
try {
mCallback = (HomeListener) con;
} catch (ClassCastException e) {
e.printStackTrace();
}
}
#Override
public void onDetach() {
mCallback = null;
super.onDetach();
}
Now when url is get:
mCallback.onHomeClick(view.getUrl());
Last in Activity, implement HomeListener, and override method:
#Override
public void onHomeClick(String url) {
Log.e("urlFromFragment",url);
}
Sample Activity:
public class MainActivity extends AppCompatActivity
implements HomeListener {
String URL="";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onHomeClick(String url) {
URL=url;
Toast.makeText(getApplicationContext(), URL, Toast.LENGTH_LONG).show();
}
From Activity to Fragment:
In your fragment, use getActivity() method to access the object of Activity.
YourActivity activity = (YourActivity) getActivity();
activity.someString = "some_url";
webView.setUrl(activity.someString);
From Fragment to Activity:
FragmentManager fm = getSupportFragmentManager();
SampleFragment sampleFragment=(SampleFragment) fm.findFragmentById(R.id.fragment_id);
activity.someString = "some_url";
webView.setUrl(activity.someString);
Your fragment root view should have the same id:
SampleFragment.xml file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_id" >
<!-- [Your other layout views goes here] -->
</LinearLayout>
I know that onBackPressed() is a method in activity but, I want to use the functionality in fragments such that when back button is pressed, it gets redirected to another activity via Intent. Is there any solution to this ?
public class News_Events_fragment extends Fragment {
ProgressDialog pd;
ListView lv1;
SharedPreferences sharedPreferences = null;
int NotiCount;
TextView txt_title, txt_msg, textView;
Context context;
Intent intent ;
ArrayList<SliderMsgTitleModel> CurrentOfficersPastList;
NewsActivityAdapter pastAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
context = (Context) getActivity();
View rootView = inflater.inflate(R.layout.activity_news, container, false);
new AsyncTask<Void, Void, ArrayList<SliderMsgTitleModel>>() {
protected void onPreExecute() {
pd = new ProgressDialog(getActivity());
pd.setCancelable(true);
pd.setTitle("UPOA");
pd.setMessage("Please wait,loading the data...");
pd.show();
}
#Override
protected ArrayList<SliderMsgTitleModel> doInBackground(
Void... params) {
System.out.println("In Background");
CurrentOfficersPastList = new ArrayList<SliderMsgTitleModel>();
// display view for selected nav drawer item
ParseQuery<ParseObject> query = ParseQuery.getQuery("message");
query.whereEqualTo("featured_status", true);
// query.whereEqualTo("push_status", true);
query.orderByDescending("updatedAt");
query.selectKeys(Arrays.asList("title"));
query.selectKeys(Arrays.asList("message"));
try {
query.setCachePolicy(ParseQuery.CachePolicy.NETWORK_ELSE_CACHE);
List<ParseObject> results = query.find();
for (int i = 0; i < results.size(); i++) {
ParseObject object = results.get(i);
CurrentOfficersPastList.add(new SliderMsgTitleModel(
object.getString("title"), object
.getString("message")));
System.out.println("title is=="
+ object.getString("title") + "&& message is"
+ object.getString("message") + "size is"
+ CurrentOfficersPastList.size());
}
} catch (Exception e) {
e.getMessage();
}
pd.dismiss();
return CurrentOfficersPastList;
}
#SuppressWarnings("unchecked")
#Override
protected void onPostExecute(ArrayList<SliderMsgTitleModel> value) {
pd.dismiss();
/*Intent ent = new Intent(getActivity(), NewsActivity.class);
ent.putExtra("NEWSLIST", (ArrayList<SliderMsgTitleModel>) value);
startActivity(ent);
System.out.println("Value is" + value.size());*/
CurrentOfficersPastList = new ArrayList<SliderMsgTitleModel>();
CurrentOfficersPastList = value;
lv1 = (ListView) getActivity().findViewById(R.id.list_title);
pastAdapter = new NewsActivityAdapter(getActivity(), R.layout.activity_news_txt, CurrentOfficersPastList);
lv1.setAdapter(pastAdapter);
}
}.execute();
return rootView;
}
public void onBackPressed() {
// TODO Auto-generated method stub
//super.onBackPressed();
//Toast.makeText(getApplicationContext(), "click",2000).show();
String cameback="CameBack";
intent = new Intent(getActivity(),HomeActivity.class);
intent.putExtra("Comingback", cameback);
startActivity(intent);
}
}
You can interact with the fragment using a callback interface. In your activity add the following:
public class MyActivity extends Activity {
protected OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
#Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
#Override
protected void onDestroy() {
onBackPressedListener = null;
super.onDestroy();
}
}
In your fragment add the following:
public class MyFragment extends Fragment implements MyActivity.OnBackPressedListener {
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((MyActivity) getActivity()).setOnBackPressedListener(this);
}
#Override
public void doBack() {
//BackPressed in activity will call this;
}
}
Yes, There is. You should implement like this.
#Override
public void onBackPressed() {
if (fragment != null)
//user defined onBackPressed method. Not of Fragment.
fragment.onBackPressed();
} else {
//this will pass BackPress event to activity. If not called, it will
//prevent activity to get BackPress event.
super.onBackPressed();
}
}
Explanation
Check whether your fragment is initialized or not. If it is, then pass on back press event to your fragment.
If above condition not passed, just pass back press to your activity so that it will handle it.
Note
Here condition can be anything. I just take fragment initialization as an example. May be that can't be helped you. You need to define your own condition to pass it to fragment.
Edit
I created a sample application on GitHub to implement Back Stack of fragment .
Download Fragment Back Stack application.
Override onKeyDown instead of onBackPressed. Not necessarily . But this works for me
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
String cameback="CameBack";
intent = new Intent(getActivity(),HomeActivity.class);
intent.putExtra("Comingback", cameback);
startActivity(intent);
return true
}
return false;
}
You can implement onKeyListener for your fragment and call next activity within that.
I've never tried this. But i hope it may help
For Example
fragmentObject.getView().setOnKeyListener( new OnKeyListener()
{
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK )
{
//your code here
}
return false;
}
} );
You need to override onBackPressed method in fragment.
I have a problem with accessing activity's method from fragment.
Or anything int the activity from the fragment.
Here's fragment code:
public class MainFragment extends Fragment {
private MainActivity ma = (MainActivity) getActivity();
public SipAudioCall call = null;
public SipManager mSipManager = null;
public SipProfile mSipProfile = null;
public MainFragment() {
// TODO Auto-generated constructor stub
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Create a new TextView and set its text to the fragment's section
// number argument value.
LinearLayout mLinearLayout = (LinearLayout) inflater.inflate(R.layout.main_layout, container, false);
final Button callbtn = (Button) mLinearLayout.findViewById(R.id.callbtn);
final Button endbtn = (Button) mLinearLayout.findViewById(R.id.endbtn);
callbtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
callbtn.setVisibility(View.GONE);
endbtn.setVisibility(View.VISIBLE);
ma.initiateCall();
}
});
Maybe casting the activity is wrong?
Thx in advance
I'm guessing that the fragment is not attached to the activity when u call getActivity(). Try to initialize the activity reference in the fragment method onAttach().
So something like this:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
ma = (MainActivity) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " Not MainActivity class instance");
}
}