Showing posts with label Android code sample: AsyncTask. Show all posts
Showing posts with label Android code sample: AsyncTask. Show all posts

Monday, June 19, 2017

Examples of ProgressBar and AsyncTask


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="20dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidprogressbar.MainActivity">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"
        />

    <Button
        android:id="@+id/startprogress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start ProgressBar"/>

    <ProgressBar
        android:id="@+id/indeterminateBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone" />

    <ProgressBar
        android:id="@+id/determinateBar1"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:progress="0"
        android:visibility="gone"/>
    <ProgressBar
        android:id="@+id/determinateBar2"
        style="@android:style/Widget.ProgressBar.Inverse"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"/>
    <ProgressBar
        android:id="@+id/determinateBar3"
        style="@android:style/Widget.ProgressBar.Large"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"/>
    <ProgressBar
        android:id="@+id/determinateBar4"
        style="@android:style/Widget.ProgressBar.Large.Inverse"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"/>
    <ProgressBar
        android:id="@+id/determinateBar5"
        style="@android:style/Widget.ProgressBar.Small"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"/>
    <ProgressBar
        android:id="@+id/determinateBar6"
        style="@android:style/Widget.ProgressBar.Small.Inverse"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"/>
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@mipmap/ic_launcher"/>
</LinearLayout>



package com.blogspot.android_er.androidprogressbar;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;

public class MainActivity extends AppCompatActivity {

    Button btnStartProgress;
    ProgressBar indeterminateBar;
    ProgressBar determinateBar1, determinateBar2, determinateBar3,
                determinateBar4, determinateBar5, determinateBar6;

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

        btnStartProgress = (Button)findViewById(R.id.startprogress);
        indeterminateBar = (ProgressBar)findViewById(R.id.indeterminateBar);
        determinateBar1 = (ProgressBar)findViewById(R.id.determinateBar1);
        determinateBar2 = (ProgressBar)findViewById(R.id.determinateBar2);
        determinateBar3 = (ProgressBar)findViewById(R.id.determinateBar3);
        determinateBar4 = (ProgressBar)findViewById(R.id.determinateBar4);
        determinateBar5 = (ProgressBar)findViewById(R.id.determinateBar5);
        determinateBar6 = (ProgressBar)findViewById(R.id.determinateBar6);

        btnStartProgress.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                btnStartProgress.setEnabled(false);
                MyAsyncTask myAsyncTask = new MyAsyncTask();
                myAsyncTask.execute();
            }
        });
    }

    public class MyAsyncTask extends AsyncTask<Void, Integer, Void> {

        @Override
        protected void onPreExecute() {
            indeterminateBar.setVisibility(View.VISIBLE);
            determinateBar1.setVisibility(View.VISIBLE);
            determinateBar1.setProgress(0);
            determinateBar2.setVisibility(View.VISIBLE);
            determinateBar3.setVisibility(View.VISIBLE);
            determinateBar4.setVisibility(View.VISIBLE);
            determinateBar5.setVisibility(View.VISIBLE);
            determinateBar6.setVisibility(View.VISIBLE);
        }

        @Override
        protected Void doInBackground(Void... voids) {
            for(int i=0; i<100; i++){
                publishProgress(i);
                SystemClock.sleep(100);
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            determinateBar1.setProgress(values[0]);
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            indeterminateBar.setVisibility(View.GONE);
            determinateBar1.setVisibility(View.GONE);
            determinateBar2.setVisibility(View.GONE);
            determinateBar3.setVisibility(View.GONE);
            determinateBar4.setVisibility(View.GONE);
            determinateBar5.setVisibility(View.GONE);
            determinateBar6.setVisibility(View.GONE);
            btnStartProgress.setEnabled(true);
        }
    }
}


Next:
Custom ProgressBar with progressDrawable
Add ProgressBar in ToolBar
ProgressBar with SecondaryProgress
Custom ProgressBar with SecondaryProgress
Question of using ContentLoadingProgressBar

Tuesday, March 29, 2016

Load something from Internet using URLConnection and BufferedReader, in AsyncTask

Here is example to load something from Internet using URLConnection and BufferedReader, in AsyncTask.

MainActivity.java
package com.blogspot.android_er.androidinternet;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

import org.w3c.dom.Text;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class MainActivity extends AppCompatActivity {

    TextView textResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textResult = (TextView)findViewById(R.id.tresult);

        MyAsyncTask myAsyncTask = new MyAsyncTask(textResult);
        myAsyncTask.execute("http://android-er.blogspot.com");
    }

    class MyAsyncTask extends AsyncTask<String, Void, String> {

        TextView textviewResult;

        public MyAsyncTask(TextView textviewResult) {
            super();
            this.textviewResult = textviewResult;
        }

        @Override
        protected String doInBackground(String... params) {
            String result = "";

            try {
                URL url = new URL(params[0]);
                URLConnection urlConnection = url.openConnection();
                InputStream inputStream = urlConnection.getInputStream();
                InputStreamReader inputStreamReader =
                        new InputStreamReader(inputStream);
                BufferedReader buffReader = new BufferedReader(inputStreamReader);

                String line;
                while ((line = buffReader.readLine()) != null) {
                    result += line;
                }

            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return result;
        }

        @Override
        protected void onPostExecute(String s) {
            textviewResult.setText(s);

            Toast.makeText(MainActivity.this,
                    "DONE", Toast.LENGTH_LONG).show();
            super.onPostExecute(s);
        }
    }
}


activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="com.blogspot.android_er.androidinternet.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <ScrollView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    <TextView
        android:id="@+id/tresult"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    </ScrollView>
</LinearLayout>


uses-permission of "android.permission.INTERNET" is needed in src/main/AndroidManifest.xml.


Add uses-permission of "android.permission.INTERNET" to AndroidManifest.xml

To access Internet in your app, you have to add uses-permission of "android.permission.INTERNET" to AndroidManifest.xml. Shown in this video:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.blogspot.android_er.androidinternet">

    <uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Related:
Load something from Internet using URLConnection and BufferedReader, in Thread

Thursday, March 24, 2016

AsyncTask vs Thread + Handler


This post show how to implement using AsyncTask and Thread/Handler to perform the same function: doing something in background and update UI elements (ProgressBar and TextView).

This video show how it run on Android Emulator running Android N, in Multi-Window.


AsyncTask

MainActivity.java
package com.blogspot.android_er.androidasynctask;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    Button btnStart;
    ProgressBar progressBar;
    TextView textMsg;

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

        progressBar = (ProgressBar)findViewById(R.id.progress);
        textMsg = (TextView)findViewById(R.id.msg);

        btnStart = (Button)findViewById(R.id.start);
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MyAsyncTask myAsyncTask = new MyAsyncTask(progressBar, textMsg);
                myAsyncTask.execute();
            }
        });
    }

    class MyAsyncTask extends AsyncTask<Void, Integer, Void>{

        ProgressBar pBar;
        TextView tMsg;

        public MyAsyncTask(ProgressBar pBar, TextView tMsg) {
            super();
            this.pBar = pBar;
            this.tMsg = tMsg;
        }

        @Override
        protected Void doInBackground(Void... params) {
            for(int i=0; i<=10; i++){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                publishProgress(i);
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            pBar.setProgress(values[0]);
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            tMsg.setText("finished");
        }
    }
}


layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidasynctask.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start"/>

    <ProgressBar
        android:id="@+id/progress"
        style="?android:attr/progressBarStyleHorizontal"
        android:indeterminate="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="10"
        android:progress="0"/>
    <TextView
        android:id="@+id/msg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>



Thread + Handler

MainActivity.java
package com.blogspot.android_er.androidthreadhandler;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import org.w3c.dom.Text;

public class MainActivity extends AppCompatActivity {

    Button btnStart;
    ProgressBar progressBar;
    TextView textMsg;

    private Handler handler = new Handler();

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

        progressBar = (ProgressBar)findViewById(R.id.progress);
        textMsg = (TextView)findViewById(R.id.msg);

        btnStart = (Button)findViewById(R.id.start);
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MyThread myThread = new MyThread(progressBar, textMsg);
                myThread.start();
            }
        });
    }

    class MyThread extends Thread{

        ProgressBar pBar;
        TextView tMsg;

        public MyThread(ProgressBar pBar, TextView tMsg) {
            super();
            this.pBar = pBar;
            this.tMsg = tMsg;
        }

        @Override
        public void run() {

            for (int i = 0; i <= 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //is accessed from within inner class, needs to be declared final
                final int finalI = i;
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        pBar.setProgress(finalI);
                    }
                });
            }

            handler.post(new Runnable() {
                @Override
                public void run() {
                    tMsg.setText("finished");
                }
            });
        }
    }
}


layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidthreadhandler.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start"/>

    <ProgressBar
        android:id="@+id/progress"
        style="?android:attr/progressBarStyleHorizontal"
        android:indeterminate="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="10"
        android:progress="0"/>
    <TextView
        android:id="@+id/msg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>



next:
- HandlerThread example

related:
Load something from Internet using URLConnection and BufferedReader, in AsyncTask
Load something from Internet using URLConnection and BufferedReader, in Thread


Friday, March 4, 2016

Too busy in background thread of AsyncTask

It's a following of the post "ProgressDialog and AsyncTask". I make the background process of the AsyncTask too busy by removing the Thread.sleep() inside doInBackground(). In such case, the system is too busy to update UI, even cannot update the ProgressBar animation!



The example code refer to the post "ProgressDialog and AsyncTask".

Tuesday, April 14, 2015

Auto dismiss popupWindow with AsyncTask

This example we will open PopupWindow together with a AsyncTask. Once the AsyncTask count for 10 seconds, it will dismiss the PopupWindow; to show how to dismiss PopupWindow outside itself.




/res/layout/popup.xml, the layout of the PopupWindow.
package com.example.androidpopupwindow;

import android.support.v7.app.ActionBarActivity;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;

public class MainActivity extends ActionBarActivity {

 LinearLayout mainLayout;
 ProgressBar progressBar;
 TextView msg;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mainLayout = (LinearLayout)findViewById(R.id.mainlayout);

  progressBar = (ProgressBar) findViewById(R.id.progressbar);
  msg = (TextView)findViewById(R.id.msg);
  
  final Button btnOpenPopup = (Button) findViewById(R.id.openpopup);
  btnOpenPopup.setOnClickListener(new Button.OnClickListener() {

   @Override
   public void onClick(View arg0) {
    LayoutInflater layoutInflater = (LayoutInflater) getBaseContext()
      .getSystemService(LAYOUT_INFLATER_SERVICE);
    View popupView = layoutInflater.inflate(R.layout.popup, null);
    final PopupWindow popupWindow = new PopupWindow(popupView,
      LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

    Button btnDismiss = (Button) popupView
      .findViewById(R.id.dismiss);
    btnDismiss.setOnClickListener(new Button.OnClickListener() {

     @Override
     public void onClick(View v) {
      // TODO Auto-generated method stub
      popupWindow.dismiss();
     }
    });
    
    TextView me = (TextView) popupView
      .findViewById(R.id.me);
    me.setText(popupWindow.toString());

    //Center the PopupWindow
    popupWindow.showAtLocation(mainLayout, Gravity.CENTER, 0, 0);

    //Auto dismiss PopupWindow in 10 sec
    new DismissAsyncTask(progressBar, msg, popupWindow).execute();
   }
  });
 }

 public class DismissAsyncTask extends AsyncTask<Void, Integer, Void> {

  ProgressBar taskProgressBar;
  TextView taskMsg;
  PopupWindow taskPopupWindow;

  public DismissAsyncTask(ProgressBar targetProgressBar,
    TextView targetMsg,
    PopupWindow targetPopupWindow) {
   taskProgressBar = targetProgressBar;
   taskMsg = targetMsg;
   taskProgressBar.setVisibility(View.VISIBLE);
   taskPopupWindow = targetPopupWindow;
  }

  @Override
  protected Void doInBackground(Void... params) {
   for (int i = 0; i < 10; i++) {
    publishProgress(i);
    SystemClock.sleep(1000);
   }
   return null;
  }

  @Override
  protected void onProgressUpdate(Integer... values) {
   taskProgressBar.setVisibility(View.VISIBLE);
   taskProgressBar.setProgress(values[0]);
   
   taskMsg.setText("Updated by : " 
    + taskPopupWindow.toString() 
    + " - " + values[0]);
  }

  @Override
  protected void onPostExecute(Void result) {
   Toast.makeText(MainActivity.this, 
    "Dismiss PopupWindows: " + taskPopupWindow.toString(), 
    Toast.LENGTH_LONG).show();
   
   taskProgressBar.setVisibility(View.INVISIBLE);
   taskPopupWindow.dismiss();
  }
 }

}

/res/layout/activity_main.xml, the layout of the main activity.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mainlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidpopupwindow.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/openpopup"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Open Popup Window" />
    
    <ProgressBar
        android:id="@+id/progressbar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:max="10"
        android:progress="0"
        android:visibility="invisible" />
    <TextView
        android:id="@+id/msg"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

MainActivity.java
package com.example.androidpopupwindow;

import android.support.v7.app.ActionBarActivity;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;

public class MainActivity extends ActionBarActivity {

 LinearLayout mainLayout;
 ProgressBar progressBar;
 TextView msg;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mainLayout = (LinearLayout)findViewById(R.id.mainlayout);

  progressBar = (ProgressBar) findViewById(R.id.progressbar);
  msg = (TextView)findViewById(R.id.msg);
  
  final Button btnOpenPopup = (Button) findViewById(R.id.openpopup);
  btnOpenPopup.setOnClickListener(new Button.OnClickListener() {

   @Override
   public void onClick(View arg0) {
    LayoutInflater layoutInflater = (LayoutInflater) getBaseContext()
      .getSystemService(LAYOUT_INFLATER_SERVICE);
    View popupView = layoutInflater.inflate(R.layout.popup, null);
    final PopupWindow popupWindow = new PopupWindow(popupView,
      LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

    Button btnDismiss = (Button) popupView
      .findViewById(R.id.dismiss);
    btnDismiss.setOnClickListener(new Button.OnClickListener() {

     @Override
     public void onClick(View v) {
      // TODO Auto-generated method stub
      popupWindow.dismiss();
     }
    });
    
    TextView me = (TextView) popupView
      .findViewById(R.id.me);
    me.setText(popupWindow.toString());

    //Center the PopupWindow
    popupWindow.showAtLocation(mainLayout, Gravity.CENTER, 0, 0);

    //Auto dismiss PopupWindow in 10 sec
    new DismissAsyncTask(progressBar, msg, popupWindow).execute();
   }
  });
 }

 public class DismissAsyncTask extends AsyncTask<Void, Integer, Void> {

  ProgressBar taskProgressBar;
  TextView taskMsg;
  PopupWindow taskPopupWindow;

  public DismissAsyncTask(ProgressBar targetProgressBar,
    TextView targetMsg,
    PopupWindow targetPopupWindow) {
   taskProgressBar = targetProgressBar;
   taskMsg = targetMsg;
   taskProgressBar.setVisibility(View.VISIBLE);
   taskPopupWindow = targetPopupWindow;
  }

  @Override
  protected Void doInBackground(Void... params) {
   for (int i = 0; i < 10; i++) {
    publishProgress(i);
    SystemClock.sleep(1000);
   }
   return null;
  }

  @Override
  protected void onProgressUpdate(Integer... values) {
   taskProgressBar.setVisibility(View.VISIBLE);
   taskProgressBar.setProgress(values[0]);
   
   taskMsg.setText("Updated by : " 
    + taskPopupWindow.toString() 
    + " - " + values[0]);
  }

  @Override
  protected void onPostExecute(Void result) {
   Toast.makeText(MainActivity.this, 
    "Dismiss PopupWindows: " + taskPopupWindow.toString(), 
    Toast.LENGTH_LONG).show();
   
   taskProgressBar.setVisibility(View.INVISIBLE);
   taskPopupWindow.dismiss();
  }
 }

}



Remark for AsyncTask:
- In this implementation, I haven't stop the AsyncTask if the PopupWindow dismissed by button. So the associated AsyncTask still run in background. I intentionally implement like this, to show the behavior of AsyncTask.
- Starting with HONEYCOMB, AsyncTask are executed on a single thread, that means one by one (read Run multi AsyncTask at the same time). If user start a PopupWindow A and AsyncTask A, and dismiss PopupWindow A with button, AsyncTask A still running. Then start PopupWindow B and AsyncTask B. It will wait AsyncTask A finished, then start AsyncTask B,...then finish, then dismiss PopupWindow B.

download filesDownload the files.

Saturday, February 7, 2015

ProgressDialog and AsyncTask

Example of ProgressDialog, work with AsyncTask.



package com.example.android_er.androidprogressdialog;

import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;


public class MainActivity extends ActionBarActivity {

    Button btnStart;

    MyAsyncTask myAsyncTask;

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

        btnStart=(Button)findViewById(R.id.start);
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this,
                        "- Start -",
                        Toast.LENGTH_LONG).show();

                myAsyncTask = new MyAsyncTask();
                myAsyncTask.execute();

            }
        });
    }

    class MyAsyncTask extends AsyncTask<Void, Integer, Void>{

        boolean running;
        ProgressDialog progressDialog;

        @Override
        protected Void doInBackground(Void... params) {
            int i = 10;
            while(running){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if(i-- == 0){
                    running = false;
                }

                publishProgress(i);

            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressDialog.setMessage(String.valueOf(values[0]));
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            running = true;

            progressDialog = ProgressDialog.show(MainActivity.this,
                    "ProgressDialog",
                    "Wait!");

            progressDialog.setCanceledOnTouchOutside(true);
            progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    running = false;
                }
            });

            Toast.makeText(MainActivity.this,
                    "Progress Start",
                    Toast.LENGTH_LONG).show();
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            Toast.makeText(MainActivity.this,
                    "Progress Ended",
                    Toast.LENGTH_LONG).show();

            progressDialog.dismiss();
        }

    }

}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start"/>

</LinearLayout>


more:
Too busy in background thread of AsyncTask

Wednesday, September 17, 2014

getView() to load images in AsyncTask

This post show getView() loading images in AsyncTask, to make UI responsive. Re-call my old "GridView example: load images to GridView from SD Card in background", it load the files in backgroud, to make the GridView start-up faster; but not in loading images in getView. Such that if the GridView going to load large images, it will block the UI in getView() and make the UI unresponsive.


The Android tutorial "Making ListView Scrolling Smooth" show how to improve getView() by loading images in AsyncTask.

The page advise to check (v.position == position) to varify if this item hasn't been recycled already. But it not work in this case. (actually, I don't understand how is the logic) In my implementation, roll-out images will be shown on incorrect cell, but the final images will replace and correct it finally.

To load images in AsyncTask will not speed up your image loading, but improve UI response.


MainActivity.java
package com.example.androidgridview;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity {
 
 AsyncTaskLoadFiles myAsyncTaskLoadFiles;

 public class AsyncTaskLoadFiles extends AsyncTask<Void, String, Void> {
  
  File targetDirector;
  ImageAdapter myTaskAdapter;

  public AsyncTaskLoadFiles(ImageAdapter adapter) {
   myTaskAdapter = adapter;
  }

  @Override
  protected void onPreExecute() {
   String ExternalStorageDirectoryPath = Environment
     .getExternalStorageDirectory().getAbsolutePath();

   String targetPath = ExternalStorageDirectoryPath + "/test/";
   targetDirector = new File(targetPath);
   myTaskAdapter.clear();
   
   super.onPreExecute();
  }

  @Override
  protected Void doInBackground(Void... params) {
   
   File[] files = targetDirector.listFiles();
   Arrays.sort(files);
   for (File file : files) {
    publishProgress(file.getAbsolutePath());
    if (isCancelled()) break;
   }
   return null;
  }

  @Override
  protected void onProgressUpdate(String... values) {
   myTaskAdapter.add(values[0]);
   super.onProgressUpdate(values);
  }

  @Override
  protected void onPostExecute(Void result) {
   myTaskAdapter.notifyDataSetChanged();
   super.onPostExecute(result);
  }

 }

 public class ImageAdapter extends BaseAdapter {

  private Context mContext;
  ArrayList<String> itemList = new ArrayList<String>();

  public ImageAdapter(Context c) {
   mContext = c;
  }

  void add(String path) {
   itemList.add(path);
  }
  
  void clear() {
   itemList.clear();
  }
  
  void remove(int index){
   itemList.remove(index);
  }

  @Override
  public int getCount() {
   return itemList.size();
  }

  @Override
  public Object getItem(int position) {
   // TODO Auto-generated method stub
   return itemList.get(position);
  }

  @Override
  public long getItemId(int position) {
   // TODO Auto-generated method stub
   return 0;
  }

  //getView load bitmap ui thread
  /*
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   ImageView imageView;
   if (convertView == null) { // if it's not recycled, initialize some
          // attributes
    imageView = new ImageView(mContext);
    imageView.setLayoutParams(new GridView.LayoutParams(220, 220));
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setPadding(8, 8, 8, 8);
   } else {
    imageView = (ImageView) convertView;
   }

   Bitmap bm = decodeSampledBitmapFromUri(itemList.get(position), 220,
     220);

   imageView.setImageBitmap(bm);
   return imageView;
  }
  */

  //getView load bitmap in AsyncTask
  @Override
  public View getView(final int position, View convertView, ViewGroup parent) {
   ViewHolder holder;

   ImageView imageView;
   if (convertView == null) { // if it's not recycled, initialize some
          // attributes
    imageView = new ImageView(mContext);
    imageView.setLayoutParams(new GridView.LayoutParams(220, 220));
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setPadding(8, 8, 8, 8);
    
    convertView = imageView;
    
    holder = new ViewHolder();
    holder.image = imageView;
    holder.position = position;
    convertView.setTag(holder);
   } else {
    //imageView = (ImageView) convertView;
    holder = (ViewHolder) convertView.getTag();
    ((ImageView)convertView).setImageBitmap(null);
   }
   
   //Bitmap bm = decodeSampledBitmapFromUri(itemList.get(position), 220, 220);
   // Using an AsyncTask to load the slow images in a background thread
   new AsyncTask<ViewHolder, Void, Bitmap>() {
       private ViewHolder v;

       @Override
       protected Bitmap doInBackground(ViewHolder... params) {
           v = params[0];
           Bitmap bm = decodeSampledBitmapFromUri(itemList.get(position), 220, 220);
           return bm;
       }

       @Override
       protected void onPostExecute(Bitmap result) {
           super.onPostExecute(result);
           //Not work for me!
           /*
           if (v.position == position) {
               // If this item hasn't been recycled already, 
            // show the image
               v.image.setImageBitmap(result);
           }
           */

           v.image.setImageBitmap(result);

       }
   }.execute(holder);

   //imageView.setImageBitmap(bm);
   //return imageView;
   return convertView;
  }

  public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth,
    int reqHeight) {

   Bitmap bm = null;
   // First decode with inJustDecodeBounds=true to check dimensions
   final BitmapFactory.Options options = new BitmapFactory.Options();
   options.inJustDecodeBounds = true;
   BitmapFactory.decodeFile(path, options);

   // Calculate inSampleSize
   options.inSampleSize = calculateInSampleSize(options, reqWidth,
     reqHeight);

   // Decode bitmap with inSampleSize set
   options.inJustDecodeBounds = false;
   bm = BitmapFactory.decodeFile(path, options);

   return bm;
  }

  public int calculateInSampleSize(

  BitmapFactory.Options options, int reqWidth, int reqHeight) {
   // Raw height and width of image
   final int height = options.outHeight;
   final int width = options.outWidth;
   int inSampleSize = 1;

   if (height > reqHeight || width > reqWidth) {
    if (width > height) {
     inSampleSize = Math.round((float) height
       / (float) reqHeight);
    } else {
     inSampleSize = Math.round((float) width / (float) reqWidth);
    }
   }

   return inSampleSize;
  }
  
  class ViewHolder {
            ImageView image;
            int position;
        }

 }

 ImageAdapter myImageAdapter;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  final GridView gridview = (GridView) findViewById(R.id.gridview);
  myImageAdapter = new ImageAdapter(this);
  gridview.setAdapter(myImageAdapter);

  /*
   * Move to asyncTaskLoadFiles String ExternalStorageDirectoryPath =
   * Environment .getExternalStorageDirectory() .getAbsolutePath();
   * 
   * String targetPath = ExternalStorageDirectoryPath + "/test/";
   * 
   * Toast.makeText(getApplicationContext(), targetPath,
   * Toast.LENGTH_LONG).show(); File targetDirector = new
   * File(targetPath);
   * 
   * File[] files = targetDirector.listFiles(); for (File file : files){
   * myImageAdapter.add(file.getAbsolutePath()); }
   */
  myAsyncTaskLoadFiles = new AsyncTaskLoadFiles(myImageAdapter);
  myAsyncTaskLoadFiles.execute();

  gridview.setOnItemClickListener(myOnItemClickListener);
  
  Button buttonReload = (Button)findViewById(R.id.reload);
  buttonReload.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    
    //Cancel the previous running task, if exist.
    myAsyncTaskLoadFiles.cancel(true);
    
    //new another ImageAdapter, to prevent the adapter have
    //mixed files
    myImageAdapter = new ImageAdapter(MainActivity.this);
    gridview.setAdapter(myImageAdapter);
    myAsyncTaskLoadFiles = new AsyncTaskLoadFiles(myImageAdapter);
    myAsyncTaskLoadFiles.execute();
   }});

 }

 OnItemClickListener myOnItemClickListener = new OnItemClickListener() {

  @Override
  public void onItemClick(AdapterView<?> parent, View view, int position,
    long id) {
   String prompt = "remove " + (String) parent.getItemAtPosition(position);
   Toast.makeText(getApplicationContext(), prompt, Toast.LENGTH_SHORT)
     .show();
   
   myImageAdapter.remove(position);
   myImageAdapter.notifyDataSetChanged();

  }
 };

}

/res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:orientation="vertical">

    <Button
        android:id="@+id/reload"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Reload"/>
    <GridView
        android:id="@+id/gridview"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"
        android:columnWidth="220dp"
        android:numColumns="auto_fit"
        android:verticalSpacing="10dp"
        android:horizontalSpacing="10dp"
        android:stretchMode="columnWidth"
        android:gravity="center"/>

</LinearLayout>

Permission of "android.permission.READ_EXTERNAL_STORAGE" is needed to read storage.

download filesDownload the files.

Next:
Improve JPG loading with ExifInterface.getThumbnail()


Friday, August 8, 2014

Access UI elements from AsyncTask

This post show some examples to Get and Set UI elements from AsyncTask. the "Start AsyncTask" button clicked, it new and execute a AsyncTask, to get and set UI elements in various call-back method, in UI thread and background thread.

  • Starting with HONEYCOMB, AsyncTask are executed on a single thread to avoid common application errors caused by parallel execution - read Run multi AsyncTask at the same time.
    So call myClientTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) if it is running on device higher than HONEYCOMB.
  • For the ProgressBar, it's a simple and standard demo: update counter in doInBackground(), and call publishProgress() to call onProgressUpdate() in-directly to update the ProgressBar in UI thread.
  • In onPreExecute() and onPostExecute(), it run on UI thread, so you can access UI elements directly.
  • In doInBackground(), it run on background thread; to read data from EditText textIn2 and update TextView textOut2.
    - In background thread, it can read UI elements, so it can call textIn2.getText() directly. (If I am wrong, please comment)
    - In background thread, it CANNOT modify UI element, call runOnUiThread() and pass a Runnable to update textOut2 in UI thread.
MainActivity.java
package com.example.androiduiasynctask;

import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.annotation.TargetApi;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;


public class MainActivity extends ActionBarActivity {

 EditText textIn1, textIn2;
 TextView textCounter;
 Button btnStart, btnClear;
 ProgressBar progressBar;
 TextView textOut1, textOut2, textOut3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        textIn1 = (EditText)findViewById(R.id.textin1);
        textIn2 = (EditText)findViewById(R.id.textin2);
     textCounter = (TextView)findViewById(R.id.counter);
     btnStart = (Button)findViewById(R.id.start);
     btnClear = (Button)findViewById(R.id.clear);
     progressBar = (ProgressBar)findViewById(R.id.progress);
     textOut1 = (TextView)findViewById(R.id.textout1);
     textOut2 = (TextView)findViewById(R.id.textout2);
     textOut3 = (TextView)findViewById(R.id.textout3);
     
     btnStart.setOnClickListener(MyOnClickListener);
     
     btnClear.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    progressBar.setProgress(0);
       textOut1.setText("");
       textOut2.setText("");
       textOut3.setText("");
   }});
    }
    
    OnClickListener MyOnClickListener = new OnClickListener(){

  @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override
  public void onClick(View v) {
   
   MyAsyncTask myAsyncTask = new MyAsyncTask();
   
   /*
    * Handle multi AsyncTask at the same time
    * Refer: http://android-er.blogspot.com/2014/04/run-multi-asynctask-as-same-time.html
    */
   if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
    myAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
   else
    myAsyncTask.execute();
   
  }
     
    };
    
    public class MyAsyncTask extends AsyncTask<Void, Integer, Void>{

  @Override
  protected void onPreExecute() {
   //In UI thread, you can access UI here
   super.onPreExecute();
   String s1 = textIn1.getText().toString();
   textOut1.setText(s1);
  }

  @Override
  protected Void doInBackground(Void... arg0) {
   
   for(int i=0; i<=10; i++){
    SystemClock.sleep(1000);
    publishProgress(i);  //update UI in onProgressUpdate
    
    //Can GET from UI elements
    String s2 = textIn2.getText().toString();
    
    final String msgInBackGround = "doInBackground: " + i + " - " + s2;
    
    /*
     * Cannot direct SET UI elements in background thread
     * so do with runOnUiThread()
     */
    runOnUiThread(new Runnable(){

     @Override
     public void run() {
      textOut2.setText(msgInBackGround);
     }});
   }
   return null;
  }

  @Override
  protected void onPostExecute(Void result) {
   //In UI thread, you can access UI here
   textOut3.setText("onPostExecute");
   super.onPostExecute(result);
  }

  @Override
  protected void onProgressUpdate(Integer... values) {
   //In UI thread, you can access UI here
   progressBar.setProgress(values[0]);
   super.onProgressUpdate(values);
  }

    }

}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androiduiasynctask.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <EditText
        android:id="@+id/textin1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <EditText
        android:id="@+id/textin2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/counter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start AsyncTask"/>
    <Button
        android:id="@+id/clear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Clear"/>
    <ProgressBar
        android:id="@+id/progress"
        style="?android:attr/progressBarStyleHorizontal"
        android:indeterminate="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="10"
        android:progress="0"/>
    <TextView
        android:id="@+id/textout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/textout2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/textout3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>


Saturday, April 26, 2014

Run multi AsyncTask at the same time

AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.

If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.

~ reference: AsyncTask | Android Developers



This example show how to execute multi AsyncTask at the same in parallel, by calling executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) for (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB), in our StartAsyncTaskInParallel() method. The first three ProgressBars updated by AsyncTask execute in normal approach by calling execute(), the last two ProgressBar updated by AsyncTask execute in parallel.


MainActivity.java
package com.example.androidparallelasynctask;

import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;

public class MainActivity extends Activity {

 public class MyAsyncTask extends AsyncTask<Void, Integer, Void> {

  ProgressBar myProgressBar;
  
  public MyAsyncTask(ProgressBar target) {
   myProgressBar = target;
  }

  @Override
  protected Void doInBackground(Void... params) {
   for(int i=0; i<100; i++){
    publishProgress(i);
    SystemClock.sleep(100);
   }
   return null;
  }

  @Override
  protected void onProgressUpdate(Integer... values) {
   myProgressBar.setProgress(values[0]);
  }

 }
 
 Button buttonStart;
 ProgressBar progressBar1, progressBar2, progressBar3, progressBar4, progressBar5;
 MyAsyncTask asyncTask1, asyncTask2, asyncTask3, asyncTask4, asyncTask5;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  progressBar1 = (ProgressBar)findViewById(R.id.progressbar1);
  progressBar2 = (ProgressBar)findViewById(R.id.progressbar2);
  progressBar3 = (ProgressBar)findViewById(R.id.progressbar3);
  progressBar4 = (ProgressBar)findViewById(R.id.progressbar4);
  progressBar5 = (ProgressBar)findViewById(R.id.progressbar5);
  
  buttonStart = (Button)findViewById(R.id.start);
  buttonStart.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    asyncTask1 = new MyAsyncTask(progressBar1);
    asyncTask1.execute();
    asyncTask2 = new MyAsyncTask(progressBar2);
    asyncTask2.execute();
    asyncTask3 = new MyAsyncTask(progressBar3);
    asyncTask3.execute();
    asyncTask4 = new MyAsyncTask(progressBar4);
    StartAsyncTaskInParallel(asyncTask4);
    asyncTask5 = new MyAsyncTask(progressBar5);
    StartAsyncTaskInParallel(asyncTask5);
   }});

 }
 
 @TargetApi(Build.VERSION_CODES.HONEYCOMB)
 private void StartAsyncTaskInParallel(MyAsyncTask task) {
     if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
         task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     else
         task.execute();
 }

}

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidparallelasynctask.MainActivity" >
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <Button
        android:id="@+id/start"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Start"/>
    
    <ProgressBar
        android:id="@+id/progressbar1"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="0" />
    <ProgressBar
        android:id="@+id/progressbar2"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="0" />
    <ProgressBar
        android:id="@+id/progressbar3"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="0" />
    <ProgressBar
        android:id="@+id/progressbar4"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="0" />
    <ProgressBar
        android:id="@+id/progressbar5"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="0" />
        
</LinearLayout>

This video show how it run on devices running various Android version, include:
- Nexus 7 (1st generation), Android 4.4.2
- HTC One X, Android 4.2.2
- HTC Flyer, Android 3.2.1
- Nexus One, Android 2.3.6


download filesDownload the files.

Monday, October 7, 2013

GridView example: load images to GridView from SD Card in background

Recall from the "old exercise of GridView", loading images to GridView from SD Card in onCreate() method running in main thread. Actually, it may take long time to finish, so it should be moved to background thread. This exercise move the file loading operation to AsyncTask running in background thread.

Also introduce Reload button to demonstrate how to clear and reload the list.

Load images to GridView from SD Card


Here are some notes in my implementation:
  • In my trial experience, should not access ImageAdapter(extends BaseAdapter) from background thread such as doInBackground(). Doing so will conflict with ImageAdapter's getView() method, and generate IndexOutOfBoundsException occasionally. It whould be accessed in UI thread, so the clear(), add() and notifyDataSetChanged() have been moved to onPreExecute(), onProgressUpdate() and onPostExecute().
  • Cancel the AsyncTask if not need.
  • In my approach, always new another ImageAdapter when reloading; to prevent the list inside mixed with a invalid but still running AsyncTask.

package com.example.androidgridview;

import java.io.File;
import java.util.ArrayList;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity {
 
 AsyncTaskLoadFiles myAsyncTaskLoadFiles;

 public class AsyncTaskLoadFiles extends AsyncTask<Void, String, Void> {
  
  File targetDirector;
  ImageAdapter myTaskAdapter;

  public AsyncTaskLoadFiles(ImageAdapter adapter) {
   myTaskAdapter = adapter;
  }

  @Override
  protected void onPreExecute() {
   String ExternalStorageDirectoryPath = Environment
     .getExternalStorageDirectory().getAbsolutePath();

   String targetPath = ExternalStorageDirectoryPath + "/test/";
   targetDirector = new File(targetPath);
   myTaskAdapter.clear();
   
   super.onPreExecute();
  }

  @Override
  protected Void doInBackground(Void... params) {
   
   File[] files = targetDirector.listFiles();
   for (File file : files) {
    publishProgress(file.getAbsolutePath());
    if (isCancelled()) break;
   }
   return null;
  }

  @Override
  protected void onProgressUpdate(String... values) {
   myTaskAdapter.add(values[0]);
   super.onProgressUpdate(values);
  }

  @Override
  protected void onPostExecute(Void result) {
   myTaskAdapter.notifyDataSetChanged();
   super.onPostExecute(result);
  }

 }

 public class ImageAdapter extends BaseAdapter {

  private Context mContext;
  ArrayList<String> itemList = new ArrayList<String>();

  public ImageAdapter(Context c) {
   mContext = c;
  }

  void add(String path) {
   itemList.add(path);
  }
  
  void clear() {
   itemList.clear();
  }
  
  void remove(int index){
   itemList.remove(index);
  }

  @Override
  public int getCount() {
   return itemList.size();
  }

  @Override
  public Object getItem(int position) {
   // TODO Auto-generated method stub
   return itemList.get(position);
  }

  @Override
  public long getItemId(int position) {
   // TODO Auto-generated method stub
   return 0;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   ImageView imageView;
   if (convertView == null) { // if it's not recycled, initialize some
          // attributes
    imageView = new ImageView(mContext);
    imageView.setLayoutParams(new GridView.LayoutParams(220, 220));
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setPadding(8, 8, 8, 8);
   } else {
    imageView = (ImageView) convertView;
   }

   Bitmap bm = decodeSampledBitmapFromUri(itemList.get(position), 220,
     220);

   imageView.setImageBitmap(bm);
   return imageView;
  }

  public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth,
    int reqHeight) {

   Bitmap bm = null;
   // First decode with inJustDecodeBounds=true to check dimensions
   final BitmapFactory.Options options = new BitmapFactory.Options();
   options.inJustDecodeBounds = true;
   BitmapFactory.decodeFile(path, options);

   // Calculate inSampleSize
   options.inSampleSize = calculateInSampleSize(options, reqWidth,
     reqHeight);

   // Decode bitmap with inSampleSize set
   options.inJustDecodeBounds = false;
   bm = BitmapFactory.decodeFile(path, options);

   return bm;
  }

  public int calculateInSampleSize(

  BitmapFactory.Options options, int reqWidth, int reqHeight) {
   // Raw height and width of image
   final int height = options.outHeight;
   final int width = options.outWidth;
   int inSampleSize = 1;

   if (height > reqHeight || width > reqWidth) {
    if (width > height) {
     inSampleSize = Math.round((float) height
       / (float) reqHeight);
    } else {
     inSampleSize = Math.round((float) width / (float) reqWidth);
    }
   }

   return inSampleSize;
  }

 }

 ImageAdapter myImageAdapter;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  final GridView gridview = (GridView) findViewById(R.id.gridview);
  myImageAdapter = new ImageAdapter(this);
  gridview.setAdapter(myImageAdapter);

  /*
   * Move to asyncTaskLoadFiles String ExternalStorageDirectoryPath =
   * Environment .getExternalStorageDirectory() .getAbsolutePath();
   * 
   * String targetPath = ExternalStorageDirectoryPath + "/test/";
   * 
   * Toast.makeText(getApplicationContext(), targetPath,
   * Toast.LENGTH_LONG).show(); File targetDirector = new
   * File(targetPath);
   * 
   * File[] files = targetDirector.listFiles(); for (File file : files){
   * myImageAdapter.add(file.getAbsolutePath()); }
   */
  myAsyncTaskLoadFiles = new AsyncTaskLoadFiles(myImageAdapter);
  myAsyncTaskLoadFiles.execute();

  gridview.setOnItemClickListener(myOnItemClickListener);
  
  Button buttonReload = (Button)findViewById(R.id.reload);
  buttonReload.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    
    //Cancel the previous running task, if exist.
    myAsyncTaskLoadFiles.cancel(true);
    
    //new another ImageAdapter, to prevent the adapter have
    //mixed files
    myImageAdapter = new ImageAdapter(MainActivity.this);
    gridview.setAdapter(myImageAdapter);
    myAsyncTaskLoadFiles = new AsyncTaskLoadFiles(myImageAdapter);
    myAsyncTaskLoadFiles.execute();
   }});

 }

 OnItemClickListener myOnItemClickListener = new OnItemClickListener() {

  @Override
  public void onItemClick(AdapterView<?> parent, View view, int position,
    long id) {
   String prompt = "remove " + (String) parent.getItemAtPosition(position);
   Toast.makeText(getApplicationContext(), prompt, Toast.LENGTH_SHORT)
     .show();
   
   myImageAdapter.remove(position);
   myImageAdapter.notifyDataSetChanged();

  }
 };

}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:orientation="vertical">

    <Button
        android:id="@+id/reload"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Reload"/>
    <GridView
        android:id="@+id/gridview"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"
        android:columnWidth="90dp"
        android:numColumns="auto_fit"
        android:verticalSpacing="10dp"
        android:horizontalSpacing="10dp"
        android:stretchMode="columnWidth"
        android:gravity="center"/>

</LinearLayout>


download filesDownload the files.

download filesDownload and try the APK.



Next:
- getView() to load images in AsyncTask


Monday, September 2, 2013

Implement callback function with interface

This example demonstrate how to implement callback function with interface.

Implement callback function with interface

Create a MyAsyncTask class extends AsyncTask. Inside MyAsyncTask, interface DoSomething declared. MyAsyncTask class handle the background timing only, know knowing about the actual jobs. The actual jobs are in the class implement DoSomething.

package com.example.androidcallback;

import android.os.AsyncTask;
import android.os.SystemClock;

public class MyAsyncTask extends AsyncTask<Void, Void, Void> {

 interface DoSomething {
  void doInBackground(int progress);
  void doPostExecute();
 }

 DoSomething myDoSomethingCallBack;
 int myMax;
 
 MyAsyncTask(DoSomething callback, int max){
  myDoSomethingCallBack = callback;
  myMax = max;
 }

 @Override
 protected Void doInBackground(Void... params) {
  for (int i = 0; i <= myMax; i++) {
   SystemClock.sleep(100);
   myDoSomethingCallBack.doInBackground(i);
  }
  return null;
 }

 @Override
 protected void onPostExecute(Void result) {
  super.onPostExecute(result);
  myDoSomethingCallBack.doPostExecute();
 }

}


MainActivity.java, implements DoSomething. Itself (this) will be passed to MyAsyncTask constructor, to implement callback function.
package com.example.androidcallback;

import com.example.androidcallback.MyAsyncTask.DoSomething;

import android.os.Bundle;
import android.widget.ProgressBar;
import android.widget.Toast;
import android.app.Activity;

public class MainActivity extends Activity implements DoSomething{
 
 ProgressBar myProgressBar;
 MyAsyncTask myAsyncTask;
 int myProgress;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  myProgressBar = (ProgressBar)findViewById(R.id.myprogressbar);
  
  myProgress = 0;
  myAsyncTask = new MyAsyncTask(this, 100);
  myAsyncTask.execute();
 }

 @Override
 public void doInBackground(int i) {
  myProgressBar.setProgress(i);
 }

 @Override
 public void doPostExecute() {
  Toast.makeText(MainActivity.this, 
    "Finish", Toast.LENGTH_LONG).show();
 }

}


layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <ProgressBar 
        android:id="@+id/myprogressbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="?android:attr/progressBarStyleHorizontal"
        android:max="100"
        android:progress="0" />

</LinearLayout>


download filesDownload the files.