I am working on text-view.in that text-view display html hyperlink.
when i click on hyper-linked text then i want to get that text.
as per above image if i click on hyperlink, then i want to display text.
Your answer would be appreciated
The LinkEnableTextView class is like this:
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Context;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
public class LinkEnabledTextView extends TextView
{
// The String Containing the Text that we have to gather links from private SpannableString linkableText;
// Populating and gathering all the links that are present in the Text
private ArrayList<Hyperlink> listOfLinks;
// A Listener Class for generally sending the Clicks to the one which requires it
TextLinkClickListener mListener;
// Pattern for gathering #usernames from the Text
Pattern screenNamePattern = Pattern.compile('(#[a-zA-Z0-9_]+)');
// Pattern for gathering #hasttags from the Text
Pattern hashTagsPattern = Pattern.compile('(#[a-zA-Z0-9_-]+)');
// Pattern for gathering http:// links from the Text
Pattern hyperLinksPattern = Pattern.compile('([Hh][tT][tT][pP][sS]?:\\/\\/[^ ,'\'>\\]\\)]*[^\\. ,'\'>\\]\\)])');
public LinkEnabledTextView(Context context, AttributeSet attrs)
{
super(context, attrs);
listOfLinks = new ArrayList<Hyperlink>();
}
public void gatherLinksForText(String text)
{
linkableText = new SpannableString(text);
//gatherLinks basically collects the Links depending upon the Pattern that we supply
//and add the links to the ArrayList of the links
gatherLinks(listOfLinks, linkableText, screenNamePattern);
gatherLinks(listOfLinks, linkableText, hashTagsPattern);
gatherLinks(listOfLinks, linkableText, hyperLinksPattern);
for(int i = 0; i< listOfLinks.size(); i++)
{
Hyperlink linkSpec = listOfLinks.get(i);
android.util.Log.v('listOfLinks :: ' + linkSpec.textSpan, 'listOfLinks :: ' + linkSpec.textSpan);
// this process here makes the Clickable Links from the text
linkableText.setSpan(linkSpec.span, linkSpec.start, linkSpec.end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
// sets the text for the TextView with enabled links
setText(linkableText);
}
// sets the Listener for later click propagation purpose
public void setOnTextLinkClickListener(TextLinkClickListener newListener)
{
mListener = newListener;
}
//The Method mainly performs the Regex Comparison for the Pattern and adds them to
//listOfLinks array list
private final void gatherLinks(ArrayList<Hyperlink> links,
Spannable s, Pattern pattern)
{
// Matcher matching the pattern
Matcher m = pattern.matcher(s);
while (m.find())
{
int start = m.start();
int end = m.end();
// Hyperlink is basically used like a structure for storing the information about
// where the link was found.
Hyperlink spec = new Hyperlink();
spec.textSpan = s.subSequence(start, end);
spec.span = new InternalURLSpan(spec.textSpan.toString());
spec.start = start;
spec.end = end;
links.add(spec);
}
}
// This is class which gives us the clicks on the links which we then can use.
public class InternalURLSpan extends ClickableSpan
{
private String clickedSpan;
public InternalURLSpan (String clickedString)
{
clickedSpan = clickedString;
}
#Override
public void onClick(View textView)
{
mListener.onTextLinkClick(textView, clickedSpan);
}
}
// Class for storing the information about the Link Location
class Hyperlink
{
CharSequence textSpan;
InternalURLSpan span;
int start;
int end;
}
Now, having this you require just another interface for propagating the clicks to the place you require to handle them in my case I implemented the interface in my Activity and simple wrote a Log Command there.
The TextLinkClickListener interface is like this:
import android.view.View;
public interface TextLinkClickListener
{
// This method is called when the TextLink is clicked from LinkEnabledTextView
public void onTextLinkClick(View textView, String clickedString)
}
After doing all this you just require to create an Activity using the Custom LinkEnabledTextView and check the things out yourself. There are a few things that you must do while creating a object of the Custom LinkEnabledTextView those are mentioned and described in the Code of the Activity below:
import android.text.method.MovementMethod;
import com.umundoinc.Tvider.Component.LinkEnabledTextView.LinkEnabledTextView;
import com.umundoinc.Tvider.Component.LinkEnabledTextView.TextLinkClickListener;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.view.View;
//Here the Activity is implementing the TextLinkClickListener the one we have created
//the Clicks over the Links are forwarded over here from the LinkEnabledTextView
public class TextViewActivity extends Activity implements TextLinkClickListener
{
private LinkEnabledTextView check;
protected void onCreate(Bundle savedInstance)
{
super.onCreate(savedInstance);
String text = "This is a #test of regular expressions with http://example.com/ links as used in #twitter for performing various operations based on the links this handles multiple links like http://this_is_fun.com/ and #Awesomess and #Cool";
check = new LinkEnabledTextView(this, null);
check.setOnTextLinkClickListener(this);
check.gatherLinksForText(text);
check.setTextColor(Color.WHITE);
check.setLinkTextColor(Color.GREEN);
MovementMethod m = check.getMovementMethod();
if ((m == null) || !(m instanceof LinkMovementMethod)) {
if (check.getLinksClickable()) {
check.setMovementMethod(LinkMovementMethod.getInstance());
}
}
setContentView(check);
}
public void onTextLinkClick(View textView, String clickedString)
{
android.util.Log.v('Hyperlink clicked is :: ' + clickedString, 'Hyperlink clicked is :: ' + clickedString);
}
Hope it will help you!!
Please try my Implementation:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
........
textView mTvTxt = findViewById(R.id.tv_txt_view);
final String hyperlink = "Vasant jetava";
SpannableString spannableString = makeLinkSpan(hyperlink , new View.OnClickListener() {
#Override
public void onClick(View v) {
showDialog(hyperlink)
}
});
mTvTxt.setText(getString("hello whats up man....");
mTvTxt.append(spannableString);
makeLinksFocusable(mTvTxt);
}
private SpannableString makeLinkSpan(CharSequence text, View.OnClickListener listener) {
SpannableString link = new SpannableString(text);
link.setSpan(new ClickableString(listener), 0, text.length(),
SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
return link;
private void makeLinksFocusable(TextView tv) {
MovementMethod m = tv.getMovementMethod();
if ((m == null) || !(m instanceof LinkMovementMethod)) {
if (tv.getLinksClickable()) {
tv.setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
private static class ClickableString extends ClickableSpan {
private View.OnClickListener mListener;
public ClickableString(View.OnClickListener listener) {
mListener = listener;
}
#Override
public void onClick(View v) {
mListener.onClick(v);
}
}
private void showDialog(String message){
AlertDialog alertDialog = new AlertDialog.Builder(<YourActivityName>this).create(); //Read Update
alertDialog.setTitle("Alert Dialog");
alertDialog.setMessage(message);
alertDialog.setButton("Continue..", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// here you can add functions
}
});
alertDialog.show();
}
Related
I made a simple quiz on Android Studio which contains 3+ questions. How to make the questions become random without duplicated. This app does not use a database. I'm new to programming so I don't know what to do about this
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlertDialog; import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
TextView totalQuestionsTextView;
TextView questionTextView;
Button ansA,ansB,ansC,ansD;
Button submitBtn;
int score=0;
int totalQuestions = QuestionAnswer.question.length;
int currentQuestionIndex = 0;
String selectedAnswer = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
totalQuestionsTextView = findViewById(R.id.total_questions);
questionTextView = findViewById(R.id.question);
ansA = findViewById(R.id.ans_A);
ansB = findViewById(R.id.ans_B);
ansC = findViewById(R.id.ans_C);
ansD = findViewById(R.id.ans_D);
submitBtn = findViewById(R.id.submbit_btn);
ansA.setOnClickListener(this);
ansB.setOnClickListener(this);
ansC.setOnClickListener(this);
ansD.setOnClickListener(this);
submitBtn.setOnClickListener(this);
totalQuestionsTextView.setText("Total Questions : "+totalQuestions);
loadNewQuestion();
}
#Override
public void onClick(View view) {
ansA.setBackgroundColor(Color.WHITE);
ansB.setBackgroundColor(Color.WHITE);
ansC.setBackgroundColor(Color.WHITE);
ansD.setBackgroundColor(Color.WHITE);
Button clickedButton = (Button) view;
if(clickedButton.getId()==R.id.submbit_btn){
currentQuestionIndex++;
loadNewQuestion();
}else{
//choices button clicked
selectedAnswer = clickedButton.getText().toString();
clickedButton.setBackgroundColor(Color.MAGENTA);
}
}
void loadNewQuestion(){
if(currentQuestionIndex == totalQuestions){
finishQuiz();
return;
}
questionTextView.setText(QuestionAnswer.question[currentQuestionIndex]);
ansA.setText(QuestionAnswer.choices[currentQuestionIndex][0]);
ansB.setText(QuestionAnswer.choices[currentQuestionIndex][1]);
ansC.setText(QuestionAnswer.choices[currentQuestionIndex][2]);
ansD.setText(QuestionAnswer.choices[currentQuestionIndex][3]);
}
void finishQuiz(){
String passStatus = "";
if (score > totalQuestions*0.60){
passStatus = "Passes";
}else{
passStatus = "Failed";
}
new AlertDialog.Builder(this)
.setTitle(passStatus)
.setMessage("Score is "+score+" out of "+ totalQuestions)
.setPositiveButton("Restart",(dialogInterface, i) -> restartQuiz())
.setCancelable(false)
.show();
}
void restartQuiz(){
score = 0;
currentQuestionIndex = 0;
loadNewQuestion();
}
QuestionAnswer.java
import java.util.Arrays; import java.util.List; import java.util.Random;
public class QuestionAnswer {
public static String[] question = {
"Which company own the android?",
"Which one is not the programming language?",
"Where are you watching this video"
};
public static String choices[][] = {
{"Google", "Apple", "Nokia", "Samsung"},
{"Java", "Kotlin", "Notepad", "Python"},
{"Facebook", "Whatsapp", "Instagram", "Youtube"},
};
public static String correctAnswers[] = {
"Google",
"Notepad",
"Youtube"
};
}
how can i add shuffle.collection or random to make my app show random question instead
You need to find out about Random class first in Java. Thereafter, you will create a random number using Random class in onClick function, then set a question's index to your Random number
I have made a custom URL span to use the chrome custom tab to open a link. The links are getting displayed correctly, I use the Html.fromHtml() function.
In the activity I use this for the TextView:
content_txt_view = (TextView)findViewById(R.id.textView_news);
content_txt_view.setTransformationMethod(new LinkTransformationMethod());
content_txt_view.setMovementMethod(LinkMovementMethod.getInstance());
The linkstransformation class looks like this:
public class LinkTransformationMethod implements TransformationMethod {
#Override
public CharSequence getTransformation(CharSequence source, View view) {
if (view instanceof TextView) {
TextView textView = (TextView) view;
// Linkify.addLinks(textView, Linkify.WEB_URLS);
if (textView.getText() == null || !(textView.getText() instanceof Spannable)) {
return source;
}
Spannable text= new SpannableString(textView.getText());
URLSpan[] spans = text.getSpans(0, textView.length(), URLSpan.class);
for (int i = spans.length - 1; i >= 0; i--) {
URLSpan oldSpan = spans[i];
int start = text.getSpanStart(oldSpan);
int end = text.getSpanEnd(oldSpan);
String url = oldSpan.getURL();
text.removeSpan(oldSpan);
text.setSpan(new CustomTabsURLSpan(url), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return text;
}
return source;
}
and the custom url span:
public class CustomTabsURLSpan extends URLSpan {
private Context context;
public CustomTabsURLSpan(String url) {
super(url);
Log.d("SensibleUrlSpan", "1");
}
public CustomTabsURLSpan(Parcel src) {
super(src);
Log.d("SensibleUrlSpan", "2");
}
#Override
public void onClick(View widget) {
Log.d("SensibleUrlSpan", "3");
String url = getURL();
Toast toast = Toast.makeText(context, "well done! you click ", Toast.LENGTH_SHORT);
toast.show();
// String url = "http://www.google.com";
}
}
I would have expected that when I click on the link, I will get the toast message...But it seems the OnClick method is not called at all.
The classes below implement the desired behaviour:
CustomClickURLSpan.java
import android.text.style.URLSpan;
import android.view.View;
public class CustomClickURLSpan extends URLSpan {
private OnClickListener mOnClickListener;
public CustomClickURLSpan(String url) {
super(url);
}
public void setOnClickListener(OnClickListener onClickListener) {
mOnClickListener = onClickListener;
}
#Override
public void onClick(View widget) {
if (mOnClickListener == null) {
super.onClick(widget);
} else {
mOnClickListener.onClick(widget, getURL());
}
}
public interface OnClickListener {
void onClick(View view, String url);
}
}
CustomTabsOnClickListener.java
import android.app.Activity;
import android.net.Uri;
import android.support.customtabs.CustomTabsIntent;
import android.view.View;
import java.lang.ref.WeakReference;
public class CustomTabsOnClickListener implements CustomClickURLSpan.OnClickListener {
private WeakReference<Activity> mActivityWeakReference;
private WeakReference<CustomTabActivityHelper> mCustomTabActivityHelperWeakReference;
public CustomTabsOnClickListener(Activity hostActivity,
CustomTabActivityHelper customTabActivityHelper) {
mActivityWeakReference = new WeakReference<>(hostActivity);
mCustomTabActivityHelperWeakReference = new WeakReference<>(customTabActivityHelper);
}
#Override
public void onClick(View view, String url) {
Activity activity = mActivityWeakReference.get();
CustomTabActivityHelper customTabActivityHelper =
mCustomTabActivityHelperWeakReference.get();
if (activity != null && customTabActivityHelper != null) {
CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder(null)
.build();
customTabsIntent.intent.setPackage(
CustomTabsHelper.getPackageNameToUse(view.getContext()));
customTabsIntent.launchUrl(activity, Uri.parse(url));
}
}
}
A Utility class with the linkifyUrl methods that creates Spans for the URLs
import android.text.Spannable;
import android.text.Spanned;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Util {
private static final Pattern URL_PATTERN = Pattern.compile("((http|https|rstp):\\/\\/\\S*)");
public static void linkifyUrl(
Spannable spannable, CustomClickURLSpan.OnClickListener onClickListener) {
Matcher m = URL_PATTERN.matcher(spannable);
while (m.find()) {
String url = spannable.toString().substring(m.start(), m.end());
CustomClickURLSpan urlSpan = new CustomClickURLSpan(url);
urlSpan.setOnClickListener(onClickListener);
spannable.setSpan(urlSpan, m.start(), m.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
Finally, invoke those classes to linkify the text:
TextView content = (TextView)findViewById(R.id.content);
Spannable spannable = new SpannableString(post.getText());
Util.linkifyUrl(spannable, new CustomTabsOnClickListener(this, mCustomTabActivityHelper));
content.setText(spannable);
content.setMovementMethod(LinkMovementMethod.getInstance());
The helper classes used are available on the Github Demo: CustomTabsHelper and CustomTabsActivityHelper
I have 3 classes, I wish to use the autocomplete text box to show user certain data (aka cities) from a web service (rest api). I've used this implementation on various features of my own application, but for some reason, there's a synchronization problem within the textchangedlistener...
CitiesArrayAdapter.java (to show a different view, in my case the "city, state"):
package com.android.lzgo.adapters;
import java.util.ArrayList;
import java.util.List;
import com.android.lzgo.activities.LiftSearchActivity;
import com.android.lzgo.activities.R;
import com.android.lzgo.models.City;
import com.android.lzgo.models.Lift;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class CitiesArrayAdapter extends ArrayAdapter<City> {
private static final String TAG = CitiesArrayAdapter.class.getName();
private final ArrayList<City> cities;
private int viewResourceId;
public CitiesArrayAdapter(Context context, int textViewResourceId, ArrayList<City> results) {
super(context, textViewResourceId, results);
this.cities = results;
this.viewResourceId = textViewResourceId;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// assign the view we are converting to a local variable
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(viewResourceId, null);
}
City i = cities.get(position);
Log.d(TAG, "Here is my value: " + i);
if (i != null) {
TextView tt = (TextView) v.findViewById(android.R.id.text1);
Log.d(TAG, "Name: " + i.getName() + ", " + i.getProvince_name());
if (tt != null){
tt.setText("Name: " + i.getName() + ", " + i.getProvince_name());
}
}
// the view must be returned to our activity
return v;
}
}
CitiesResponderFragment.java (this is how I get my values from my rest api):
package com.android.lzgo.fragment;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import com.android.lzgo.activities.LiftSearchActivity;
import com.android.lzgo.definitions.Constants;
import com.android.lzgo.models.City;
import com.android.lzgo.service.LzgoService;
import com.google.gson.Gson;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.Toast;
public class CitiesResponderFragment extends LzgoResponderFragment {
private static String TAG = CitiesResponderFragment.class.getName();
private List<City> mCities;
ArrayAdapter<City> adapter;
private String enteredCharacters;
LiftSearchActivity activity;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
activity = (LiftSearchActivity) getActivity();
// This gets called each time our Activity has finished creating itself.
getCities();
}
private void getCities() {
if (mCities == null && activity != null) {
Intent intent = new Intent(activity, LzgoService.class);
intent.setData(Uri.parse(Constants.REST_CITIES_AUTOCOMPLETE));
Bundle params = new Bundle();
params.putString("search", getenteredCharacters());
intent.putExtra(LzgoService.EXTRA_HTTP_VERB, LzgoService.GET);
intent.putExtra(LzgoService.EXTRA_PARAMS, params);
intent.putExtra(LzgoService.EXTRA_RESULT_RECEIVER, getResultReceiver());
// Here we send our Intent to our RESTService.
activity.startService(intent);
}
}
#Override
public void onRESTResult(int code, String result) {
Log.e(TAG, Integer.toString(code));
Log.e(TAG, result);
// Check to see if we got an HTTP 200 code and have some data.
if (code == 200 && result != null) {
mCities = getCitiessFromJson(result);
adapter = activity.getArrayAdapter();
adapter.clear();
for( City city : mCities){
//debugging
Log.d(TAG, "City : " + city.getName());
adapter.add(city);
adapter.notifyDataSetChanged();
}
getCities();
}
else {
Activity activity = getActivity();
if (activity != null && code == 400) {
Toast.makeText(activity, result, Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(activity, "Failed to load lzgo data. Check your internet settings.", Toast.LENGTH_SHORT).show();
}
}
private List<City> getCitiessFromJson(String json) {
ArrayList<City> cityList = new ArrayList<City>();
Gson gson = new Gson();
try {
JSONObject citiesWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray cities = citiesWrapper.getJSONArray("cities");
for (int i = 0; i < cities.length(); i++) {
//JSONObject city = cities.getJSONObject(i);
String jsonCity = cities.getString(i);
City city = gson.fromJson( jsonCity, City.class );
//Log.e(TAG, "Hurray! Parsed json:" + city.getString("name"));
//cityList.add(city.getString("name"));
cityList.add(city);
}
}
catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
return cityList;
}
public String getenteredCharacters() {
return enteredCharacters;
}
public void setenteredCharacters(String characters) {
this.enteredCharacters = characters;
}
}
LiftSearchActivity.java (My FragmentActivity):
package com.android.lzgo.activities;
import java.util.ArrayList;
import com.android.lzgo.adapters.CitiesArrayAdapter;
import com.android.lzgo.fragment.CitiesResponderFragment;
import com.android.lzgo.models.City;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AutoCompleteTextView;
import android.widget.DatePicker;
public class LiftSearchActivity extends FragmentActivity{
private static final String TAG = LiftSearchActivity.class.getName();
// User lift input
private AutoCompleteTextView autoCityFrom;
private AutoCompleteTextView autoCityTo;
private DatePicker date;
private CitiesArrayAdapter adapter;
private ArrayList<City> mCities ;
int year , month , day;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lift_search);
mCities = new ArrayList<City>();
adapter = new CitiesArrayAdapter(this,
android.R.layout.simple_dropdown_item_1line, mCities);
autoCityFrom = (AutoCompleteTextView) findViewById(R.id.cityFrom);
autoCityTo = (AutoCompleteTextView) findViewById(R.id.cityTo);
adapter.setNotifyOnChange(true);
autoCityFrom.setAdapter(adapter);
autoCityTo.setAdapter(adapter);
autoCityFrom.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
// no need to do anything
}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (((AutoCompleteTextView) autoCityFrom).isPerformingCompletion()) {
return;
}
if (charSequence.length() < 2) {
return;
}
String query = charSequence.toString();
getCities(query);
}
public void afterTextChanged(Editable editable) {
}
});
autoCityTo.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
// no need to do anything
}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (((AutoCompleteTextView) autoCityTo).isPerformingCompletion()) {
return;
}
if (charSequence.length() < 2) {
return;
}
String query = charSequence.toString();
getCities(query);
}
public void afterTextChanged(Editable editable) {
}
});
date = (DatePicker) findViewById(R.id.dpResult);
}
public void searchLifts(View view) {
Intent intent = new Intent(this, LiftsResultActivity.class);
//While autocomplete doesn't work hardcore value...
intent.putExtra("from", Integer.toString(9357)); // Sherbrooke
intent.putExtra("to", Integer.toString(6193)); // Montreal
intent.putExtra("date", Integer.toString(date.getMonth()+1) + "-" + Integer.toString(date.getDayOfMonth()) + "-" + Integer.toString(date.getYear()));
startActivity(intent);
}
public void getCities(String query) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
CitiesResponderFragment responder = (CitiesResponderFragment) fm.findFragmentByTag("RESTResponder");
responder = new CitiesResponderFragment();
responder.setenteredCharacters(query);
ft.add(responder, "RESTResponder");
ft.commit();
}
public CitiesArrayAdapter getArrayAdapter() {
// TODO Auto-generated method stub
return adapter;
}
}
I get the correct result and all. But my service doesn't seem to populate my array adapter in my activity, when I try to show my first "city", my adapter contains nothing. I wonder if I have to put a notifydatasetchanged (I tried, but doesn't work). I'm kind of confuse... any pointers?
While debugging the application I noticed that the properties mObjects of
the ArrayAdapter is cleared even if the associated ArrayList has
elements, and then properties mOriginalValues is filled with the
Strings loaded the first time.
Without seeing the full code base(+ data), I don't know if someone can pin point the reason for your code's failure. But I think the problem comes more from the way you setup the whole auto complete related code than some obvious line error. Below I'll try to address some of this issues(from my point of view) :
First of all, in the TextWatcher from LiftSearchActivity you call the getCities() method which adds, each time the user modifies the auto complete text, a Fragment to the Activity. I really doubt you want this, you should probably look at having only one Fragment in the Activity on which to call a refresh(or update) method, passing it the new filter text. If the user rotates the phone those fragments will also be recreated because of the configuration change.
Second, in the CitiesResponderFragment class you call the fragment's getCities() method(if you don't have any data) in onActivityCreated which start an update service(?!). Now related to the first point, you could end up doing a lot of unnecessary queries, for example if the user enter 4 characters and then decides to delete one of the characters as it was incorrect you'll end up with 5 added fragments, from which 3 will make the service start/query for data.
And last, I'm not sure if you understand how the AutoCompleteTextView works under the hood. In order to provide the drop down with the suggestions the AutoCompleteTextView widget will filter its adapter(adapter.getFilter()) and show as suggestions the items that match the filter. I don't know if you set some threshold on the AutoCompleteTextView but initially the auto complete will be empty for the first 3 characters entered as you start with an empty list of items when you first setup the Activity. The first two characters will not show anything because you start with an empty list and you don't add any new fragments(charSequence.length() < 2). The third character will most likely also not show anything, because the overhead of creating the fragment, starting the service and fetching the data will almost for sure be greater then doing the work of the adapter filtering(which will still see the initially empty list). I don't know if you tested, but from this fourth character the adapter should have some elements in it and the filtering should show something. Clearing the adapter and adding new data in it willl only make that data available to the next character entered in the AutoCompleteTextView.
The proper way of doing the filtering would be to further extend your adapter and implement the getFilter() method to return your own Filter implementation which would query the data store for new filtered items. The filtering method runs on a background thread, with a little work I think you could implement your current logic with the Service and the REST callback.
See example of the REST API Autocomplete : https://subversion.assembla.com/svn/rockitsearch-android/
Although it is part of my service, it can also serve as an example of how you can integrate your own REST API in AutoCompleteTextView control. If you are interested in autocomplete 3rd party service, here you go : www.rockitsearch.com
I am getting the text from API, can be random, but It contains expressions like on FB
#xyz hi, #abc how u??
1. I need to create a regex expression starts with #, ends with space.
2. Linkify it to open the user activity like XYZ or ABC.
Please help me, I have tried to create a class like,
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.text.style.ClickableSpan;
import android.view.View;
import android.widget.TextView;
public class ClickSpan extends ClickableSpan {
private OnClickListener mListener;
public ClickSpan(OnClickListener listener) {
mListener = listener;
}
#Override
public void onClick(View widget) {
if (mListener != null) mListener.onClick();
}
public interface OnClickListener {
void onClick();
}
/**
* To clickify a textview
* #param view
* #param clickableText
* #param listener
*/
public static void clickify(TextView view, final String clickableText,
final ClickSpan.OnClickListener listener) {
CharSequence text = view.getText();
String string = text.toString();
ClickSpan span = new ClickSpan(listener);
int start = string.indexOf(clickableText);
int end = start + clickableText.length();
if (start == -1) return;
if (text instanceof Spannable) {
((Spannable)text).setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
SpannableString s = SpannableString.valueOf(text);
s.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
view.setText(s);
}
MovementMethod m = view.getMovementMethod();
if ((m == null) || !(m instanceof LinkMovementMethod)) {
view.setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
And call like,
clickify(textView, clickText,new ClickSpan.OnClickListener()
{
#Override
public void onClick() {
startActivity here..
}
});
I need help as to how I can get this to work on my activity creating a loop of regex.
public class ClickableURLSpan extends URLSpan {
public ClickableURLSpan(String url) {
super(url);
}
#Override
public void onClick(View widget) {
String clickedText = getURL();
// START your activity here
}
}
Now you can linkify your text:
CharSequence input = "#xyz hi, #abc how u??!";
SpannableStringBuilder builder = new SpannableStringBuilder(input);
Pattern pattern = Pattern.compile("#.*?\\s");
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
int start = matcher.start();
int end = matcher.end();
String text = input.subSequence(start, end).toString();
ClickableURLSpan url = new ClickableURLSpan(text);
builder.setSpan(url, start, end, 0);
}
textView.setText(builder);
textView.setMovementMethod(LinkMovementMethod.getInstance());
I am new to Android development and currently learning to design for a basic calculator app. I have already self designed the layout, but sourced Main Activity codes from different websites for the operations for 0 to 9, +, -, *, / and after incorporation, they work fine.
However, I do want to further modify the MainActivity with decimal point function.
While integer can be shown properly to the screen using "current = current * 10 + number", eg 53 = 5*10+3;
I am thinking applying the same approach for decimal point with a loop function, the idea like this:
1. current = current + remaining if dot button is pressed
2. create an integer i, i increases by 1 once any numerial button is clicked
3. so that when e.g. input 5.3, i =1, it will = 5 + 3/(10^i) = 5.3
4. 5.3 loop to here, then when e.g. input as 5.39, now i=2, it will = 5.3 + 9/(10^i) = 5.39
QUESTION >>
*Yet...really...I am so fresh that I do not know how to design the coding for the decimal button, would there be anyone can suggest the code?* first ignore the following addons where errors to be detected (such as delete the second dot if the dot is input twice or more, adding 0 in front of . if say, .5 is input)
The button id is as follows, and once clicked to refer to DecimalClickEvent
Button b_decimal = (Button) findViewById(R.id.decimal);
b_decimal.setOnClickListener(new DecimalClickEvent(???));}
Many many thanks in advance!! The codes are attached below for reference and your comments:
=========================MainActivity.java=====================================
package com.trial.newcalculator;
import java.io.Serializable;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
#SuppressLint("ParserError")
public class MainActivity extends Activity {
State s;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
s = new State();
int[] opNumbers = new int[] {
R.id.zero,
R.id.one,
R.id.two,
R.id.three,
R.id.four,
R.id.five,
R.id.six,
R.id.seven,
R.id.eight,
R.id.nine,
};
final TextView textView = (TextView) findViewById(R.id.ansEditText);
for (int i = 0; i < 10;i++){
final Button button = (Button) findViewById(opNumbers[i]);
button.setOnClickListener(new NumberClickEvent(textView,s,i));
}
int[] opButtons = new int[] { R.id.add, R.id.subtract, R.id.multiply, R.id.divide };
State.Operation[] states = new State.Operation[] {
State.Operation.PLUS,
State.Operation.MINUS,
State.Operation.MULTIPLY,
State.Operation.DIVIDE};
for(int i = 0; i < opButtons.length;i++){
Button b_op = (Button) findViewById(opButtons[i]);
b_op.setOnClickListener(new OperationClickEvent(textView, s, states[i]));
}
// Memory functions
int[] memButtons = new int[] { R.id.MC, R.id.MR, R.id.Mdeduct, R.id.Mplus};
State.Operation[] mstates = new State.Operation[] {
State.Operation.MEMORYCLEAR,
State.Operation.MEMORYCALL,
State.Operation.MEMORYMINUS,
State.Operation.MEMORYPLUS};
for(int i = 0; i < memButtons.length;i++){
Button b_mem = (Button) findViewById(memButtons[i]);
b_mem.setOnClickListener(new OperationClickEvent(textView, s, states[i]));
}
// Memory functions
//decimal
// Button b_decimal = (Button) findViewById(R.id.decimal);
// b_decimal.setOnClickListener(new DecimalClickEvent(textView, s, "."));
//decimal
Button b_eq = (Button) findViewById(R.id.equal);
b_eq.setOnClickListener(new EqualClickEvent(textView, s));
Button b_op = (Button) findViewById(R.id.ac);
b_op.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
s.clear();
textView.setText(s.getDisplay());
}
});
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putSerializable("STATE", s);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
Serializable serializable = savedInstanceState.getSerializable("STATE");
if(serializable!= null){
s = (State) serializable;
}
}
public void onPause(){
super.onPause();
}
}
===============================State.java==================================
package com.trial.newcalculator;
import java.io.Serializable;
import android.text.Editable;
import android.widget.TextView;
public class State implements Serializable {
private static final long serialVersionUID = -1231231231231233L;
public TextView output;
public enum Operation {
PLUS,
MINUS,
MULTIPLY,
DIVIDE,
MEMORYPLUS,
MEMORYMINUS,
MEMORYCALL,
MEMORYCLEAR,
}
public enum IOState{
INPUTTING,
DISPLAY_RESULT,
}
private Double accu = null;
private double current = 0;
private double memory = 0;
private Operation currentOp = null;
private IOState currentState = IOState.INPUTTING;
public Operation getCurrentOp() {
return currentOp;
}
public void setCurrentOp(Operation currentOp) {
if (currentState == IOState.INPUTTING){
if (accu != null && this.currentOp != null ){calculateResult();
}
else{accu = Double.valueOf(current);current = 0;
}
}
this.currentOp = currentOp;
if (currentState == IOState.INPUTTING){
currentState = IOState.DISPLAY_RESULT;
}
}
private void calculateResult() {
double res = accu.doubleValue();
switch (currentOp) {
case PLUS:
res += current;
break;
case MINUS:
res -= current;
break;
case MULTIPLY:
res *= current;
break;
case DIVIDE:
res /= current;
break;
case MEMORYPLUS:
memory += current;
break;
case MEMORYMINUS:
memory -= current;
break;
case MEMORYCLEAR:
memory = 0;
break;
case MEMORYCALL:
current = memory;
break;
}
accu = Double.valueOf(res);
current = 0;
}
public void number(int number) {
if (currentState == IOState.INPUTTING){
current = current *10 + number;
}
else if(currentState == IOState.DISPLAY_RESULT){
currentState = IOState.INPUTTING;
current = number;
}
}
public String getDisplay() {
String res;
Double d = getCurrentDisplayValue();
double doubleValue = d.doubleValue();
int intVal = (int)doubleValue;
if (intVal == doubleValue){
res = Integer.toString(intVal);
}
else{
res = d.toString();
}
return res;
}
private Double getCurrentDisplayValue() {
Double d = accu;
if (currentState == IOState.INPUTTING){
d = Double.valueOf(current);
}
return d;
}
public void clear() {
accu = null;
currentState = IOState.INPUTTING;
currentOp = null;
current = 0;
}
public void equal() {
if (accu == null || currentOp == null){
return;
}
calculateResult();
currentState = IOState.DISPLAY_RESULT;
currentOp = null;
current = getCurrentDisplayValue();
}
}
====================OperationClickEvent.java===============================
package com.trial.newcalculator;
import com.trial.newcalculator.State.Operation;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
final class OperationClickEvent implements OnClickListener {
private State s;
private TextView textView;
private Operation op;
public OperationClickEvent(TextView textView, State s, State.Operation op) {
super();
this.op = op;
this.s = s;
this.textView = textView;
}
public void onClick(View v) {
s.setCurrentOp(op);
textView.setText(s.getDisplay());
}
}
=================EqualClickEvent.java=======================================
package com.trial.newcalculator;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
final class EqualClickEvent implements OnClickListener {
private State s;
private TextView textView;
public EqualClickEvent(TextView textView, State s) {
super();
this.s = s;
this.textView = textView;
}
public void onClick(View v) {
s.equal();
textView.setText(s.getDisplay());
}
}
======================NumberClickEvent.java==================================
package com.trial.newcalculator;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
final class NumberClickEvent implements OnClickListener {
private int number;
private State s;
private TextView textView;
public NumberClickEvent(TextView textView, State s, int number) {
super();
this.number = number;
this.s = s;
this.textView = textView;
}
public void onClick(View v) {
s.number(number);
textView.setText(s.getDisplay());
}
}
Instead of creating new classes for negative click event and doublezeroclickevent, i suggest you to get their id's and do the proper functionality when the particular button is clicked .
Each OnClickListener can be a default anonymous class, that will be triggered only by one button.
So no need to name them "NegativeClickEvent", "DoublezeroClickEvent", etc.
You can keep a boolean variable if the "." was pressed, and accept another one only if not.
If you want a usable calculator, you need a "backspace" button as well. So note that the dot may be deleted. (need to keep track of its placement).
For the leading 0, you can use a simple "if dot was pressed first, insert 0.".
There are many ways to implement what you want, but to keep it simple, just handle the cases you need to handle.
Other ways to implement this may include Double.parseDouble(s) with catch (NumberFormatException e) on each key pressed, or using a double as your buffer, and using the buttons to perform mathematical operations on it directly (such as multiply by 10 and adding the new digit on each button press) - this will ensure input validity without the need to parse String, but it's more complicated to implement.