Android Handler Message to Main Activity from FileObserver Issue

1.3k Views Asked by At

I am new to android and this is my first project and have gotten a little stuck with the Handlers and FileObservers. The app will observe a folder on the file system and when files are modified, the new image inside the folder will be displayed on the UI.

At the moment the code doesn't break but I have been left scratching my head as to why the Handler that I call in the FileObserver class only fires once.

If I remove the Handler call and modify multiple files in the watched folder the FileObserver picks up all the changes and logs the relevant messages.

But like mentioned previously the moment I allow the Handler to fire the FileObserver, it only picks up the first change to the watched folder and nothing subsequently.

Main Activity

private static ImageView imgMAX;
private static ImageView imgMIN;

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

    imgMAX = (ImageView)findViewById(R.id.imageViewMAX);
    imgMIN = (ImageView)findViewById(R.id.imageViewMIN);
    vidAD = (VideoView)findViewById(R.id.videoViewAD);

    //Sorting out media player playback options
            MediaPlayer.OnPreparedListener PreparedListener = new MediaPlayer.OnPreparedListener(){

                 @Override
                 public void onPrepared(MediaPlayer m) {
                     try {
                            if (m.isPlaying()) {
                                m.stop();
                                m.release();
                                m = new MediaPlayer();
                            }
                            m.setVolume(0f, 0f);
                            m.setLooping(true);
                            m.start();
                        } catch (Exception e) {
                            e.printStackTrace();
                        } 
                 }
             };

    //Set up media controller for videos
    MediaController mediaController = new MediaController(this);
    mediaController.setAnchorView(vidAD);
    vidAD.setMediaController(new MediaController(this));
    vidAD.setOnPreparedListener(PreparedListener);

    //Create Message Handler
     handler = new Handler(Looper.getMainLooper()) 
     { 
        @Override
        public void handleMessage(Message msg) { 
              String type = msg.getData().getString("typeoperation"); 
              String path = msg.getData().getString("path"); 

              Log.d("MESSAGE HANDLER", "Message Recieved: "+ type + " " + path); 

              String splitchar = "/";
              String[] parts = path.split(splitchar);
              String file = parts[parts.length-1];

                  if (file.equals("min.jpg")){
                      Bitmap bmp = BitmapFactory.decodeFile(path);
                      imgMIN.setImageBitmap(bmp);

                      PathFileObserver pfo = new     PathFileObserver(filepath,handler); 
                      pfo.startWatching();  
                  } else if (file.equals("max.jpg")){
                      Bitmap bmp = BitmapFactory.decodeFile(path);
                      imgMAX.setImageBitmap(bmp);

                      PathFileObserver pfo = new PathFileObserver(filepath,handler); 
                      pfo.startWatching();  
                  } else if (file.equals("video.mp4")){
                      vidAD.stopPlayback();
                      vidAD.setVideoPath(path);
                      vidAD.requestFocus();
                      vidAD.start();
                  }
              } 
     }; 

    //Check if Storage is available
    if(isExternalStorageReadable()){
        filepath = Environment.getExternalStorageDirectory()+File.separator;
        File f = new File(Environment.getExternalStorageDirectory());
        if(f.exists()){
            Bitmap bmp = BitmapFactory.decodeFile(filepath+"max.jpg");
            imgMAX.setImageBitmap(bmp);

            bmp = BitmapFactory.decodeFile(filepath+"min.jpg");
            imgMIN.setImageBitmap(bmp);

            vidAD.setVideoPath(filepath+"video.mp4");
            vidAD.requestFocus();
            vidAD.start();

            PathFileObserver pfo = new PathFileObserver(filepath,handler); 
            pfo.startWatching(); 
        }else{
            new AlertDialog.Builder(this).setTitle("Error").setMessage("Error Loading Content.").setNeutralButton("Close", null).show();
        }   
    }
}

FileObserver

public class PathFileObserver extends FileObserver{
static final String TAG="FILEOBSERVER";
String rootPath;

static final int mask = (FileObserver.CREATE | 
        FileObserver.DELETE | 
        FileObserver.DELETE_SELF |
        FileObserver.MODIFY |
        FileObserver.MOVED_FROM |
        FileObserver.MOVED_TO |
        FileObserver.MOVE_SELF |
        FileObserver.CLOSE_WRITE);
private Handler handler; 

public PathFileObserver(String root,Handler handler){
    super(root, mask);

    if (! root.endsWith(File.separator)){
        root += File.separator;
    }
    rootPath = root;
    this.handler = handler;
}

public void onEvent(int event, String path) {

    Message msg = Message.obtain(handler); 
    Bundle b = new Bundle(); 

    switch(event){
    case FileObserver.CREATE:
        Log.d(TAG, "CREATE:" + rootPath + path);
        break;
    case FileObserver.DELETE:
        Log.d(TAG, "DELETE:" + rootPath + path);
        break;
    case FileObserver.DELETE_SELF:
        Log.d(TAG, "DELETE_SELF:" + rootPath + path);
        break;
    case FileObserver.MODIFY:
        Log.d(TAG, "MODIFY:" + rootPath + path);
        break;
    case FileObserver.MOVED_FROM:
        Log.d(TAG, "MOVED_FROM:" + rootPath + path);
        break;
    case FileObserver.MOVED_TO:
        Log.d(TAG, "MOVED_TO:" + path);
        break;
    case FileObserver.MOVE_SELF:
        Log.d(TAG, "MOVE_SELF:" + path);
        break;
    case FileObserver.CLOSE_WRITE:
        Log.d(TAG, "CLOSE_WRITE:" + path);

            b.putString("typeoperation","CLOSE_WRITE"); 
            b.putString("path",rootPath + path); 
            msg.setData(b); 
            handler.sendMessage(msg); 

        break;
    default:
        // just ignore
        break;
    }

}

public void close(){
    super.finalize();
}
}

EDIT

So after some more development and working on a video view I discovered that by changing the onevent in the FileObserver to:

case FileObserver.CLOSE_WRITE:
        Log.d(TAG, "CLOSE_WRITE:" + path);

            b.putString("typeoperation","CLOSE_WRITE"); 
            b.putString("path",rootPath + path); 
            msg.setData(b); 
            handler.sendMessage(msg); 

        break;

And filling in code on my Handler for the VideoView to:

else if (file.equals("video.mp4")){
  Toast.makeText(getBaseContext(), "Buffering New Video...", Toast.LENGTH_LONG).show();
      vidAD.stopPlayback();
          vidAD.setVideoPath(path);
          vidAD.requestFocus();
          vidAD.start();
}

When a new video is loaded into the folder and picked up by the FileObserver it loads, the video as expected and then if I then try load an image immediately after the video the FileObserver picks up the new image immediately without having to create a instance of file observer.

0

There are 0 best solutions below