I'm not sure exactly how this can be corrected but I'm getting an error stating: VISIBLE cannot be resolved to a variable. Any suggestions are greatly appreciated. Thus far I've looked over:
http://developer.android.com/reference/android/view/View.html#setVisibility(int)
but I do not understand exactly how this can be implemented in this case.
SOURCE:
public class MainActivity extends Activity {
private TextView textView;
private String response;
public interface Callback {
void onModifiedTextView(String value);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.TextView01);
textView.setVisibility(VISIBLE);
}
public void onModifiedTextView(final String title) {
runOnUiThread(new Runnable() {
public void run() {
textView.setText(title);
textView.invalidate(); // not even necessary
}
});
}
public class DownloadWebPageTask extends AsyncTask<String, Void, String> {
public DownloadWebPageTask(MainActivity mainActivity) {
this.callback = mainActivity;
}
private MainActivity callback;
private String title;
public DownloadWebPageTask() {
// TODO Auto-generated constructor stub
}
public DownloadWebPageTask(TextView textView) {
// TODO Auto-generated constructor stub
}
#Override
protected String doInBackground(String... urls) {
String response = title;
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
Document doc = Jsoup.connect("http://google.com")
.userAgent("Mozilla")
.get();
// get page title
String title = doc.title();
System.out.println("title : " + title);
// get all links
Elements links = doc.select("a[href]");
for (Element link : links) {
// get the value from href attribute
System.out.println("\nlink : " + link.attr("href"));
System.out.println("text : " + link.text());
}
} catch (IOException e) {
e.printStackTrace();
}
}
// callback.onModifiedTextView(response);
return response;
}
#Override
protected void onPostExecute(final String title) {
callback.onModifiedTextView(title);
callback.onModifiedTextView(response);
}
}
public void onClick(View view) {
DownloadWebPageTask task = new DownloadWebPageTask(this);
task.execute(new String[] { "http://www.google.com" });
}
}
VISIBLE is an integer value in the View class. You should change this to View.VISIBLE instead of just VISIBLE, unless you are inside a custom view.
In addtion to #kcoppock answer. You can use
you can use this import:
import static android.view.View.VISIBLE;
or just
textView.setVisibility(View.VISIBLE);
VISIBLE is defined as static final int in the View class.
Related
I got a AsyncTask:
package e.marco.swimcommit;
import android.os.AsyncTask;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
public class News extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... strings) {
final StringBuilder builder = new StringBuilder();
final StringBuilder builder2 = new StringBuilder();
{
try {
Document doc = Jsoup.connect("http://www.schwimmclub-schwandorf.de/index.php/8-home/56-infos-neuigkeiten").get();
String title = doc.title();
Elements links = doc.select("h2");
Elements links2 = doc.select("h3");
builder.append(title).append("\n");
for (Element link : links) {
builder.append(link.text()).append("$");
}
for (Element link : links2) {
builder2.append(link.text()).append("$");
}
} catch (IOException e) {
e.printStackTrace();
}
}
String text = builder.toString() + "%" + builder2.toString();
return text;
}
}
and a onResume Methode in my MainActivity which set the returned text in a textview
#Override
protected void onResume()
{
super.onResume();
try {
eins.setText(new News().execute().get());
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
But if i start the App it shows me a white Screen until onResume Methode get the text and set it to the Textview. How is it possible to load the App show all other Elements like Buttons Background and so on without the delayed start? So that the Textview is blank until the onResume Methode get the Information and set it?
Edit: Without blocking the UI
AsyncTask is used to perform background operations and publish results on the UI thread. In your case you should put eins.setText into onPostExecute of AsyncTask.
Another problem is because the AsyncTask is a separate class so you need to define an interface to pass result back to MainActivity.
News
public class News extends AsyncTask<String, Void, String> {
private WeakReference<OnNewsListener> mOnNewsListener;
public void setOnNewsListener(OnNewsListener listener) {
mOnNewsListener = new WeakReference<>(listener);
}
#Override
protected String doInBackground(String... strings) {
final StringBuilder builder = new StringBuilder();
final StringBuilder builder2 = new StringBuilder();
{
try {
Document doc = Jsoup.connect("http://www.schwimmclub-schwandorf.de/index.php/8-home/56-infos-neuigkeiten").get();
String title = doc.title();
Elements links = doc.select("h2");
Elements links2 = doc.select("h3");
builder.append(title).append("\n");
for (Element link : links) {
builder.append(link.text()).append("$");
}
for (Element link : links2) {
builder2.append(link.text()).append("$");
}
} catch (IOException e) {
e.printStackTrace();
}
}
String text = builder.toString() + "%" + builder2.toString();
return text;
}
#Override
protected void onPostExecute(String text) {
if (mOnNewsListener != null) {
if (mOnNewsListener.get() != null) {
mOnNewsListener.get().onNews(text);
}
}
}
public interface OnNewsListener {
void onNews(String text);
}
}
MainActivity
public class MainActivity extends AppCompatActivity implements News.OnNewsListener{
TextView eins;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
eins = findViewById(R.id.eins);
}
#Override
protected void onResume() {
super.onResume();
News news = new News();
news.setOnNewsListener(this);
news.execute();
}
#Override
public void onNews(String text) {
eins.setText(text);
}
}
As suggested by pz64, set the text in onPostExecute() method and call the AsyncTask() without calling get() method. get() method on AsyncTask makes task synchronous and also affects your UI.
public class News extends AsyncTask<String, Void, String> {
#override
protected void onPreExecute(){
//initiate your loading views
}
#Override
protected String doInBackground(String... strings) {
final StringBuilder builder = new StringBuilder();
final StringBuilder builder2 = new StringBuilder();
{
try {
Document doc = Jsoup.connect("http://www.schwimmclub-schwandorf.de/index.php/8-home/56-infos-neuigkeiten").get();
String title = doc.title();
Elements links = doc.select("h2");
Elements links2 = doc.select("h3");
builder.append(title).append("\n");
for (Element link : links) {
builder.append(link.text()).append("$");
}
for (Element link : links2) {
builder2.append(link.text()).append("$");
}
} catch (IOException e) {
e.printStackTrace();
}
}
String text = builder.toString() + "%" + builder2.toString();
return text;
}
#override
protected void onPostExecute(String response){
//dispose loading views
if(response != null){
eins.setText(response);
}else{
//could not load
}
}
}
Call:
#Override
protected void onResume()
{
super.onResume();
new News().execute(); //do not call get method
}
You can call asyncTask in oncreate method.
And set the result in onProgressUpdate method.
#Override
protected void onProgressUpdate(String... text) {
eins.setText.setText(text);
}
public class ConnectionTest extends AsyncTask<Void, Void, Void> {
String connection;
String loginFormUrl = "https://intranet.tam.ch/";
#Override
protected Void doInBackground(Void... voids) {
try{
Connection.Response loginForm = Jsoup.connect(loginFormUrl).method(Connection.Method.GET)
.execute();
connection = loginForm.toString();
System.out.print(title);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
My Activity should just display the connection in a TextView. I have also tried making a Thread and running it in the new Thread but it also won't work.
Here is my Activity
public class Test extends AppCompatActivity {
TextView textView;
ConnectionTest connectionTest = new ConnectionTest();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
connectionTest.getWebsite();
textView = findViewById(R.id.sdweedew);
textView.setText(connectionTest.connection);
}
}
Change your activity code like this,
I've used a TextView to display the status of the connection.
public class MainActivity extends AppCompatActivity {
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
textView = findViewById(R.id.sdweedew);
new ConnectionTest().execute();
}
class ConnectionTest extends AsyncTask<Void, Void, String> {
String loginFormUrl = "https://intranet.tam.ch/";
#Override
protected String doInBackground(Void... voids) {
try {
Connection.Response loginForm = Jsoup.connect(loginFormUrl).method(Connection.Method.GET)
.execute();
return loginForm.statusMessage();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
if (textView != null) {
textView.setText(s);
}
super.onPostExecute(s);
}
}
}
And remember to add Internet permission in manifest file.
<uses-permission android:name="android.permission.INTERNET" />
please check this code
private void getWebsite() {
new Thread(new Runnable() {
#Override
public void run() {
final StringBuilder builder = new StringBuilder();
try {
Document doc = Jsoup.connect("https://intranet.tam.ch/").get();
String title = doc.title();
Elements links = doc.select("a[href]");
builder.append(title).append("\n");
for (Element link : links) {
builder.append("\n").append("Link : ").append(link.attr("href"))
.append("\n").append("Text : ").append(link.text());
}
} catch (IOException e) {
builder.append("Error : ").append(e.getMessage()).append("\n");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(builder.toString());
}
});
}
}).start();
}
I want to use return a value from AsyncTask class by using interface. Problem is that my following code is work fine in Activity but not in fragment class.
I got ClassCastException like this:
java.lang.ClassCastException: com.demo.HomeActivity cannot be cast to com.demo.helper.OnTaskCompleteListener
at com.demo.util.JSONParseAsync.<init>(JSONParseAsync.java:33)
at com.demo.fragment.PersonalDetailFragment.loadProfileAction(PersonalDetailFragment.java:93)
at com.demo.fragment.PersonalDetailFragment.onCreate(PersonalDetailFragment.java:81)
at android.support.v4.app.Fragment.performCreate(Fragment.java:1942)
Interface class:
public interface OnTaskCompleteListener {
void onTaskComplete(JSONObject jsonObject);
}
PersonalDetailFragment class:
public class PersonalDetailFragment extends Fragment implements OnTaskCompleteListener {
private View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_personal_detail, container,
false);
loadProfileAction();
return view;
}
private void loadProfileAction() {
SessionPreference preference = new SessionPreference(getActivity());
try {
String encodedUrl = URLEncoder.encode(preference.getSessionId(), "UTF-8")
+ ","
+ URLEncoder.encode(Constants.URL_TOKEN, "UTF-8");
// URL base64Encode
String processUrl = Base64.encodeToString(encodedUrl.getBytes("UTF-8"), Base64.DEFAULT);
JSONParseAsync parseAsync = new JSONParseAsync(getContext()); // also try getActivity()
parseAsync.execute((URLConstants.GET_USER_DETAIL_URL+processUrl).trim());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onTaskComplete(JSONObject jsonObject) {
try {
boolean status = jsonObject.getBoolean(URLConstants.TAG_STATUS);
Log.e(Constants.DEBUG_TAG, "Status:- " + status);
if (status == true) {
JSONArray dataarray = jsonObject.getJSONArray(URLConstants.TAG_DATA);
JSONObject data = dataarray.getJSONObject(0);
fillProfileData(data);
} else if (status == false) {
Snackbar.make(view,
"Incorrect User Name OR Password",
Snackbar.LENGTH_LONG).show();
}
Log.i("GARG", "Excution Line Finish ");
} catch (Exception e) {
e.printStackTrace();
}
}
JSONParseAsync class:
public class JSONParseAsync extends AsyncTask<String, String, JSONObject>{
private Context mContext;
ProgressDialog mProgress;
private OnTaskCompleteListener mCallback;
public JSONParseAsync(Context context){
this.mContext = (AppCompatActivity)context;
this.mCallback = (OnTaskCompleteListener) mContext;
}
#Override
protected JSONObject doInBackground(String... URL) {
JSONObject jsonObj = null;
try{
Log.d(Constants.DEBUG_TAG, "line excucation 2 doInBackground");
ServiceHandler sh = new ServiceHandler();
String url = URL[0];
Log.d(Constants.ACTIVITY_TAG, "...." + url);
// Making a request to url and getting response.
String jsonStr = sh.makeServiceCall(url, ServiceHandler.GET);
Log.d(Constants.JSON_TAG, "" + jsonStr);
if (jsonStr != null) {
jsonObj = new JSONObject(jsonStr);
Log.e(Constants.JSON_TAG, "" + jsonObj);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return jsonObj;
}
#Override
protected void onPreExecute() {
Log.d(Constants.DEBUG_TAG, "line excucation 1 onPreexcute");
mProgress = new ProgressDialog(mContext);
mProgress.setMessage("Downloading nPlease wait...");
mProgress.show();
}
#Override
protected void onProgressUpdate(String... values) {
Log.d(Constants.DEBUG_TAG, "line excucation 3 onProgressUpdate");
mProgress.setMessage(values[0]);
}
#Override
protected void onPostExecute(JSONObject result) {
Log.d(Constants.DEBUG_TAG, "line excucation 3 onPostExecute");
mProgress.dismiss();
//This is where you return data back to caller
Log.d(Constants.APP_TAG, " final result:- "+result);
mCallback.onTaskComplete(result);
}
}
Please help me:
By doing this
JSONParseAsync parseAsync = new JSONParseAsync(getContext());
you're sending the Activity to your AsyncTask, but it is your Fragment that implements OnTaskCompleteListener.
Either have your Activity implement your interface, or
do this :
JSONParseAsync parseAsync = new JSONParseAsync(this, getContext());
and change your AsyncTask constructor to
public JSONParseAsync(OnTaskCompleteListener listener, Context context){
this.mContext = context;
//this.mContext = (AppCompatActivity)context; -> you don't need that cast, AppCompatActivity is a subclass of Context
this.mCallback = listener;
}
Use 2 Parameters for your Tasks Constructor:
public JSONParseAsync(Context context, OnTaskCompleteListener listener){
this.mContext = context;
this.mCallback = listener;
}
and create a new instance by using
JSONParseAsync parseAsync = new JSONParseAsync(getContext(), this);
Because when you pass the Context, you don't pass the fragment but the underlying activity. So you'll probaly need 2 parameters if you want to use your task inside your fragment.
You problem is, because you have passed the Activity context to JSONParseAsync and inside its constructor you are casting it to activity AppCompatActivity following the activity casting to your OnTaskCompleteListener.. So, your activity should be implementing the listener and not your fragment.
just let HomeActivity implement your interface OnTaskCompleteListener.
Example:
public class HomeActivity extends AppCompatActivity implements OnTaskCompleteListener{
...
}
In my opinion, don't create your custom classes unless and until its required. In your case you should have achieved your task with anonymous class too.. there's no need to create separate class..
I hope you got my point.
Still, what you can do is, pass the context and OnTaskCompleteListener in the constructor
private void loadProfileAction() {
...
JSONParseAsync parseAsync = new JSONParseAsync(getContext(), this); // also try getActivity()
...
}
and change the constructor to:
public JSONParseAsync(Context context, OnTaskCompleteListener listener){
this.mContext = context;
this.mCallback = listener;
}
I am trying to send a POST request to a php file and when the user is asked for login information, if wrong, it prints the json message from the php file and if right, it allows user to login. However, my application crashes, giving a NetworkOnThreadMainException pointing errors to three lines.
HttpResponse response=httpClient.execute(httpPost);
public class LoginActivity extends ActionBarActivity {
login();
So how can i make this possible?
This is some part of the code I have written:
public class LoginActivity extends ActionBarActivity {
EditText et, et2;
ImageButton ib5;
String name,pwd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
et = (EditText) findViewById(R.id.editText);
et2 = (EditText) findViewById(R.id.editText2);
ib5 = (ImageButton) findViewById(R.id.imageButton5);
name=et.getText().toString();
pwd=et2.getText().toString();
final LoginActivity loginActivity=null;
ib5.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//login();
new DownloadFilesTask(loginActivity,name,pwd).doInBackground();
}
});
}
public void login() {
new LoginTask(this, et.getText().toString(), et2.getText().toString());
}
private class LoginTask {
public LoginTask(LoginActivity loginActivity, String name, String pwd) {
}
}
void navigatetoMainActivity() {
Intent homeIntent = new Intent(getApplicationContext(), MainActivity.class);
homeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(homeIntent);
}
void InvalidToast(){
Toast.makeText(getApplicationContext(), "Please enter valid name and password", Toast.LENGTH_LONG).show();
}
void EmptyToast(){
Toast.makeText(getApplicationContext(), "Please fill the form, don't leave any field blank", Toast.LENGTH_LONG).show();
}
}
DownloadFilesTask.java
public class DownloadFilesTask extends AsyncTask<String, String, String> {
private String name, pwd;
private LoginActivity loginActivity;
public DownloadFilesTask(LoginActivity loginActivity,String name, String pwd){
this.loginActivity=loginActivity;
this.name=name;
this.pwd=pwd;
}
#Override
protected String doInBackground(String... strings) {
HttpClient httpClient=new DefaultHttpClient();
HttpPost httpPost=new HttpPost("login.php");
List<NameValuePair> nameValuePairs=new ArrayList<NameValuePair>(2);
String result=null;
nameValuePairs.add(new BasicNameValuePair("name", name));
nameValuePairs.add(new BasicNameValuePair("password", pwd));
try {
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
HttpResponse response= null;
try {
response = httpClient.execute(httpPost); //error is given here
} catch (IOException e) {
e.printStackTrace();
}
HttpEntity entity=response.getEntity();
InputStream instream= null;
try {
instream = entity.getContent();
} catch (IOException e) {
e.printStackTrace();
}
result=convertStreamToString(instream);
try {
instream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (Utility.isNotNull(name) && Utility.isNotNull(pwd)) {
RequestParams params = new RequestParams();
if (Utility.validate(name, pwd)) {
params.put("username", name);
params.put("password", pwd);
onPostExecute();
} else {
loginActivity.InvalidToast();
}
} else {
loginActivity.EmptyToast();
}
return result;
}
private String convertStreamToString(InputStream instream) {
BufferedReader reader=new BufferedReader(new InputStreamReader(instream));
StringBuilder sb=new StringBuilder();
String line=null;
try {
while ((line=reader.readLine())!=null){
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
instream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
protected void onPostExecute(){
loginActivity.navigatetoMainActivity();
}
private static class Utility {
static Pattern pattern;
static Matcher matcher;
static Pattern pattern1;
static Matcher matcher1;
static String NAME_PATTERN="SuperBoise";
static String PWD_PATTERN="qwerty";
public static boolean validate(String name,String pwd){
pattern=Pattern.compile(NAME_PATTERN);
pattern1=Pattern.compile(PWD_PATTERN);
matcher=pattern.matcher(name);
matcher1=pattern1.matcher(pwd);
return matcher.matches()&& matcher1.matches();
}
public static boolean isNotNull(String name) {
return name!=null && name.trim().length()>0 ? true: false;
}
}
}
Your application has 1 main thread running all the time when it is not paused which is called the UI Thread.
As of the latest versions of Android, you are not permitted to make any network related actions on the UI Thread because it is time-consuming and it blocks the main thread which is responsible for drawing all the UI and registering the clicks, etc. (there is a way to bypass this but it is HIGHLY NOT RECOMMENDED)
An easy way to perform network related actions such as logging in, is the AsyncTask class implemented by Android.
The class runs on a very simple principle, it has 2 methods which run on the UI Thread: the onPreExecute() and the onPostExecute() methods.
And it has a method that runs on a Background Thread which is called the doInBackground() (this is where you should do all your network related actions
Here is a very basic example of an AsyncTask class:
public class DownloadFilesTask extends AsyncTask<void, void, void> {
public DownloadFilesTask(){
// Here you can pass data to the task
// if you want to pass more than 1 type of data
}
protected void onPreExecute(){
// this is executed on the UI Thread
// so you can modify elements inside the UI Thread
// this is called after execute() is called and
// before doInBackground() is called
}
protected void doInBackground(Void... params) {
//here you do all your network related stuff
return null;
}
protected void onPostExecute(Void result) {
// here you can work on the UI Thread
// this is executed after the AsyncTask's execute() is finished
// (after doInBackground() is done)
}
}
And to use this task you can just simply call it from the UI Thread like this:
new DownloadFilesTask().execute();
This is the AsyncTask documentation page on the developer.android.com: AsyncTask
You could pass a reference to your LoginActivity through the constructor of the task and if the login is valid then you can call the navigatetoMainActivity() method from your onPostExecute() inside the task
Edit1: How your LoginActivity should look:
public class LoginActivity extends ActionBarActivity {
EditText et, et2;
ImageButton ib5;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
et = (EditText) findViewById(R.id.editText);
et2 = (EditText) findViewById(R.id.editText2);
ib5 = (ImageButton) findViewById(R.id.imageButton5);
ib5.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
login();
}
});
}
public void login(){
new LoginTask(this, et.getText().toString(), et2.getText.toString()).execute();
}
}
Edit2: This is how your task should look like:
public class LoginTask extends AsyncTask<void , void, void> {
private String user, password;
private LoginActivity loginActivity;
public LoginTask(LoginActivity loginActivity, String user, String password){
this.loginActivity = loginActivity;
this.user = user;
this.password = password;
}
#Override
protected String doInBackground(Void... params) {
//do all the networking here
}
protected void onPostExecute(Void results){
super.onPostExecute(results);
loginActivity.navigatetoMainActivity();
}
}
I'm attempting to implement a JSOUP query however I'm getting an error stating "doc cannot be resolved" and "doc cannot be resolved to a variable" I know I'll need to call doc before I can use it I'm just not sure how to do so yet - It's my first time building a parser with JSOUP - I'm sure it's pretty simple - I just need a quick pointer.
public class MainActivity extends Activity {
TextView tv;
String url = "http://microsoft.com";
String tr;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.TextView01);
new MyTask().execute(url);
}
private class MyTask extends AsyncTask<String, Void, String> {
ProgressDialog prog;
String title = "";
#Override
protected void onPreExecute() {
prog = new ProgressDialog(MainActivity.this);
prog.setMessage("Loading....");
prog.show();
}
#Override
protected String doInBackground(String... params) {
try {
doc = Jsoup.connect(params[0]).get();
Element tableElement = doc.select(".datagrid").first();
Elements tableRows = tableElement.select("tr");
for (Element row : tableRows) {
Elements cells = row.select("td");
if (cells.size() >0) {
System.out.println(cells.get(0).text()+"; "+cells.get(1).text()+"; "+cells.get(2).text()+"; "+cells.get(3).text());
}
}} catch (IOException e) {
e.printStackTrace();
}
return title;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
prog.dismiss();
tv.setText(result);
}
}
}
You are trying to use a variable that has not been declared. Just as you have done with
TextView tv;
you will have to declare the variable doc.
Document doc;
Don't forget to import the following package org.jsoup.nodes.Document.