Destry Destry - 5 months ago 55
Java Question

Set TextView in Android app after POST call

I am working on an android app that makes a post call to a website via API. After the call is made and returns it then puts that response in the TextView of another fragment. However every time I run the app it force closes if the fragment_main is not included in activity_main. I cannot figure out why it cannot find my ID but it is frustrating. Also if I include fragment_main in activity_main then it never goes away. Here is the code...

MainActivity.java -------------

package com.horizonservers.horizon;

import android.app.ProgressDialog;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputEditText;
import android.view.View;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebViewFragment;
import android.widget.TextView;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.Buffer;

import javax.net.ssl.HttpsURLConnection;

public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, ProfileFragment.OnFragmentInteractionListener, MainFragment.OnFragmentInteractionListener {

TextView mResult;

NavigationView navigationView = null;
Toolbar toolbar = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//Set the main fragment
MainFragment fragment = new MainFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();

navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);


mResult = (TextView) findViewById(R.id.tv_result);


// Make GET request to server
//new


//Make POST request to server
new PostDataTask().execute("https://thewebsite.com/api/v1/blah");
}

@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();

//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}

return super.onOptionsItemSelected(item);
}

@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();

if (id == R.id.main) {
//Set the main fragment
MainFragment fragment = new MainFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
} else if (id == R.id.player_profile) {
//Set the main fragment
ProfileFragment fragment = new ProfileFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();

} else if (id == R.id.map_tracker) {

}

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
public void onFragmentInteraction(Uri uri){
//you can leave it empty
}

class GetDataTask extends AsyncTask<String, Void, String> {

ProgressDialog progressDialog;

@Override
protected void onPreExecute() {
super.onPreExecute();

progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Loading Data...");
progressDialog.show();
}

@Override
protected String doInBackground(String... params) {

try {
return getData(params[0]);
} catch (IOException ex){
return "Network Error!";
}
}

@Override
protected void onPostExecute(String result) {

//Set data to be shown on TextView
mResult.setText(result);

//cancel progressdialog
if(progressDialog != null) {
progressDialog.dismiss();
}
super.onPostExecute(result);
}

private String getData(String urlPath) throws IOException{


BufferedReader bufferedReader = null;
StringBuilder result = new StringBuilder();
//Initialize request with server

try {
URL url = new URL(urlPath);
HttpURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000 /* 10 second time out */);
urlConnection.setConnectTimeout(10000 /* 10 second time out */);
urlConnection.setRequestMethod("GET");
urlConnection.setRequestProperty("Content-type", "application/json");
urlConnection.connect();

//Read data from server
InputStream inputStream = urlConnection.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;

while((line = bufferedReader.readLine()) != null){
result.append(line).append("\n");
}



} finally {
if(bufferedReader != null){
bufferedReader.close();
}
}
return result.toString();
}
}


class PostDataTask extends AsyncTask<String, Void, String> {

ProgressDialog progressDialog;

@Override
protected void onPreExecute() {
super.onPreExecute();

progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Inserting data...");
progressDialog.show();
}

@Override
protected String doInBackground(String... params) {

try {
return postData(params[0]);
} catch (IOException ex) {
return "Network error !";
} catch (JSONException ex) {
return "Data Invalid !";
}
}

@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);

mResult.setText(result);

if (progressDialog != null) {
progressDialog.dismiss();
}
}

private String postData(String urlPath) throws IOException, JSONException {

StringBuilder result = new StringBuilder();
BufferedWriter bufferedWriter = null;
BufferedReader bufferedReader = null;

try {
//Create data to send to server
JSONObject dataToSend = new JSONObject();
dataToSend.put("apikey", "UPj07lqWdetOWrk9M8Ya9UZzeIAizjr4sYQRKzkHFYm1KaQDopytCFq9HHCerwNy");
dataToSend.put("steamid", "STEAM_0:1:90345825");
dataToSend.put("maptype", "surf");

//Initialize and config request, then connect to server.
URL url = new URL(urlPath);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(10000 /* milliseconds */);
urlConnection.setRequestMethod("POST");
urlConnection.setDoOutput(true); //enable output (body data)
urlConnection.setRequestProperty("Content-Type", "application/json");// set header
urlConnection.connect();

//Write data into server
OutputStream outputStream = urlConnection.getOutputStream();
bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write(dataToSend.toString());
bufferedWriter.flush();

//Read data response from server
InputStream inputStream = urlConnection.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
result.append(line).append("&");
}
} finally {
if (bufferedReader != null) {
bufferedReader.close();
}
if (bufferedWriter != null) {
bufferedWriter.close();
}
}

return result.toString();
}
}


}


Here is MainFragment.java it inflates the fragment_main.xml file.

FragmentMain.java

package com.horizonservers.horizon;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.CookieManager;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.WebViewFragment;
import android.widget.Button;
import android.widget.TextView;


/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link MainFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {@link MainFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class MainFragment extends Fragment {


// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";

// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;

private OnFragmentInteractionListener mListener;

public MainFragment() {
// Required empty public constructor
}

/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment MainFragment.
*/
// TODO: Rename and change types and number of parameters
public static MainFragment newInstance(String param1, String param2) {
MainFragment fragment = new MainFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false);
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}


// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}

@Override
public void onDetach() {
super.onDetach();
mListener = null;
}

/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}

}


Here is the activity_main.xml, mostly unchanged.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">

<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />


<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />

</android.support.v4.widget.DrawerLayout>


And finally, the fragment_main.xml

fragment_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="-20dp"
android:textSize="17sp"
android:textStyle="bold"
android:text="Test HTTP request !" />
</RelativeLayout>


Now when I run the app without fragment_main being included in activity_main I get this error


java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.horizonservers.horizon.MainActivity$PostDataTask.onPostExecute(MainActivity.java:257)
at com.horizonservers.horizon.MainActivity$PostDataTask.onPostExecute(MainActivity.java:228)


Can anyone help me, I'm still learning so please forgive me.

Answer

tv_result is in fragment_main and you are initializing it in your Activity.It needs to be initialized in your fragment. You cannot find the views of other layouts in your activity.

Initialize the view in your fragment's onCreateView like :

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View v = inflater.inflate(R.layout.fragment_main, container, false);
    mResult = (TextView) v.findViewById(R.id.tv_result);
    return view;
}

After the on the result is obtained send it your fragment using eventBus or an interface and set the text in the Fragment and not the Activity.

Comments