Java multithreading: Passing camera frame to running worker thread - java

I am using OpenCV4Android and capturing camera frames, so each time a frame has been captured, the method Mat onCameraFrame(CvCameraViewFrame inputFrame) is called. Inside that method I receive the frames in a Mat object (mRgba).
When a button has been clicked, I start sending out those frames to a connected FTP server. When that button has been clicked again, I stop sending the frames. I need to be putting this on a separate thread, as sending out these frames causes a lot of GUI lag.
What I am struggling to conceptualize and code is... to be able to have one thread that starts and stops on button clicked, and initialize and start the thread once - when started, receives each camera frame from the camera and pushes that camera frame out to the FTP server.
Currently I have this:
public class FdActivity extends Activity implements CvCameraViewListener2 {
private FTPImage ftp;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//connect to FTP server
ftp = new FTPImage();
Runnable runnable = new Runnable() {
#Override
public void run() {
String ftpResult = ftp.connectToFTP(config.getFtpIP());
}
};
new Thread(runnable).start();
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
if (isRecordFrames) {
Bitmap bmp;
try {
//convert Mat to Bitmap
bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgba, bmp);
//scale down Bitmap
final Bitmap scaledBmp = Bitmap.createScaledBitmap(bmp, bmp.getWidth()/2, bmp.getHeight()/2, false);
//issue - this is going to create a Runnable for each frame
Runnable runnable = new Runnable() {
#Override
public void run() {
ftp.writeImageToFTP(scaledBmp);
}
};
new Thread(runnable).start();
}
catch(Exception ex) {
Log.i(TAG, "Exception onCameraFrame");
}
}
return mRgba;
}
}
FTPImage Class:
public class FTPImage {
private FTPClient ftpClient = null;
public String connectToFTP(String ftpIP) {
ftpClient = new FTPClient();
String reply = "";
try {
ftpClient.connect(InetAddress.getByName(ftpIP));
if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
ftpClient.disconnect();
}
ftpClient.enterLocalPassiveMode();
ftpClient.login("anonymous", "");
reply = ftpClient.getReplyString();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
}
catch (IOException ex)
{ }
}
e.printStackTrace();
}
return reply;
}
public void writeImageToFTP(Bitmap b) {
if (ftpClient != null) {
if (ftpClient.isConnected()) {
try {
boolean res = ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
b.compress(CompressFormat.PNG, 100, stream);
BufferedInputStream buffIn = new BufferedInputStream(
new ByteArrayInputStream(stream.toByteArray()));
res = ftpClient.storeFile("testImg.jpg", buffIn);
//when res returns, storeFile has finished uploading
String reply = ftpClient.getReplyString();
buffIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void disconnectFromFTP() {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
How can I pass each camera frame to a single, separate, running thread which then sends out that frame to a FTP server?
I hope that makes sense... just having trouble with the threading part. Thank you in advance!

I have tried to add Thread UploadThread here :
public class FdActivity extends Activity implements CvCameraViewListener2 {
private FTPImage ftp;
// declaration
private UploadThread mUploadThread;
private Handler mUploadHandler;
public static int UPLOAD_IMAGE = 11;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// initialization
mUploadThread = new UploadThread(this);
mUploadThread.start();
//connect to FTP server
ftp = new FTPImage();
Runnable runnable = new Runnable() {
#Override
public void run() {
String ftpResult = ftp.connectToFTP(config.getFtpIP());
}
};
new Thread(runnable).start();
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
if (isRecordFrames) {
Bitmap bmp;
try {
//convert Mat to Bitmap
bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgba, bmp);
//scale down Bitmap
final Bitmap scaledBmp = Bitmap.createScaledBitmap(bmp, bmp.getWidth()/2, bmp.getHeight()/2, false);
Message msg = Message.obtain();
msg.what = UPLOAD_IMAGE;
mUploadHandler.sendMessage(msg); // this way we send message to upload thread queue
}
catch(Exception ex) {
Log.i(TAG, "Exception onCameraFrame");
}
}
return mRgba;
}
Thread UploadThread = new Thread() {
private Context;
public UploadThread(Context context) {
this.context = context;
}
#Override
public void run() {
Looper.prepare();
mUploadHandler = new Handler() {
public void handleMessage(msg) {
case UPLOAD_IMAGE:
ftp.writeImageToFTP(scaledBmp); // uploading
break;
}
}
Looper.loop();
}
};

Related

How to update UI elements from a background thread in Android?

I implemented a custom Android camera using the camera2 api and when I click capture button I save the captured image to my phone eternal storage.
Now I needed to show a popup to enter the picture name before saving it and this popup has an imageView to show the captured image.
Even though I am loading the image from the Main thread I am getting this error
"Only the original thread that created a view hierarchy can touch its views"
Here is the code
private void initPopup(final Bitmap bitmap) {
popAddName = new Dialog(this);
popAddName.setContentView(R.layout.popup_add_name);
popAddName.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popAddName.getWindow().setLayout(Toolbar.LayoutParams.MATCH_PARENT, Toolbar.LayoutParams.WRAP_CONTENT);
popAddName.getWindow().getAttributes().gravity = Gravity.TOP;
popup_add = popAddName.findViewById(R.id.popup_add);
popup_img = popAddName.findViewById(R.id.popup_img);
popup_name = popAddName.findViewById(R.id.popup_name);
Thread thread = new Thread() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
Picasso.with(getApplicationContext()).load(getImageUri(getApplicationContext(), bitmap)).placeholder(R.drawable.placeholder).into(popup_img);
}
});
}
};
thread.start();
}
Here is the method to convert Bitmap to Uri for Picasso loading
public Uri getImageUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
This is the capture method
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader imageReader) {
Image image = null;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
//CONVERTION BYTES[] TO BITMAP
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
//create a new folder in external storage directory
String lorealFolder = "coffretPics";
File f = new File(Environment.getExternalStorageDirectory(), lorealFolder);
if (!f.exists()) {
f.mkdirs();
}
initPopup(bitmap);
popAddName.show();
file = new File(Environment.getExternalStorageDirectory() + "/" + lorealFolder + "/" + UUID.randomUUID().toString() + ".jpg");
save(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
{
if (image != null)
image.close();
}
}
}
private void save(byte[] bytes) throws IOException {
/* OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
outputStream.write(bytes);
} finally {
if (outputStream != null) {
outputStream.close();
}
}*/
}
};
Can someone please tell me what's the problem ?
Updated answer:
Create a class called AppExecutors
public class AppExecutors {
// For Singleton instantiation
private static final Object LOCK = new Object();
private static AppExecutors sInstance;
private final Executor diskIO;
private final Executor mainThread;
private final Executor networkIO;
private AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) {
this.diskIO = diskIO;
this.networkIO = networkIO;
this.mainThread = mainThread;
}
public static AppExecutors getInstance() {
if (sInstance == null) {
synchronized (LOCK) {
sInstance = new AppExecutors(Executors.newSingleThreadExecutor(),
Executors.newFixedThreadPool(3),
new MainThreadExecutor());
}
}
return sInstance;
}
public Executor diskIO() {
return diskIO;
}
public Executor mainThread() {
return mainThread;
}
public Executor networkIO() {
return networkIO;
}
private static class MainThreadExecutor implements Executor {
private Handler mainThreadHandler = new Handler(Looper.getMainLooper());
#Override
public void execute(#NonNull Runnable command) {
mainThreadHandler.post(command);
}
}
And get the main thread like:
AppExecutors.getInstance().mainThread().execute(new Runnable() {
#Override
public void run() {
// Do the work on UI thread here.
}
});
That should fix your problem.

How to download a file after clicking a button (Android Studio)

I recently created an activity in my app. Now I wanted the user to download a .pdf file when he/she wants to view the guidelines. I wanted to implement this on a button. Any idea how to do this properly?
Heres my code below:
public class Exhibitor_Registration_Activity extends AppCompatActivity {
Button buttonDownload;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exhibitor_registration_);
this.setTitle("Buyer Registration");
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
myToolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp);
final Button buttonDownload = (Button) findViewById(R.id.buttonDownload);
buttonDownload.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
try {
//this is the file you want to download from the remote server
String path ="http://www.manilafame.com/website-assets/downloads/exhibitor-application-kit/local/201704/1-Summary-of-Participation-Details-April-2017_MN_002.pdfp";
//this is the name of the local file you will create
String targetFileName = null;
boolean eof = false;
URL u = new URL(path);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
FileOutputStream f = new FileOutputStream(new File("c:\\junk\\"+targetFileName));
InputStream in = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ( (len1 = in.read(buffer)) > 0 ) {
f.write(buffer,0, len1);
}
f.close();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
I also got the source code from here and here.
if you want resumable, speed of download ...
follow this steps
create a class DownloadManager.java
public class DownloadManager extends AsyncTask<String,String,String>{
String downloadlink,fileDestination;
public static final int ON_INIT=100,ON_ERROR=102,ON_PROGRASS=103,ON_COMPLETED=104,STATUS_DOWNLOADED=1500,STATUS_NOT_YET=1501;
private onUpdateListener onUpdateListener;
private String downloadedPath="";
private long downloaded=0;
private File file;
private String returnData=null;
private File cacheDownloadFile;
public DownloadManager(String downloadlink,String fileDestinationPath){
this.downloadlink=downloadlink;
this.fileDestination=fileDestinationPath;
file=new File(fileDestination, Tools.getFileName(downloadlink));
cacheDownloadFile=new File(AppCostants.CHACHE_PATH+Tools.getFileName(downloadlink));
try {
if(cacheDownloadFile.isFile())
downloaded=Tools.getFileSize(cacheDownloadFile);
else
downloaded=0;
Log.d("FILE_DOWNLOAD_TAG_p",downloaded+" <- "+cacheDownloadFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
fireOnUpdate(ON_INIT,"init ...");
}
#Override
protected String doInBackground(String... params) {
try {
File dir=new File(fileDestination);
File chacheDir=new File(AppCostants.CHACHE_PATH);
if(!chacheDir.isDirectory())
chacheDir.mkdirs();
if(!dir.isDirectory()){
dir.mkdirs();
}
if(file.exists()) {
Log.d("FILE_DOWNLOAD_TAG","File exist return complete");
return "COMPLETED";//file exist
}
if(!cacheDownloadFile.exists()){
cacheDownloadFile.createNewFile();
}
Log.d("FILE_DOWNLOAD_TAG","LINK "+downloadlink);
URL url=new URL(downloadlink);
HttpURLConnection urlConnection= (HttpURLConnection) url.openConnection();
if(downloaded>0)
urlConnection.setRequestProperty("Range","byte="+downloaded);
urlConnection.connect();
int status = urlConnection.getResponseCode();
InputStream inputStream=urlConnection.getInputStream();
int totalSize=urlConnection.getContentLength();
if(totalSize<=downloaded){
returnData= "COMPLETED";
publishProgress("File checked "+Tools.getFileName(file.getAbsolutePath()));
return returnData;
}
this.downloadedPath=cacheDownloadFile.getAbsolutePath();
byte[] buffer=new byte[1024];
int bufferLength=0;
FileOutputStream fileOutput=new FileOutputStream(cacheDownloadFile);
long d=0;
long starttime=System.currentTimeMillis();
while ((bufferLength=inputStream.read(buffer))>0){
fileOutput.write(buffer,0,bufferLength);
downloaded+=bufferLength;
d+=bufferLength;
//String l=" "+Tools.getFileName(file.getAbsolutePath())+" ( "+Tools.convertMemory(downloaded)+" / "+Tools.convertMemory(totalSize)+" )";
String l=" "+Tools.convertMemory(downloaded)+" / "+Tools.convertMemory(totalSize)+" ( "+getDownloadSpeed(starttime,d)+" )";
publishProgress(l);
if(downloaded>=totalSize){
break;
}
}
Log.d("FILE_DOWNLOAD_TAG","DWONLOADED TO "+downloadedPath+" ("+cacheDownloadFile.length()+")");
fileOutput.close();
if(Tools.fileCopy(file,cacheDownloadFile)){
Log.d("FILE_DOWNLOAD_TAG","file Copied, delete cache");
cacheDownloadFile.delete();
}
returnData="COMPLETED";
} catch (MalformedURLException e) {
returnData=null;
e.printStackTrace();
publishProgress(e.toString());
Log.d("###################",e+"");
} catch (IOException e) {
returnData=null;
e.printStackTrace();
publishProgress(e.toString());
}
return returnData;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
fireOnUpdate(ON_PROGRASS,values[0]);
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if(s!=null){
fireOnUpdate(ON_COMPLETED,downloadedPath);
}else{
fireOnUpdate(ON_ERROR,"Download failed");
}
}
public interface onUpdateListener{
void onUpdate(int code,String message);
}
public void setOnUpdateListener(onUpdateListener onUpdateListener){
this.onUpdateListener=onUpdateListener;
}
private void fireOnUpdate(int code,String message){
if(onUpdateListener!=null)
onUpdateListener.onUpdate(code,message);
}
private String getDownloadSpeed(long starttime,float totalDownloaded) {
long elapsedTime = System.currentTimeMillis() - starttime;
//byte :
float speed=1000f * totalDownloaded / elapsedTime;
return convert(speed);
}
private String convert(float value){
long kb=1024
,mb=kb*1024
,gb=mb*1024;
if(value<kb){
String speed=(value+"");
speed=speed.substring(0,speed.indexOf('.')+2);
return speed+" B/s";
}else if(value<mb){
value=value/kb;
String speed=(value+"");
speed=speed.substring(0,speed.indexOf('.'));
return (speed)+" KB/s";
}else if(value<gb){
value=(value/mb);
String speed=(value+"");
speed=speed.substring(0,speed.indexOf('.'));
return speed+" MB/s";
}
return "";
}
}
use this code in onClick()
DownloadManager downloadManager = new DownloadManager(url,filepath);
set event
downloadManager.setOnUpdateListener(new DownloadManager.onUpdateListener() {
#Override
public void onUpdate(int code, String message) {
if (code == DownloadManager.ON_COMPLETED) {
}
if(DownloadManager.ON_PROGRASS==code){}
}
});
start download by
downloadManager.execute();
lib setup
compile "commons-io:commons-io:+"
Tools.java
public static long getFileSize(File file) throws IOException {
FileOutputStream fileOutputStream=new FileOutputStream(file);
fileOutputStream.close();
return file.length();
}
public static boolean fileCopy(File dest,File source){
try {
FileUtils.copyFile(source,dest);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
It is really bad idea to download file in main thread.
Use separate Thread for this
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
//your downloading here
}
});
thread.start();
it`s better, but still not so good. There are some problems with it:
1) User know nothing about downloading
So better to show additional layout which overlays screen with progress bar, probably indeterminate if you want to write less code. Then after downloading is finished you just hide your layout.
You can use runOnUiThread inside run method in thread for it.
runOnUiThread(new Runnable() {
#Override
public void run() {
//just hide some popup
//or do what you want after downloading is finished
popupLayout.serVisibility(View.GONE);
}
});
2) If user will do action which re-creates activity/fragment (like changing screen orientaion) with running thread you will get memory leak and probably activity will not know about end of download.
There are few ways to solve this problem:
You can block screen orientation at this screen, at least while downloading. Probably easiest way in your case.
You can use downloading in foreground service. Its really good
practice, but you will have to learn about services.
You can try to interrupt downloading by calling thread.interrupt()
method in onDestroy of your Activity/Fragment
You can use something like rxJava/rxAndroid (so you don not use threads at all, but you need some time for learn rxJava)
UPD
About threads
Not so bad tutorial about threads in android
You can use AsyncTask instead of Thread, but I highly recommend to use threads especially for long operations.

Threads Streaming video

I have a Server in Java and a Client in Android. In Android I have an AsyncTask for the receive of the video continuous by the server and a Thread that read the video with the MediaPlayer.
I launch the MediaPlayer after 5s but only the receipt packets are read at the moment when the MediaPlayer is launched.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
vidSurface = (SurfaceView) findViewById(R.id.surfView);
ConcurrentLinkedDeque<OutputStream[]> list = new ConcurrentLinkedDeque<>();
Connexion connexion = new Connexion(list);
connexion.execute();
new Thread(new Task2(list)).start();
}
private class Connexion extends AsyncTask<Void, Void, Void> {
private ConcurrentLinkedDeque<OutputStream[]> list;
public Connexion(ConcurrentLinkedDeque<OutputStream[]> list) {
this.list = list;
}
#Override
protected Void doInBackground(Void... params) {
ConcurrentLinkedDeque<OutputStream[]> list = new ConcurrentLinkedDeque<>();
DownloadVideo dv = new DownloadVideo(list);
dv.connexion();
return null;
}
}
public void launchVideo() {
Thread.sleep(5000);
vidHolder = vidSurface.getHolder();
vidHolder.addCallback(this);
}
class Task2 implements Runnable {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
Log.d("1", "Thread2");
launchVideo();
}
});
}
Thanks a lot.
Download Video :
public void connexion() {
try {
client = new Socket(IP_SERVER, 9003); // Creating the server socket.
if (client != null) {
// Receive video
InputStream in = client.getInputStream();
OutputStream out[] = new OutputStream[1];
// Store on device
out[0] = new FileOutputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Movies/chrono2.mp4");
byte buf[] = new byte[1024];
int n;
while ((n = in.read(buf)) != -1) {
out[0].write(buf, 0, n);
//Adding last in the queue
list.addLast(out);
Log.d("byte" , "" + out);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

libGDX: How can I tell core game getIconImageUri() and use it as Image actor into my game

I created IGoogleServices interface on core project:
public interface IGoogleServices {
.....
public String getPlayerName();
}
Then I put the following code inside the implementaion method in MainActivity on android project:
private String name;
#Override
public String getPlayerName() {
runOnUiThread(new Runnable() {
public void run() {
name = Games.Players.getCurrentPlayer(_gameHelper.getApiClient()).getDisplayName();
}
});
return name;
}
This is simple way to tell MyGame the player name as a String:
lblPlayerName = new Label("" + googleServices.getPlayerName(), style);
stage.addActor(lblPlayerName);
BUT I can't do it in the image case.
In the same previous String case, I tried to do it in the image case:
private Uri imgUri;
#Override
public void requestImgProfile() {
runOnUiThread(new Runnable() {
public void run() {
imgUri = Games.Players.getCurrentPlayer(_gameHelper.getApiClient()).getIconImageUri();
ImageManager manager = ImageManager.create(MainActivity.this);
manager.loadImage(new ImageManager.OnImageLoadedListener() {
public void onImageLoaded(Uri arg0, Drawable drawable, boolean arg2) {
try {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
FileOutputStream out = new FileOutputStream(imagePath);;
out = openFileOutput(imgUri + ".png", Context.MODE_MULTI_PROCESS);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}, imgUri);
};
});
}
My imgUri is:
content://com.google.android.gms.games.background/images/26s5523b/2633
What is the class type (like String) which I can tell MyGame it and libGDX libraries can treat with it?
If you have an Image URI, you can get a Bitmap via:
Uri imgUri;
Bitmap bitmap = null;
try {
InputStream inputStream = getContentResolver().openInputStream(imgUri);
bitmap = BitmapFactory.decodeStream(inputStream);
} catch (FileNotFoundException e) {
}
This works whether it is a file:// URI or content:// URI.
Then use solutions such as this answer to convert the Bitmap into something usable by libGDX.

Returning a bitmap file from AsyncTask freezes UI thread

I have created a simple Activity. The activity is responsible for downloading data from parse.com database and populating a linear layout. In the process, I am dynamically creating the linear layout with TextViews and ImageViews according according to the content.
The problem is that, whenever I try to download an image, I use as AsyncTask Downloading class, which results in slowing down the UI thread! I am currently trying to return the bitmap file from the AsyncTask Image downloading class using: returnedBitmap = new LoadImage().execute(src).get(); which might be responsible for slowing down the UI thread. I have to do this because the caller method geneterImageView will return an imageview when it receives the bitmap file.
The complete Activity code:
public class MainActivity extends ActionBarActivity {
ArrayList<String> heightList = new ArrayList<String>();
ArrayList<String> reversedList = new ArrayList<String>();
ImageView imageView1;
Bitmap bitmap;
RelativeLayout parent_layout;
ParseObject user;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// imageView1 = (ImageView)findViewById(R.id.imageView1);
parent_layout = (RelativeLayout) findViewById(R.id.parent_layout);
login("xyz#xyz.com", "xyz");
}
private void loopThroughArrayAndAttach(){
LinearLayout llInner = new LinearLayout(this);
llInner.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
parent_layout.addView(llInner);
for (int i = 0; i < heightList.size(); i++) {
if (hasNoImagess(heightList.get(i)) == true) {
// No images.
TextView myText = geneterTextView(heightList.get(i));
llInner.addView(myText);
// geneterTextView(heightList.get(i));
} else {
ImageView myImage = geneterImageView(heightList.get(i));
llInner.addView(myImage);
// geneterImageView(heightList.get(i));
}
}
}
public static boolean hasNoImagess(String contents){
Document doc = Jsoup.parse(contents);
Element element = doc.body();
Elements elements = element.select("img");
if (elements.isEmpty()) {
return true;
} else {
return false;
}
}
public ImageView geneterImageView(String imgContent){
// Will need to run via background thread - like aysnc
// Extract the image file via jsoup
// Insert it into a imagevieww
// Inser that into a layout.
Log.d("IN IMAGE ", " " + imgContent);
Document doc = Jsoup.parse(imgContent);
Elements img = doc.getElementsByTag("img");
Bitmap returnedBitmap = null;
for (Element el : img) {
String src = el.absUrl("src");
System.out.println("src attribute is : " + src);
// new DownloadImageTask((ImageView)
// findViewById(R.id.imageView1)).execute(src);
try {
returnedBitmap = new LoadImage().execute(src).get();
// imageView1.setImageBitmap(returnedBitmap);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
ImageView iv = new ImageView(this);
iv.setImageBitmap(returnedBitmap);
return iv;
}
public TextView geneterTextView(String textContent){
// Will need to run via background thread.
Log.i("In TEXT ", " " + textContent);
TextView tv = new TextView(this);
tv.setText(Html.fromHtml(textContent));
return tv;
}
// to download images
private class LoadImage extends AsyncTask<String, String, Bitmap> {
#Override
protected void onPreExecute(){
super.onPreExecute();
}
protected Bitmap doInBackground(String... args){
try {
bitmap = BitmapFactory.decodeStream((InputStream) new URL(args[0]).getContent());
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
protected void onPostExecute(Bitmap image){
if (image != null) {
} else {
Toast.makeText(MainActivity.this, "Image Does Not exist or Network Error", Toast.LENGTH_SHORT).show();
}
}
}
// to login to parse
private void login(final String username, String password){
ParseUser.logInInBackground(username, password, new LogInCallback() {
#Override
public void done(ParseUser user, ParseException e){
if (e == null) {
// if login sucess
// Start intent
// loginSuccess();
Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_SHORT).show();
CloudCallStudentPosts(user);
} else {
Toast.makeText(MainActivity.this, "Failure", Toast.LENGTH_SHORT).show();
}
}
});
}
// //to get data from parse
public void CloudCallStudentPosts(ParseObject s){
setRichStory(s);
}
private void setRichStory(ParseObject s){
// Simialr to setStory, once implemented delete setStory()
new AddStoryAsync(s).execute();
}
class AddStoryAsync extends AsyncTask<Void, Object, Void> {
private static final String TAG = "LazyListView";
ParseObject s;
public AddStoryAsync(ParseObject s) {
this.s = s;
Log.w("In richStory", "ParseObject Id: " + s.getObjectId());
}
#Override
protected void onPreExecute(){
}
#Override
protected Void doInBackground(Void... unused){
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("userid", this.s.getObjectId());
params.put("skip", 0);
ParseCloud.callFunctionInBackground("studentsPosts", params, new FunctionCallback<List<List<ParseObject>>>() {
#Override
public void done(List<List<ParseObject>> postList, com.parse.ParseException arg1){
if (postList == null) {
} else {
if (postList.size() > 0) {
// CustomWebView cwb;
for (int i = 0; i < postList.size(); i++) {
// final Post post = new Post();
if (postList.get(i).get(0).get("htmlContent") == null) {
}
if (postList.get(i).get(0).get("htmlContent") != null) {
Log.e("htmlContent parse", postList.get(i).get(0).get("htmlContent").toString());
// Parse HTML String using JSoup library
String HTMLSTring = postList.get(i).get(0).get("htmlContent").toString();
Document html = Jsoup.parse(HTMLSTring);
Elements paragraphs = html.getElementsByTag("p");
for (org.jsoup.nodes.Element paragraph : paragraphs) {
String paragraphText = paragraph.toString();
Log.e("paragraphText", paragraphText);
heightList.add(paragraphText);
}
loopThroughArrayAndAttach();
}
}
}
}
}
});
return (null);
}
#Override
protected void onProgressUpdate(Object... object){
Log.w("onProgressUpdate ", " " + object[0].getClass());
Log.w("adding to arrayPostList ", " " + object[0].getClass());
}
#Override
protected void onPostExecute(Void unused){
}
}
}
Is there any substitute for getting the bitmap from the AsyncTask and set it in the imageview? Should there be a logical alteration in the approach?
try this :
dont call get() #praveen. instead pass the imageview Reference in the constructor
WorkerThread mWorkerThread = new WorkerThread(mImageView);
mWorkerThread.execute(src);
private class WorkerThread extends AsyncTask<String, String, Bitmap> {
private WeakReference<ImageView> imageViewReference;
public WorkerThread(ImageView imageView) {
super();
imageViewReference = new WeakReference<ImageView>(imageView);
}
#Override
protected Bitmap doInBackground(String... args) {
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream((InputStream) new URL(args[0]).getContent());
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (result != null && imageViewReference.get() != null) {
imageViewReference.get().setImageBitmap(result);
}
}
}
Don't call get() method on AsyncTask it makes main thread to wait for AsyncTask to complete. If you really want to start something only after AsyncTask completes put that into onPostExecute() of your AsynTask
As others have mentioned, your code has several design flaws which makes it difficult to provide you a solution to your problem.
The whole purpose of an AsyncTask is to execute on a background thread. Executing networking and bitmap processing on the main thread will never work. You must refactor your code to accommodate this. Consider the following solution to this particular problem at least:
// to download images
private class LoadImage extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... args) {
String imgContent = args[0];
Document doc = Jsoup.parse(imgContent);
Elements img = doc.getElementsByTag("img");
for (Element el : img) {
String src = el.absUrl("src");
System.out.println("src attribute is : " + src);
try {
return BitmapFactory.decodeStream((InputStream) new URL(src).getContent());
} catch (Exception e) {
// log
}
}
return null;
}
protected void onPostExecute(Bitmap b) {
ImageView iv = new ImageView(MainActivity.this);
iv.setImageBitmap(b);
llInner.addView(iv);
}
}
You can then do something like:
for (int i = 0; i < heightList.size(); i++) {
new LoadImage(heightList.get(i)).execute();
}
However, this may not be desirable depending on how many AsyncTasks you end up creating. But this is the idea.

Categories

Resources