3

I have an Arraylist<image> image in class A.

I have an AsyncTask which is a separate file. In the AsyncTask, I populate an Arraylist<String> imagePaths, which is derived like this in doInBackground :

for (Image image: images) {
    imagePaths.add(getPath(image));
} 

I want to send imagePaths to class A, when do in background has finished. I want to do it without passing instance of class A into the AsyncTask. This is my code but I can't get imagePath from AsyncTask:

public class SellCarInformationActivity extends BaseActivity implements  
        OnWheelChangedListener,
        saveImageAsyncTaskListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Res.init(this);
        setContentView(R.layout.activity_sell_car_information);
        bimap = BitmapFactory.decodeResource(
                getResources(),
                R.drawable.icon_addpic_unfocused);
        PublicWay.activityList.add(this);
        parentView = getLayoutInflater().inflate(R.layout.activity_sell_car_information, null);
        setContentView(parentView);
        //hide editext key board when click other place
        mHideEditor=new HideEditorKeyboard(this);
        mHideEditor.setupUI(findViewById(R.id.sellCarInfromationId));
        carInformationDB=new CarInformationDB(this);
        carPictureUrlDB=new CarPictureUrlDB(this);
        Init();
        eventListener=this;





            }
        });
        mCarPublishBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCarInformation=new CarInformation();
                mCarInformation.setCarBrand(mBrandText.getText().toString());
                mCarInformation.setCarModel(mModelText.getText().toString());
                mCarInformation.setCarUsedHours(Integer.parseInt(mCarUsedHours.getText().toString()));
                mCarInformation.setCarSite(mSiteText.getText().toString());
                mCarInformation.setCarProducedYear(mCarProduceDateText.getText().toString());
                mCarInformation.setCarPrice(Double.parseDouble(mCarPrice.getText().toString()));
                mCarInformation.setCarUsedState(mCarStateText.getText().toString());
                mCarInformation.setCarUsedPurpose(mCarUsingPurposeText.getText().toString());
                mCarInformation.setCarUserDescriber(mCarDescriber.getText().toString());
                mCarInformation.setCarUserName(mCarUserName.getText().toString());
                mCarInformation.setCarUserPhone(mCarUserPhone.getText().toString());



                //ArrayList<Bitmap> selectedPictures;
                HashMap<String,Bitmap> nameAndPictures=new HashMap<String, Bitmap>();
                String pictureName;
                long j=0;
                for(int i=0;i<Bimp.tempSelectBitmap.size();i++){
                    nameAndPictures.clear();
                   Bitmap selectedPicture= Bimp.tempSelectBitmap.get(i).getBitmap();
                    //selectedPictures=new ArrayList<Bitmap>();
                    //selectedPictures.add(selectedPicture);
                    j=System.currentTimeMillis();
                    j++;

                    pictureName=mModelText.getText().toString()+j;
                    nameAndPictures.put(pictureName,selectedPicture);
                    mCarInformation.setCarPictureLocalName(pictureName);
                }

                long carID=carInformationDB.insertCarInformation(mCarInformation);

                mCarInformation.setCarId((int) carID);

               // SaveImageToMemory saveImageToMemory=new SaveImageToMemory(selectedPicture,pictureName,mCarInformation);
                SaveImageToMemory saveImageToMemory=new SaveImageToMemory(nameAndPictures,mCarInformation);
                saveImageToMemory.setEventListener(eventListener);
                saveImageToMemory.execute();

                storeImagePathstoDB(carID);
                Toast.makeText(SellCarInformationActivity.this,
                        "发布成功"+carInformationDB.getCarInformationByCarId(carID).getCarBrand()+
                                carInformationDB.getCarInformationByCarId(carID).getCarModel()
                        , Toast.LENGTH_SHORT).show();

            }
        });
    }

    public void storeImagePathstoDB(long caID) {
        long carID =caID ;
        userLoadPictureUrl=new UserLoadPictureUrl();
        userLoadPictureUrl.setCarId((int) carID);
        userLoadPictureUrl.setPictureUrl1(imagePaths.get(0));
        userLoadPictureUrl.setPictureUrl2(imagePaths.get(1));
        userLoadPictureUrl.setPictureUrl3(imagePaths.get(2));
        userLoadPictureUrl.setPictureUrl4(imagePaths.get(3));
        userLoadPictureUrl.setPictureUrl5(imagePaths.get(4));
        userLoadPictureUrl.setPictureUrl6(imagePaths.get(5));
        userLoadPictureUrl.setPictureUrl7(imagePaths.get(6));
        userLoadPictureUrl.setPictureUrl8(imagePaths.get(7));
        userLoadPictureUrl.setPictureUrl9(imagePaths.get(8));
        carPictureUrlDB.insertUserLoadPictureUrl(userLoadPictureUrl);
        carPictureUrlDB.getUserLoadPictureUrlByCarId(carID);
    }


public class SaveImageToMemory extends AsyncTask< HashMap<String,Bitmap>, Void, ArrayList<String> > {
   Bitmap image;
    String imageName;
    String imagePath;
    CarInformation carInformation;
    HashMap<String,Bitmap> nameAndPicture;
    private Context context = null;
    private ArrayList<String> storePictureUrl;
    private saveImageAsyncTaskListener eventListener;
    private ArrayList<String> imagePaths;
    public SaveImageToMemory(HashMap<String,Bitmap> nameAndPicture, CarInformation carInformation) {
        super();
       // this.image = image;
       // this.imageName = imageName;
        this.carInformation = carInformation;
        this.nameAndPicture=nameAndPicture;
    }

    @Override
    protected ArrayList<String> doInBackground(HashMap<String,Bitmap>... params) {
        HashMap<String,Bitmap> nameAndPicture=params[0];
        imagePaths = new ArrayList<String>();
        storePictureUrl= new ArrayList<>();
        for(Map.Entry<String,Bitmap> entry :nameAndPicture.entrySet()){
             imageName=entry.getKey();
             image=entry.getValue();
            imagePath = saveImageInternalMemory(image, imageName);
            imagePaths.add(imagePath+ "/" +imageName);
        }


        return imagePaths;
    }

    @Override
    protected void onPostExecute(ArrayList<String> result) {
        Log.d("News reader", "Feed downloaded");
        eventListener.onImagePathsReady(imagePaths);
       // carInformation.setCarPictureLocalUrl(imagePath);
       // saveToDatabase(carInformation, imagePath);
    }

    public String saveImageInternalMemory (Bitmap bitmapImage, String imageName){
        ContextWrapper cw = new ContextWrapper(AppController.getInstance().getApplicationContext());
        // path to /data/data/yourapp/app_data/imageDir
        File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
        // Create imageDir
        File mypath=new File(directory, imageName);
        FileOutputStream fos = null;
        try {

            fos = new FileOutputStream(mypath);
            // Use the compress method on the BitMap object to write image to the OutputStream
            bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
            fos.close();


        } catch (Exception e) {
            e.printStackTrace();
        }
        return directory.getAbsolutePath();
    }

    public void setEventListener(saveImageAsyncTaskListener listener){
        this.eventListener=listener;
    }

}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Gang Luo
  • 51
  • 6
  • 1
    Did you tried using an `Interface`?? – Emil Aug 27 '15 at 05:18
  • What's the problem with passing an instance of class A into the async task? – Nir Alfasi Aug 27 '15 at 05:28
  • 2
    possible duplicate of [How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?](http://stackoverflow.com/questions/12575068/how-to-get-the-result-of-onpostexecute-to-main-activity-because-asynctask-is-a) – Emil Aug 27 '15 at 05:33

2 Answers2

2

The best way to do this by using custom events. An event need to fire in your class A when the async task has finished creating the ArrayList<String> imagePaths .

Custom events can be created in android using interfaces.

This should be class A

Class A  implements MyAsyncTaskListenerInterface{

 private ArrayList<image> images = getImages();  // array with 9 images
 private ArrayList<String> imagePaths; // array to store image 9 paths

 private void someMethod() {
   MyAsyncTask asyncTask = new AsyncTask();
   asyncTask.setEventListener(this);
   asyncTask.execute(images);
 }

 @Override
 onPathsReady(ArrayList<String> paths) {
  this.imagepaths =  paths;
 }

}

This should be MyAsyncTask

public MyAsyncTask extends Asynctask<ArrayList<image>, Void, Void> {
   private MyAsyncTaskListenerInterface eventListener;

   @Override
   DoInBackground(ArrayList<image>... params) {
     ArrayList<Image> images = params[0];
     ArrayList<String> imagePaths = new ArrayList<String>();

     for (Image image : images) {
       String path = getImagePath(image);
       imagePaths.add(path);
     } 
    eventListener.onPathsReady(imagePaths); 
  }

  public void setEventListener(MyAsyncTaskListenerInterface listener) {
    this.eventListener = listener;
  }

  private String getImagePath(Image image) {
    // your code
  }
}

Now, create the an interface like this MyAsyncTaskListenerInterface

public interface MyAsyncTaskListenerInterface {
  void onPathsReady(ArrayList<String> paths);
}

It is good practice to create a separate file for the interface.

In the DoInBackground the event is fired after the paths array is made and passed into the event.

Class A is set as the listener for the event and the onPathsReady(ArrayList<String> paths) method fires and you can assign the value in that method as shown.

Using interfaces and firing custom events is a great way to make your code very clean and makes better utilisation of the features of java.

rgv
  • 1,186
  • 1
  • 17
  • 39
  • you answer is very clear ,if can i don't use the interface ,just using callback method ,like in class A ,i write a method :Public void getTheImagePaths(ArrayList imagePaths){this.imagePaths=imagePaths},then i class Async ,i using class A object call the getTheImagePaths(imagePaths),and passing the imagePath to the method,that i can get the ImagePaths in class A – Gang Luo Aug 27 '15 at 14:54
  • You can do that, but there are few problems to doing it that way, like these: 1) It is very bad code. You have a separate Async task class because you want to make it reusable, but if you have to pass an object of class `A`, only class `A` can use Async task class. Also, I believe that why you asked in your question that you want a way to do it without passing an instance of class `A` into async task. you should use interfaces because that is the best way to do it. Interfaces are a bit confusing at first, but keep writing code by copying this code and you'll figure it out later, how it works. – rgv Aug 27 '15 at 15:34
  • asyncTask.setEventListener(this);what is "this"? – Gang Luo Aug 27 '15 at 16:22
  • `this` keyword in java means the instance of that class. So when you say `this` inside class `A`, that instance of class A is passed. – rgv Aug 27 '15 at 17:47
  • you have defined setEventListener(MyAsyncTaskListenerInterface listener) argument is MyAsyncTaskListenerInterface,though "this" is that class A instance.i am using your answer ,but have not get the result – Gang Luo Aug 27 '15 at 18:20
  • when a class implements an interface, that class pass as a type of that interface. So instance of any class that implements `MyAsyncTaskListenerInterface` can be passed into this method. What do you mean by does not get result? Debug and specify the exact issue. – rgv Aug 27 '15 at 18:39
0

I guess all nou need is already answered in SO (I place a link at the bottom of my answer):

(What the answer says is that you should have a class that extends AsynkTask and call to the execute method and in that class implement doInBackgorund that returns what you need, in your case a list of url's)

// This method is not called directly. 
 // It is fired through the use of execute()
 // It returns the third type in the brackets <...>
 // and it is passed the first type in the brackets <...>
 // and it can use the second type in the brackets <...> to track progress
 protected Long doInBackground(URL... urls) 
 {
         int count = urls.length;
         long totalSize = 0;

         // This will download stuff from each URL passed in
         for (int i = 0; i < count; i++) 
         {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
         }

         // This will return once when all the URLs for this AsyncTask instance
         // have been downloaded
         return totalSize;
 }

But, please, take a look to the entire answer:

How to pass variables in and out of AsyncTasks?

Community
  • 1
  • 1
Juan
  • 2,156
  • 18
  • 26