i am trying to make an application where asynctask is used to continously update a textview in my main interface. There is another button which opens another activity. When i start the application, the asyntask starts and displays data to the textview but when i click on the other button to open another activity and click on back button to return to the previous activity where the aysnctask was running, it stopped displaying data to the textview.
Could you help mem with this problem or suggest alternative ways. Thank you.
Code for MainActivity:
Button about;
TextView tempData;
Context context = this;
AllSensorData sensorData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
about=(Button)findViewById(R.id.hAbout);
tempData=(TextView)findViewById(R.id.tempData);
sensorData=new AllSensorData(tempData,getApplicationContext());
sensorData.execute("http://192.168.1.177/");
about.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Intent i =new Intent(getApplicationContext(),AboutActivity.class);
startActivity(i);
}
});
Code for aynctask class:
public class AllSensorData extends AsyncTask<String, byte[], String>{
TextView temp;
Context context;
public AllSensorData(TextView temp,Context context) {
this.temp=temp;
this.context=context;
}
InputStream nis;
OutputStream nos;
BufferedReader in;
DefaultHttpClient httpclient =new DefaultHttpClient();
URL url;
URLConnection urlconn=null;
InputStreamReader isn;
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
try {
//this method is working for data only
while(true){//while connected
HttpGet httpget =new HttpGet("http://192.168.1.177/");
response = httpclient.execute(httpget);
in=new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String msgFromServer = in.readLine();//read the lines coming from the socket
byte[] theByteArray = msgFromServer.getBytes();//store the bytes in an array
publishProgress(theByteArray);//update the publishProgress
if(isCancelled()){
break;
}
}
} catch (ClientProtocolException e) {
} catch (IOException e) {
}
return null;
}
private boolean alreadyDisplayedNotification = false;
private boolean already =false ;
protected void onProgressUpdate(byte[]... values) {
super.onProgressUpdate(values);
String command=new String(values[0]);//get the String from the recieved bytes
String[] parts= command.split(",");
String part1=parts[0];
temp.setText(part1);
}
}
Read about the activity state saving and recreation of Activity
http://developer.android.com/training/basics/activity-lifecycle/recreating.html
Go through this save instance state to understand why your value in text is not showing
put your "refresh" code inside of onStart() instead of onResume(). onStart() gets "Called when the activity is becoming visible to the user."
Go through Activity life cycle
Related
I have just started out with Java development(android app) and I stumbled upon a problem I don't know how to solve.
So I have two fragments:
1) Fragment with barcode scanner
2) Fragment with just a simple textview
The app should be able to scan barcode, get API response based on the scan result, deserialize it into a Java object and then show value of one variable in the textview located in the second fragment.
I have already implemented the barcode scanner and class to get data from API and turn it into a Java object. The problem is that I can't find a way to send the barcode result to the class that handles the API data retrieval and also how to send the object to the second fragment.
Can someone please direct me in the right way on how to implement it correctly?
1)Barcode fragment
public class BarcodeFragment extends Fragment {
private CodeScanner mCodeScanner;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
final Activity activity = getActivity();
View root = inflater.inflate(R.layout.barcode_fragment, container, false);
CodeScannerView scannerView = root.findViewById(R.id.scanner_view);
mCodeScanner = new CodeScanner(activity, scannerView);
mCodeScanner.setDecodeCallback(new DecodeCallback() {
#Override
public void onDecoded(#NonNull final Result result) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(activity.getApplicationContext(), result.getText(), Toast.LENGTH_SHORT).show();
}
});
}
});
scannerView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mCodeScanner.startPreview();
}
});
return root;
}
#Override
public void onResume() {
super.onResume();
mCodeScanner.startPreview();
}
#Override
public void onPause() {
mCodeScanner.releaseResources();
super.onPause();
}
}
2) Class to get data from API and turn it into JAVA object
public class RetrieveFeedTask extends AsyncTask<Void, Void, String> {
Product productFromDatabase;
String resultString;
public RetrieveFeedTask(String barcodeResult){
resultString = barcodeResult;
}
protected void onPreExecute() {
}
protected String doInBackground(Void... urls) {
try {
URL url = new URL("https://api.appery.io/rest/1/apiexpress/api/example/Products?apiKey=12345678&Barcode=" + resultString);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close();
return stringBuilder.toString();
}
finally{
urlConnection.disconnect();
}
}
catch(Exception e) {
Log.e("ERROR", e.getMessage(), e);
return null;
}
}
protected void onPostExecute(String response) {
if(response == null) {
response = "THERE WAS AN ERROR";
}
Log.i("INFO", response);
deSerializeProduct(response);
}
public void deSerializeProduct(String response){
response = response.substring(1,response.length() - 3);
StringBuilder stringBuilder = new StringBuilder(response);
stringBuilder.append(",\"productId\":\"23323123sdasd\"}"); // for testing
String responseToDeSerialize = stringBuilder.toString();
ObjectMapper mapper = new ObjectMapper();
try {
productFromDatabase = mapper.readValue(responseToDeSerialize, Product.class);
} catch (IOException e) {
e.printStackTrace();
}
}
}
3) Cart fragment class where to name of the object should appear in the textview
public class CartFragment extends Fragment {
static TextView showReceivedData;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
// Defines the xml file for the fragment
View view = inflater.inflate(R.layout.cart_fragment, parent, false);
showReceivedData = (TextView) view.findViewById(R.id.resultCode);
return view;
}
}
The asynctask shouldn't outlive the lifecycle of the activity or fragment that starts it. I'm assuming you probably will display some sort of loading status while the network request happens. Here are some options:
If the two fragments are in the same activity, you could pass the result of the scan to the activity, kick off the network request, swap fragments, and send the request result to the second fragment.
The scanner fragment can get the barcode data, kick off the request, show the loading state, and when the result returns, package in the bundle, which the second fragment can read.
Invert the previous model, if it fits your app better, and send just the barcode result in the bundle, and have the second fragment kick off the request while displaying the loading status.
The exact choice will depend on the flow and structure of your app. Additionally, you may want to look into using another multithreading option instead of asynctask, as it has been deprecated and Google is trying to move developers away from it. Some alternatives are the Java concurrency library, RxJava, or if you are willing to use Kotlin in your project, Kotlin coroutines.
Use Bundle to add pass data between Activity and fragments
try This code to Pass data between two fragments
Bundle bundle=new Bundle();
bundle.putString("scanner_data","myData");
Fragment fragment=new HomeFragment();
fragment.setArguments(bundle);
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.add(R.id.framContainer, fragment, "TAg");
ft.commit();
How to get data
Bundle bundle=getArguments();
I want to show progressbar where image downloaded and set custom color
I do it in onProgressUpdate() but it dosent work it also doesn't appear in logcat.. it also shows a white screen until download completed and if I press back button during the download, it will crash.
my code:
public class DownloadImage extends AsyncTask<String ,Void, Bitmap> {
Bitmap bit;
#Override
protected Bitmap doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
return BitmapFactory.decodeStream(connection.getInputStream());
} catch(Exception e){
Log.i("error download", "doInBackground: "+e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
Log.i("download", "onPostExecute: ");
imageView.setImageBitmap(bitmap);
progressBar.setVisibility(View.GONE);
}
#Override
protected void onProgressUpdate(Void... values) {
Log.i("download", "onProgressUpdate: ");
imageView.setColorFilter(R.color.imagecolor);
}
}
and onCreate() method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
imageView = findViewById(R.id.imageView2);
progressBar = findViewById(R.id.progressBar2);
DownloadImage downloadImage = new DownloadImage();
downloadImage.execute("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRaL6woz3RgMF-UXU682S_BYb1ayl5xaVancp0PPvF2HnCDmPsb");
try {
downloadImage.get();
} catch (Exception e){
}
}
I want to show progressbar where image downloaded and set custom color I do it in onProgressUpdate() but it dosent work
You need to call publishProgress() from doInBackground(). That will trigger calls to onProgressUpdate(). You are not doing this, and so onProgressUpdate() will not be called.
it also shows a white screen until download completed
Remove your downloadImage.get(); call. That will block the main application thread, and the point of using AsyncTask (or its more modern replacements) is to not block the main application thread.
and if I press back button during the download, it will crash.
If the activity/fragment is destroyed, you should not update the UI. So, you need to confirm in onPostExecute() whether it is safe to update the UI (e.g., call isDestroyed() on the activity).
Beyond that, use Logcat to examine the stack trace associated with any crashes.
I am an university student programming an android app that shall display messages, which the android device receives via TCP from a server.
The class ListenForMessage (extending AsyncTask) opens the TCP connection and receives messages from the server within the DoInBackground method. I can print out the messages from the server in the log, but if I try to edit the text of a TextView, my app crashes. It seems I cannot edit TextView´s texts from the DoInBackground method, especially not, because the class does not extend the activity, in which the TextView is created.
I have two activities and I am executing the class "ListenForMessage" in the onCreate of the second activity "StreamPageMain" (Before that, I executed it from within MainActivity, but that did not work either). I tried to let the method know, in which activity the TextView belongs, as you can see in my code, and I created another method within the class "ListenForMessage" to set the text, so that it is not the DoInBackground method trying to change the text, but none of that worked.
Summary:
I have marked the spot in the code, that goes wrong. What I need to do, is somehow taking the String called "message" and put that String in the TextView with ID "textView1" which is part of the "StreamPageMain" activity and not the MainActivity.
I start with this method in the MainActivity when a button is pressed:
public void stream(View V) {
EditText IPText = (EditText) findViewById(R.id.editTextBox2); //Extracting the IP from an EditTextView
EditText portText = (EditText) findViewById(R.id.editTextBox3); //Extracting the port from an EditTextView
String IP = IPText.getEditableText().toString(); //correcting the format to String
Integer port = Integer.parseInt(portText.getEditableText().toString()); //correcting the format to Integer
Intent i = new Intent(MainActivity.this, StreamPageMain.class);
i.putExtra("IP", IP);
i.putExtra("port", port);
startActivity(i);
}
The second Activity "StreamPageMain" is launched. That works.
import android.widget.VideoView;
public class StreamPageMain extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stream_page);
Log.d("StreamingApp", "OnCreate is running.");
//In this middle part I am implementing a videostream into the second
activity, but that does not affect anything
String IP = getIntent().getStringExtra("IP");
Integer port = getIntent().getExtras().getInt("port");
ListenForMessage listenForMessage = new ListenForMessage(StreamPageMain.this, IP, port);
listenForMessage.execute();
}
}
You can see, how I am passing the Activity StreamPageMain to the ListenForMessage class here. The class itself, the connection and everything works fine if I comment out the marked line:
package comn.example.ezio.streamingapp;
import android.app.Activity;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class ListenForMessage extends AsyncTask<Void, Void, Void> {
public Activity executingActivity;
public String IP;
public Integer port;
public ListenForMessage(Activity activity, String IPString, Integer portNumber) {
this.executingActivity = activity;
IP = IPString;
port = portNumber;
}
#Override
protected Void doInBackground(Void... voids) {
try (Socket socket = new Socket(IP, port)) {
Boolean connectionCancelled = false;
while (connectionCancelled == false) {
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(isr);
String message = br.readLine();
Log.d("StreamingApp", "Server says: " + message);
setTextOfTextView(message); //!!!! This is it. At this line it
//crashes, no matter how I put it.
//Doing it directly here or in an
//extra method like now.
}
} catch (
UnknownHostException e)
{
e.printStackTrace();
} catch (
IOException e)
{
e.printStackTrace();
}
return null;
}
public void setTextOfTextView(String textOfTextView) {
TextView textView1 = executingActivity.findViewById(R.id.textView1);
textView1.setText("Server says: " + textOfTextView);
}
}
I am after all very new to Java and my knowledge does not go far beyond what I have posted here. Please excuse formatting mistakes and not-best practices, I am happy to learn and improve!
As you saw you can't make changes to the UI in doInBackground because the code in there is executed in another thread and you can only make changes to the UI in the UI thread. (You can post changes to the UI thread from a nother thread though).
To update the UI in AsyncTasks you can use the onProgressUpdate to update the UI because the code here runs on the UI thread. You override this method in the AsyncTask:
protected void onProgressUpdate(String... progress) {
setTextOfTextView(progress[0]);
}
To send the updates from doInBackground to the onProgressUpdate you call the method publishProgress()
#Override
protected Void doInBackground(Void... voids) {
try (Socket socket = new Socket(IP, port)) {
Boolean connectionCancelled = false;
while (connectionCancelled == false) {
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(isr);
String message = br.readLine();
Log.d("StreamingApp", "Server says: " + message);
publishProgress(message); //!!!! This is it. At this line it
//crashes, no matter how I put it.
//Doing it directly here or in an
//extra method like now.
}
} catch (
UnknownHostException e)
{
e.printStackTrace();
} catch (
IOException e)
{
e.printStackTrace();
}
return null;
}
EDIT:
Moreover, in order to publish any results you should change your AsyncTask signature to AsyncTask<Void, String, Void>
I have an app connected to a Java Servlet backend by means of an AsyncPost task. The task returns a String to the client representing a json object serialized with Gson.
It works almost fine, the problem is that I'm unable to access the Servlet response message from the class instantiating the call to the ServletPostAsyncTask: ListViewPrenota.class.
The project is structured as follows:
Both within the Servlet and the Client I created the two classes, Tour.class and Tours.class to store my data:
Tour class:
public class Tour {
// some simple int/string/list fields
}
Tours class:
public class Tours {
private List<Tour> tours;
// ...
}
On Client side, in a ServletPostAsyncTask.class, I receive the aforementioned Gson object within doInBackGround(). Within onPostExecute() I deserialize it, this way:
class ServletPostAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
private Context context;
Tours tours;
#Override
protected String doInBackground(Pair<Context, String>... params) {
//connect to Servlet and get the serialized Gson object
}
#Override
protected void onPostExecute(String jsonResponse) {
tours = (new Gson().fromJson(jsonResponse, Tours.class));
}
}
Now, from ListViewPrenota.class in Client I am calling the ServletPostAsyncTask:
ServletPostAsyncTask s = new ServletPostAsyncTask();
s.execute(new Pair<Context, String>(ListViewPrenota.this, "tours"));
Tours ttours = s.tours;
Tour tour = ttours.getTours().get(0);
Problem: I receive a java.lang.NullPointerException pointing to Tour tour = ttours.getTours().get(0);
What is the reasong preventing me to access the newly received Tours object from other classes than ServletPostAsyncTask?
Thank you very much
the problem is you are thinking that code runs serially, if you want to use stuff returned from the AsycTask you need to use it in onPostExecute or have a callback that sends the data after it is done
doInBackground(){
//do heavy work
}
onPostExecute(Data data){
//handle data
//send data via interface to activity or class that needs the data
//or just put everything that needs the data in here
}
Ok, it works. Here's what I was able to come up with:
Callback interface:
interface CallBack {
void callBackMethod(Tours tours);//do job
}
Caller class:
class ServletPostAsyncTask extends AsyncTask<Pair<Context, String>, Tours, String>{
private Context context;
Tours tours;
public ListViewPrenota listViewPrenota;
public ServletPostAsyncTask(ListViewPrenota listView){
this.listViewPrenota = listView;
}
#Override
protected String doInBackground(Pair<Context, String>... params) {
//communicate with Servlet and get a HttpResponse
}
#Override
protected void onPostExecute(String jsonResponse) {
tours = (new Gson().fromJson(jsonResponse, Tours.class));
//the callback starts a thread updating the UI in ListViewPrenota
listViewPrenota.callBackMethod(tours);
Toast.makeText(
context,
"Connected. \nTours size: "+ tours.getTours().size(),
Toast.LENGTH_LONG).show();
}
}
The callback interface's implementation within ListViewPrenota:
public class ListViewPrenota extends FragmentActivity implements CallBack{
private ProgressDialog m_ProgressDialog = null;
private Runnable viewOrders;
private TourAdapter m_adapter;
ListView listView;
private ArrayList<Tour> m_tours =null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view_prenota);
listView = (ListView) findViewById(R.id.list);
m_tours = new ArrayList<Tour>();
m_adapter = new TourAdapter(this, R.layout.list_row, m_tours);
listView.setAdapter(m_adapter);
getActionBar().setDisplayHomeAsUpEnabled(true); //pulsante drawer
getActionBar().setHomeButtonEnabled(true); //pulsante dietro
ServletPostAsyncTask spat = new ServletPostAsyncTask(ListViewPrenota.this);
String status = spat.getStatus().toString();
spat.execute(new Pair<Context, String>(ListViewPrenota.this,"tours"));
}
public void callBackMethod(final Tours tours){
System.out.println("I've been called back");
viewOrders = new Runnable(){
#Override
public void run() {
getOrders(tours);
}
};
Thread thread = new Thread(null, viewOrders, "MagentoBackground");
thread.start();
m_ProgressDialog = ProgressDialog.show(
ListViewPrenota.this,
"Please wait...",
"Retrieving data ...",
true);
}
public void getOrders(Tours tours){
try{
m_tours = new ArrayList<>();
m_tours.addAll(tours.getTours());
Thread.sleep(2000);
Log.i("ARRAY", "" + m_tours.size());
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
//add tours to the adapter
runOnUiThread(returnRes);
}
private Runnable returnRes = new Runnable() {
#Override
public void run() {
if(m_tours != null && m_tours.size() > 0){
m_adapter.notifyDataSetChanged();
for(int i=0;i<m_tours.size();i++)
m_adapter.add(m_tours.get(i));
}
m_ProgressDialog.dismiss();
m_adapter.notifyDataSetChanged();
}
};
If there's a better way to do it I accept further suggestions.
In the mean time, thank you very much
I am trying to get some text via HTTP GET and display it to the UI. I do not need an async task (i.e, the user have to wait until I get the text completely).
I tried this in main thread
try {
String url = URL_HERE;
HttpGet httpget = new HttpGet (url);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
text = Client.execute(httpget, responseHandler);
}
catch(Exception ex) {
text = ex.getLocalizedMessage();
}
But I always see an exception.
I just need a simple mechanism to get the text. Could you suggest?
Thank you very much,
You should use AsyncTask but if you have to use a sync method
try
String resut = execute().get().toString();
it will freeze the UI(without application is not responding) till you got the message from httpget
All networking has to be in a separate thread by Android's design. It is very possible that the request will take some time and the user has to be bothered by waiting as little as possible. So, you will have to use an AsyncTask or similar.
You should use a ASyncTask so the UI thread doesn't freeze. If the UI thread freezes, Android will show an "Application not responding" dialog to the user, so it's important that you do your call in a ASyncTask even if you don't want your user to use the UI while you are doing it.
You can "block" the UI overriding the onPreExecute method in the ASyncTask (to show a progress dialog for example) then "unblock" it overriding the onPostExecute method (to remove the progress dialog for example).
You should always use AsyncTask to perform the network operations
in android
Because anything that takes more time to load to the UI will lead to
"Unresponsive of the android application"(ANR)
Sample::
public class FrgLatein extends Fragment {
//New-Instance
public static FrgLatein newInstance(){
Log.d("FrgLatein", "newInstance");
FrgLatein fragment = new FrgLatein();
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("FrgLatein", "onCreateView");
View view=inflater.inflate(R.layout.frg_latein, container, false);
setHasOptionsMenu(true);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.d("FrgLatein", "onActivityCreated");
super.onActivityCreated(savedInstanceState);
}
#Override
public void onStart() {
Log.d("FrgLatein", "onStart");
super.onStart();
new LongOperation1().execute("");
}
private class LongOperation1 extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
// Do the Web service long run here
try {
String url = URL_HERE;
HttpGet httpget = new HttpGet (url);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
text = Client.execute(httpget, responseHandler);
}
catch(Exception ex) {
text = ex.getLocalizedMessage();
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
// Do the UI-task here
}
#Override
protected void onPreExecute() {
// Do the UI-task here
}
#Override
protected void onProgressUpdate(Void... values) {
// Do the UI-task here which has to be done during backgroung tasks are running like a downloading process
}
}
}