I have a program with 4 different tabs.
One of these tabs is an ActivityGroup which has a ListView in it. When I click on one of the list items, it switches to WebActivity:
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Intent intent = new Intent(TabActivity2.this, WebActivity.class);
Bundle b = new Bundle();
b.putString("URL", URLs[(int)id]);
b.putString("prevActivity", "TabActivity2");
intent.putExtras(b);
replaceContentView("web", intent);
}
});
}
public void replaceContentView(String id, Intent newIntent) {
View view = getLocalActivityManager().startActivity(id,newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) .getDecorView(); this.setContentView(view);
}
So now we're in the WebActivity class. Here's the code:
public class WebActivity extends ActivityGroup {
WebView mWebView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web);
Bundle b = getIntent().getExtras();
String URL = b.getString("URL");
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setPluginsEnabled(true);
mWebView.requestFocus();
mWebView.loadUrl(URL);
mWebView.setWebViewClient(new FirstTabWebViewClient());
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
Bundle b = getIntent().getExtras();
String retActivity = b.getString("prevActivity");
if (retActivity == "TabActivity2") {
Intent intent = new Intent(WebActivity.this, TabActivity2.class);
replaceContentView("list_webpages", intent);
return true;
}
return super.onKeyDown(keyCode, event);
}
public void replaceContentView(String id, Intent newIntent) {
View view = getLocalActivityManager().startActivity(id,newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) .getDecorView(); this.setContentView(view);
}
I had to implement my own onKeyDown because otherwise hitting the Back button resulted in closing the application rather than returning to the ListView.
So the StackOverflowError seems to be a structural problem in my program and I'm not sure how to go about resolving it. Any help would be appreciated.
I ended up using a FrameLayout in the same activity with both WebView and ListView and used visilibity to switch between them.
Related
I developed an android app which has a list view as its main gui, when the user click the item in the list, a webview will show basing on the content of the item.
It works fine, however when I clicked the back button in the android phone (or simulator), a blank white screen is shown, and the list view appears only after I click the back button again.
Can anyone help explain and help solve the problem?
Here is my WebviewActivity :
public class WebViewActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.active_item_detail);
if (savedInstanceState == null) {
WebViewFragment wvf = new WebViewFragment();
Intent i = this.getIntent();
wvf.init(i.getExtras());
getFragmentManager().beginTransaction().add(R.id.webview, wvf).commit();
}
}
}
and WebviewFragment:
public class WebViewFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.active_item_detail, container, false);
WebView wv = (WebView) v.findViewById(R.id.webview);
wv.getSettings().setJavaScriptEnabled(true);
//data is the content
if(data!=null) {
wv.loadData(data, "text/html", "UTF-8");
}
return v;
}
}
The layout file is like:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<WebView android:id="#+id/webview"
android:layout_height="match_parent"
android:layout_width="wrap_content"
tools:context="com.mycompany.myapp.WebViewFragment" />
</LinearLayout>
private void emulateShiftHeld(){
try
{
KeyEvent shiftPressEvent = new KeyEvent(0, 0,
KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0);
System.out.println(“shift press:::”+shiftPressEvent.dispatch(view));
}
catch (Exception e){
Log.e(“dd”, “Exception in emulateShiftHeld()”, e);
}
refer to this link https://harshdevchandel.wordpress.com/2013/05/13/android-webview-selection/
check if back is pressed finish this activity
How to handle back button in activity
If a part of your application is contained in a WebView, it may be appropriate for Back to traverse browser history.
#Override
public void onBackPressed() {
if (mWebView.canGoBack()) {
mWebView.goBack();
return;
}
// Otherwise defer to system default behavior.
super.onBackPressed();
}
It is documented in the official docs here
http://developer.android.com/training/implementing-navigation/temporal.html#back-webviews
Try this way:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (wv.canGoBack()) {
wv.goBack();
} else {
finish();
}
return true;
}
}
return super.onKeyDown(keyCode, event);
}
Also, you try with:
#Override
public void onBackPressed() {
Fragment webviewFragment = getSupportFragmentManager().findFragmentByTag("webview");
if (webview instanceof WebViewFragment) {
boolean goback = ((WebViewFragment)webview).canGoBack();
if (!goback)
super.onBackPressed();
}
}
Thanks to all. Unfortunately I couldn't make it after trying all suggestions above. I resolved the problem by creating an intent inside the onBackPressed() hook, and start the initial activity.
I have literally looked at every question to do with getting the back button to work with a WebView inside a fragment and cannot seem to make it work in my case.
I am currently trying to get blackbelt's answer to work, but my app just closes once I have pressed the back button.
Any help would be great, thanks.
public class MainActivity extends BaseActivity {
private Fragment FragmentArchietecture = new FragmentShakira();
WebView webview;
private Fragment mContent;
public MainActivity() {
super(R.string.app_name);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
mContent = getSupportFragmentManager().getFragment(
savedInstanceState, "mContent");
if (mContent == null)
mContent = new FragmentShakira();
setContentView(R.layout.content_frame);
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, FragmentArchietecture, "webby")
.commit();
setBehindContentView(R.layout.menu_frame);
getSupportFragmentManager().beginTransaction()
.replace(R.id.menu_frame, new RandomList()).commit();
ActionBar bar = getSupportActionBar();
bar.setTitle(R.string.app_name);
getSlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
setSlidingActionBarEnabled(true);
}
#Override
public void onBackPressed() {
Fragment webview = getSupportFragmentManager().findFragmentByTag(
"webby");
if (webview instanceof FragmentShakira) {
boolean goback = ((FragmentShakira) webview).canGoBack();
if (!goback)
super.onBackPressed();
}
}
}
Fragment:
public class FragmentShakira extends SherlockFragment {
static WebView webview;
String TAG = "webby";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater
.inflate(R.layout.fragmentwebview, container, false);
WebView webview = (WebView) view.findViewById(R.id.webView1);
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(new WebViewClient());
webview.loadUrl("https://www.google.co.uk/");
return view;
}
public boolean canGoBack() {
return webview != null && webview.canGoBack();
}
}
it should work. dont forget to pass on the message to the fragment to goback if it can
ie
if (!goback)
super.onBackPressed();
else
((FragmentShakira) view).goBack();
use the code posted by Nawrez here.
and here how you can implement it in your code.
in the onCreateView() method add this :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater
.inflate(R.layout.fragmentwebview, container, false);
WebView webview = (WebView) view.findViewById(R.id.webView1);
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(new WebViewClient());
webview.loadUrl("https://www.google.co.uk/");
//handles the back navigation in the fragment
webView.canGoBack();
webView.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK
&& event.getAction() == MotionEvent.ACTION_UP
&& webView.canGoBack()) {
webView.goBack();
return true;
}
return false;
}
}); // until here
return view;
}
In Kotlin you can handle this easily by adding setOnKeyListener to your WebView.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val myWebView: WebView = view.findViewById(R.id.your_webView)
myWebView.webViewClient = WebViewClient()
myWebView.loadUrl("https://www.google.com/")
myWebView.setOnKeyListener { v, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) {
myWebView.goBack() // Navigate back to previous web page if there is one
nested_scroll.scrollTo(0, 0) // Scroll webview back to top of previous page
}
true
}
}
I have a webview inside fragment and I want it to be controlled by the navigation history whenever I press the back button.
In my case, when I press the back button I leave the webview, but I want that on pressing the button I will return to the state that is stored in the navigation history (from before leaving the webview).
Any solution please?
I tried with onKey but it does not resolve my problem. Here my code:
public class FragmentAll extends Fragment implements
DialogInterface.OnCancelListener, DialogInterface.OnDismissListener,
OnDownloaExpodTerminated {
public static Fragment newInstance(Context context) {
FragmentAll f = new FragmentAll();
return f;
}
private WebView myWebView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
(((MainActivity) getActivity()) ).setActionBarTitle("Store");
myWebView = (WebView) v.findViewById(R.id.webView1);
setWebview();
v.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View arg0, int arg1, KeyEvent arg2) {
// TODO Auto-generated method stub
if (arg1 == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) {
myWebView.goBack();
return true;
}
return false;
}
});
return v;
}
...
}
You can try it
#Override
public void onBackPressed() {
if (mWebView.canGoBack()) {
mWebView.goBack();
return;
}
// Otherwise defer to system default behavior.
super.onBackPressed();
}
You will have to make a method inside your Fragment class:
public void goBackWebview(){
myWebview.goBack();
}
Now, go to the Activity class to which this fragment is attached and override the onBackPressed():
#Override
public void onBackPressed() {
//if webview has history
myFragment.goBackWebView();
}
you need to manage list of links is loaded in your webview.
you can get the url like this
web_des2.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
HitTestResult hitTestResult = web_des2.getHitTestResult();
if (hitTestResult != null) {
String url = hitTestResult.getExtra();
if (url != null && url.startsWith("http://")) {
yourUrlList.add(url);
web_des2.loadUrl(url);
}
}
return true;
}
return false;
}
});
you can check onBackPress if your list does not empty then get url form list and load it into webview and remove from the list.
you can use Stack to store url so become easy you can use pop() and push() function directly. if like than +1
I have 3 Tabs
Tab1,Tab2,Tab3
public Class TabLayout extends TabActivity {
Tab1,Tab2,Tab3
}
Each Tab Contains one ListActivity
that means
Tab1>>>Tab1ListActivity(List with Image and Text)
Tab2>>>Tab2ListActivity(List with Image and Text)
Tab3>>>Tab3ListActivity(List with Image and Text)
and if i click on any listitem from(Tab1ListActivity,Tab2ListActivity etc.......)
I'm forwarding to one More Activity(Tab1ListItemActivity,Tab2ListItemActivity etc......)
But My Actual Requirement is if suppose I'm clicking backbutton from Tab2ListItemActivity ,then I
Should be able to forward to Tab2ListActivity
But,if i write my code like this
public class Tab2ListItemActivity extends Activity
{
//on Back Button Pressed
Intent intent=new Intent(Tab2ListItemActivity.this,TabLayout.class);
startActivity(intent);
Tab2ListItemActivity.this.finish();
}
when i execute above code I'm able to forward to my TabLayout(Tab1ListActivity) but not to Tab2ListActivity?,Beacuse
Tab2ListItemActivity related to Tab2ListActivity
Could any one help?
Why not leave the default behaviour (do not override onBackPressed)? It will restore to previous Activity.
Solution 1:
Do not finish the TabLayout Activity. And Leave the default implementation of back button in Tab2ListItemActivity activity.
Solution 2 (the hard, the force way):
Add the intent extra on what tab it should open.
Intent intent = new Intent(Tab2ListItemActivity.this, TabLayout.class);
intent.putExtra(TabLayout.EXTRA_TAB_TO_OPEN, 1);
startActivity(intent);
Tab2ListItemActivity.this.finish();
in TabLayout Activity
#Override
protected void onPostCreate(Bundle state) {
super.onPostCreate(state);
handleTab(getIntent());
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleTab(intent);
}
private void handleTab(Intent intent) {
// init tabs
final int tab = intent.getIntExtra(EXTRA_TAB_TO_OPEN, -1);
if (tab != -1) {
getTabHost().setCurrentTab(tab);
}
}
Why are you trying to override the Back button ? I mean, just let the default behaviour take place and then pressing the back button would take you to the previous activity.
If you really want to do it your way, then you would need to set the tab id before launching the TabLayout activity and inside the onCreate() of TabLayout you would need to check the tab id and launch the corresponding ListActivity. The tab id is 1 by default and that is why it is taking you to the Tab1ListActivity always.
I am getting same issue but i solve using this solution.
TabSample.class
public class TabSample extends TabActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TabHost tabHost = getTabHost();
tabHost.addTab(tabHost.newTabSpec("tab1")
.setIndicator("OPT")
.setContent(new Intent(this, TabGroup1Activity.class)));
tabHost.addTab(tabHost.newTabSpec("tab2")
.setIndicator("EDIT")
.setContent(new Intent(this, TabGroup2Activity.class)));
tabHost.setCurrentTab(1);
}
}
TabGroup1Activity.class
public class TabGroup1Activity extends TabGroupActivity{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startChildActivity("OptionsActivity", new Intent(this,OptionsActivity.class));
}
}
OptionsActivity.class
public class OptionsActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.optionspage);
Button back = (Button) findViewById(R.id.BackButton1);
Button next = (Button) findViewById(R.id.NextButton1);
OnTouchListener backListener = new OnTouchListener() {
public boolean onTouch (View v, MotionEvent event) {
if (event.getAction()==MotionEvent.ACTION_UP){
finish();
}
return false;
}
};
OnTouchListener nextListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction()==MotionEvent.ACTION_UP){
Intent edit = new Intent(getParent(), EditActivity.class);
TabGroupActivity parentActivity = (TabGroupActivity)getParent();
parentActivity.startChildActivity("EditActivity", edit);
return true;
}
return false;
}
};
back.setOnTouchListener(backListener);
next.setOnTouchListener(nextListener);
}
}
finally over TabGroupActivity.class which save all the stat instance.
public class TabGroupActivity extends ActivityGroup {
private ArrayList<String> mIdList;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mIdList == null) mIdList = new ArrayList<String>();
}
#Override
public void finishFromChild(Activity child) {
LocalActivityManager manager = getLocalActivityManager();
int index = mIdList.size()-1;
if (index < 1) {
finish();
return;
}
manager.destroyActivity(mIdList.get(index), true);
mIdList.remove(index); index--;
String lastId = mIdList.get(index);
Intent lastIntent = manager.getActivity(lastId).getIntent();
Window newWindow = manager.startActivity(lastId, lastIntent);
setContentView(newWindow.getDecorView());
}
public void startChildActivity(String Id, Intent intent) {
Window window = getLocalActivityManager().startActivity(Id,intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
if (window != null) {
mIdList.add(Id);
setContentView(window.getDecorView());
}
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//preventing default implementation previous to android.os.Build.VERSION_CODES.ECLAIR
return true;
}
return super.onKeyDown(keyCode, event);
}
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackPressed();
return true;
}
return super.onKeyUp(keyCode, event);
}
public void onBackPressed() {
int length = mIdList.size();
if ( length > 1) {
Activity current = getLocalActivityManager().getActivity(mIdList.get(length-1));
current.finish();
}
}
}
This is awesome solution you can try this.and make appropriate manifest entry.
I created a small Android 4 application with fragments.
In all these fragments I have some webviews and if I click a different fragment I want a different website to load.
I have right now TabOne.java ; TabTwo.java ; TabThree.java and so on.
I was also wondering : Can I make this application without needing a TabOne.java, TabTwo.java and so on; only from MainActivity.java? I mean, to have a single WebView, and when clicking different Tabs, this WebView to load different Url (according to the selected Tab).
If this is not possible, can you tell me what is wrong here (TabOne.java) :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.tabone, container, false);
myWebView = (WebView) view.findViewById(R.id.webview);
myWebView.getSettings().setPluginsEnabled(true);
myWebView.loadUrl("http://m.stirileprotv.ro");
myWebView = new WebView(getActivity());
myWebView.setOnKeyListener(new OnKeyListener(){
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack())
{
myWebView.goBack();
return true;
}
return false;
}
});
myWebView.setWebViewClient(new WebViewClient() {
#Override public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().equals("m.stirileprotv.ro")) {
myWebView.loadUrl(url);
return true;
}
else
{
return false;
}
}
});
return view;
}
This is what i did.
In the fragment, declare the webview reference as static-
public static WebView mWebView;
public WebFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.fragment_web, container, false);
mWebView = (WebView) v.findViewById(R.id.webview);
mWebView.loadUrl("https://google.com");
// Enable Javascript
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
// Force links and redirects to open in the WebView instead of in a browser
mWebView.setWebViewClient(new WebViewClient());
return v;
}
public boolean canGoBack() {
return mWebView.canGoBack();
}
public void goBack() {
mWebView.goBack();
}
}
Now, In the parent activity -
#Override
public void onBackPressed() {
WebFragment fragment = new WebFragment();
if (fragment.mWebView.canGoBack()) {
fragment.mWebView.goBack();
} else {
super.onBackPressed();
}
}
What I did was implement it within the activity and then have a public static so:
In the main activity:
public class MainActivity extends FragmentActivity{
public static WebView myWebView;
...
#Override
public void onBackPressed() {
if (getSupportFragmentManager().findFragmentByTag("yourtag") != null) {
if(myWebView.canGoBack())
myWebView.goBack();
else {
super.onBackPressed();
}
}
else
super.onBackPressed();
}
...
}
and to reference it within the fragment:
MainActivity.myWebView = (WebView) getView().findViewById(R.id.webview);
and be sure when you create the fragment you add a tag
transaction.replace(R.id.yourfragid, newfragment, "yourtag");