i have this class:
public class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageFromWeb ifw;
private String url;
private final WeakReference<ImageView> imageViewReference;
public DownloadImageTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
#Override
protected Bitmap doInBackground(String... params) {
url = params[0];
try {
return BitmapFactory.decodeStream(new URL(url).openConnection().getInputStream());
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(Bitmap result) {
if (isCancelled()) {
result = null;
}
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(result);
}
}
}
#Override
protected void onPreExecute() {
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
---------> imageView.setImageResource(R.drawable.pw);
}
}
}
}
and the main activity:
public class ImageFromWeb extends Activity {
private String path = "http://....";
private ImageView imageView;
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.main);
ImageView mChart = (ImageView) findViewById(R.id.imview);
mChart.setTag(path);
new DownloadImageTask(mChart).execute(path);
}
}
I want to put in the point of arrow(in DownloadImageTask class) an alert dialog! How can i do this? Because this class isn't an activity.
thanks :)
change the constructor and pass a Context object
Context mContext;
public DownloadImageTask(ImageView imageView,Context mContext) {
imageViewReference = new WeakReference<ImageView>(imageView);
this.mContext = mContext;
}
Now you can use this Context to create dialogs
You can even cast mContext to your Activity class and call functions within your Activity
Move the Async Task to your activity and use that to call your DownloadImageTask class & methods. This will make your life a lot easier.
pass a Activity instance to the class where you want to display dialog, and check
if(!actvity.isFinishing){
//show dialog
}
You can have a static Context in your Application like this:
public static Context CurrentContext;
and a custom abstract Activity that sets currentContext upon creation like this:
public abstract class CustomActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication.CurrentContext = this;
}
}
Then you would get context like this:
AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(MyApplication.CurrentContext);
dlgBuilder.setTitle("Context Example");
dlgBuilder.setMessage("I am being shown from the application Static context!");
dlgBuilder.setNeutralButton("Ok", null);
dlgBuilder.show();
This way you never have to worry about context wether you are in a background task or directly in an Activity it will work for most cases.
hope this helps!
Related
I have a problem related to AsyncTask. I want to change the text inside the onPostExecute method, but it doesn't work. I really don't know what I am doing wrong. Can somebody help me out please?
I don't understand why it work when I declare the AsyncTask as a nested class but it don't work when I declare it as a own class.
Here is my code:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Button button = null;
private Helper helper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.helper = new Helper(this, getLayoutInflater());
this.button = (Button) findViewById(R.id.button1);
this.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
new MyAsyncTask(helper).execute("");
} catch (Exception e) {
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
}
}
});
}
}
Helper.java
public class Helper {
private Context context;
private LayoutInflater inflater;
public Helper(Context context, LayoutInflater inflater) {
setContext(context);
setInflater(inflater);
}
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
public LayoutInflater getInflater() {
return inflater;
}
public void setInflater(LayoutInflater inflater) {
this.inflater = inflater;
}
}
MyAsyncTask.java
public class MyAsyncTask extends AsyncTask<String, String, String> {
private Helper helper;
public MyAsyncTask(Helper helper) {
setHelper(helper);
}
public String getJSON(String url, int timeout) {
HttpURLConnection c = null;
try {
URL u = new URL(url);
c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setRequestProperty("Content-length", "0");
c.setUseCaches(false);
c.setAllowUserInteraction(false);
c.setConnectTimeout(timeout);
c.setReadTimeout(timeout);
c.connect();
int status = c.getResponseCode();
switch (status) {
case 200:
case 201:
BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
return sb.toString();
}
} catch (MalformedURLException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
} finally {
if (c != null) {
try {
c.disconnect();
} catch (Exception ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
}
}
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String s) {
TextView t = (TextView) getHelper().getInflater().inflate(R.layout.activity_main, null).findViewById(R.id.textView);
t.setText("" + s); //has no effect on the UI but the text was set????
Toast.makeText(getHelper().getContext(), t.getText(), Toast.LENGTH_LONG).show();
super.onPostExecute(s);
}
#Override
protected String doInBackground(String... params) {
return getJSON("testside.com", 10000);
}
public Helper getHelper() {
return helper;
}
public void setHelper(Helper helper) {
this.helper = helper;
}
}
Thanks :)
Utilize you AsyncTask outside of your main Class using separate files
class MyActivity{
new MyAsyncTask().execute();
}
Your AsyncTask lives as another class Extending AsyncTask
class MyAsyncTask extends AsyncTask{
public MyAsyncTask(Context appContext){
}
}
Be sure to pass in your App's Context. You can only execute each instance of the task once.... but you can create and run a new instance when needed...
Wouldn't fly:
class MyActivity{
MyAsyncTask myTask = new MyAsyncTask();
myTask.execute();
//DO OTHER STUFF
myTask.execute();
}
You would instead do each time needed:
new MyAsyncTask().execute();
Your code looks fine but it doesn't work because it take reference to TextView from new layou which you inflate.
You have two options:
In your helper store TextView which you want to change, you can make it optional if your helper looks something like this:
public class Helper {
private Context context;
private LayoutInflater inflater;
private TextView textView;
...
public void addTextView(TextView textView){
this.texView = textView;
}
public TextView getTextView(){
return textView;
}
}
and then in your postExecute() call TextView t = helper.getTextview().
Pass textView directly to your AsyncTask so it look like
public MyAsyncTask(Helper helper, TextView t) {
setHelper(helper);
this.textView = t;
}
Your AsyncTask is executed on a background thread. To update your UI call,
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText("Text");
}
});
on an activity.
I'm trying receive the image over TCP (in Asynctask) and display it in ImageView but I have an error in onPostExecute. Anyone know why?
And also whether idea of receiving is correct, if the next step will be recurring receiving image over TCP and displaying it?
Code:
public class TcpClient extends Activity {
ImageView imageView;
public static String aHost;
public String aSocketIn;
public static int aSocketInInt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bundle_result);
imageView = (ImageView) findViewById(R.id.imageView);
Intent intent = getIntent();
aHost = intent.getStringExtra("addressIp");
aSocketIn = intent.getStringExtra("socketIn");
aSocketInInt = Integer.parseInt(aSocketIn);
new DownloadImageTask(aHost,aSocketInInt).execute();
} }
public class DownloadImageTask extends AsyncTask <Void,Void,Bitmap > {
public Bitmap bitmap = null;
String Host;
int SocketIn;
public DownloadImageTask(String Host,int SocketIn) {
this.Host = Host;
this.SocketIn = SocketIn;
}
#Override
protected Bitmap doInBackground(Void... params) {
ClientIn clientIn;
try {
InetAddress serwerAddress = InetAddress.getByName(Host);
Socket socket = new Socket(serwerAddress, SocketIn);
clientIn = new ClientIn(socket);
bitmap = clientIn.Receive();
return bitmap;
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(Bitmap result) {
imageView.setImageBitmap(result); // ERROR: Cannot resolve symbol 'imageView'
} }
Looks like DownloadImageTask class is not inner-class of TcpClient class which is extending Activity,so to access imageView object of ImageView in other class, need to send it on DownloadImageTask using class constructor in same way as doing currently for getting Host and SocketIn in DownloadImageTask class.
Change DownloadImageTask as for to using imageView "
public DownloadImageTask(String Host,int SocketIn,ImageView imageView) {
this.Host = Host;
this.SocketIn = SocketIn;
this.imageView=imageView;
}
I am using asynckTask to decode a file and onPostExecute I setImageBitmap and call progressDialog.dismiss() but after the progressDialog is dismissed the imageView take a few seconds to show the image. What I want is the progressDialog to disappear only when the image view is ready for the user. My code is below:
class MyTask extends AsyncTask<String, Integer, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private String mainImageString;
private Context context;
ProgressDialog progressDialog;
public MyTask(ImageView imageView, Context mContext) {
imageViewReference = new WeakReference<ImageView>(imageView);
context = mContext;
}
#Override
protected void onPreExecute() {
progressDialog= ProgressDialog.show(MyClass.this, "Progress Dialog Title Text","Process Description Text", true);
}
// Decode image in background.
#Override
protected Bitmap doInBackground(String... params) {
mainImageString = params[0];
return BitmapFactory.decodeFile(mainImageString);
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
progressDialog.dismiss();
}
}
}
}
When you are setting your Bitmap basically you are "building" it on the UI thread. What I recommend is to call setImageBitmap in your doInBackground callback and then dismiss the dialog.
You can do this...
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
handler.postDelayed(new Runnable() {
public void run() {
progressDialog.dismiss();
}
}, 1000); //time for image to appear in image view
}
}
Please note this is not a foolproof way..but this what-easy way-currently I can think of..
Other hack I can think about is to extend ImageView and override onDraw().call super() in onDraw(),once the call to super() returns then dismiss the dialog box.This is more accurate way of doing it.
something like this:
onDraw(){
super();
onDismissDialogBox()//send an even to activity to dismiss dialog box
}
I have this little piece of code and I want to achieve this: program should set a wallpaper from linked image.
ImgDownload:
public class ImgDownload extends AsyncTask {
private String requestUrl;
private ImageView view;
private Bitmap pic;
private ImgDownload(String requestUrl, ImageView view) {
this.requestUrl = requestUrl;
this.view = view;
}
#Override
protected Object doInBackground(Object... objects) {
try {
URL url = new URL(requestUrl);
URLConnection conn = url.openConnection();
pic = BitmapFactory.decodeStream(conn.getInputStream());
} catch (Exception ex) {
}
return null;
}
#Override
protected void onPostExecute(Object o) {
view.setImageBitmap(pic);
}
}
main
public class MainActivity extends Activity {
private ImageView img;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img= (ImageView)findViewById(R.id.img);
//!!!! This is where I am stuck :)
Object s = new ImgDownload("http://images1.wikia.nocookie.net/__cb20120402213849/masseffect/images/4/42/Uncharted_Worlds_Codex_Image.jpg",img );
}
#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;
}
}
How to instantiate/create this class in my mainActivity, so it could download img from link? Any help suggestions, thoughts, will be appreciated :)
You execute this AsyncTask like this:
ImgDownload downloader = new ImgDownload("http://images1.wikia.nocookie.net/__cb20120402213849/masseffect/images/4/42/Uncharted_Worlds_Codex_Image.jpg",img);
downloader.execute();
But I would not recommend using your code as it will produce memory leaks. For example try to rotate your device while it is downloading an image. I guarantee you your application will crash. Plus AsyncTask is a generic class. You could use that to make your code a little simpler. Here is my improved image download task:
public class ImgDownload extends AsyncTask<Void, Void, Bitmap> { // Use Generics
private final String requestUrl;
private final WeakReference<ImageView> imageViewReference; // Use WeakReference to prevent memory leaks
public ImgDownload(String requestUrl, ImageView view) {
this.requestUrl = requestUrl;
this.imageViewReference = new WeakReference<ImageView>(view);
}
#Override
protected Bitmap doInBackground(Void... objects) {
try {
URL url = new URL(requestUrl);
URLConnection conn = url.openConnection();
return BitmapFactory.decodeStream(conn.getInputStream()); // Return bitmap instead of using global variable
} catch (Exception ex) {
}
return null;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
ImageView imageView = imageViewReference.get();
if(imageView != null && bitmap != null) { // Check if image or ImageView are null
imageView.setImageBitmap(bitmap);
}
}
}
new ImgDownload("http://images1.wikia.nocookie.net/__cb20120402213849/masseffect/images/4/42/Uncharted_Worlds_Codex_Image.jpg", MainActivity.img).execute();
I am working with some Acitivitys , it's working pretty well. But i am having a strange delay on it.
And I figure it out that, it was about this part of the code, where I am loading stored image in the SDCard.
if(p.getAdress() != null){
Bitmap bitmap = BitmapFactory.decodeFile(p.getAdress());
new_image.setBackgroundDrawable(null);
new_image.setImageBitmap(bitmap);
}
Why this simple code is taking too long to execute?
How to solve it?
If I take this code off, everything works as i wished.
You shouldn't load large bitmaps directly on the UI thread.
Actually, the best reference to loading large Bitmaps efficiently can be found here.
And right here you can find good information on how you can load them using an AsyncTask.
This is the method they show you there (you can even download the sample!)
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private int data = 0;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
#Override
protected Bitmap doInBackground(Integer... params) {
data = params[0];
return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
}
// Once complete, see if ImageView is still around and set bitmap.
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
public void loadBitmap(int resId, ImageView imageView) {
if (cancelPotentialWork(resId, imageView)) {
final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
final AsyncDrawable asyncDrawable =
new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
imageView.setImageDrawable(asyncDrawable);
task.execute(resId);
}
}
Your can try this way. It help you
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
if(p.getAdress() != null){
Bitmap bitmap = BitmapFactory.decodeFile(p.getAdress());
new_image.setBackgroundDrawable(null);
new_image.setImageBitmap(bitmap);
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}