I am new to Android programming and only have a very basic knowledge of it. I am trying to understand basic multithreading.
I have followed a tutorial for creating a basic thread and displaying a progressDialog which simply adds 500 records to a database when the button is clicked.
public void btnAddClick(View v) {
// Create progress dialog to show status
dialog = ProgressDialog.show(MainActivity.this, "Loading", "Updating database...");
h = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
dialog.dismiss();
}
};
// Create a new thread
new Thread() {
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
// Time consuming task here
try {
Thread.sleep(1);
UpdateDB();
h.sendEmptyMessage(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
.start();
//UpdateDB();
}
With this code i get a warning within the IDE: This Handler class should be static or leaks might occur.
I Have 2 more buttons View and Clear, i use the same code for each of them and just UpdateDB(); Becomes ViewDB(); and ClearDB();
The code compiles and the AddClick works perfectly, but if i try and use ViewClick or ClearClick then my application crashes, on View sometimes the dialog displays for a few seconds then my application is crashing.
Is that caused by a resource leak? and can somebody please show me an example of how to make the Handler static so i avoid issues while using it.
The Full source code for the activity is here:
import android.app.Activity;
import android.app.ProgressDialog;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
protected ProgressDialog dialog;
protected Handler h;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
DBAdapter myDb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkDataBase();
}
#Override
protected void onDestroy() {
super.onDestroy();
closeDB();
}
private void openDB() {
myDb = new DBAdapter(this);
myDb.open();
}
private void closeDB() {
myDb.close();
}
private void displayText(String message) {
TextView textView = (TextView) findViewById(R.id.textDisplay);
textView.setText(message);
}
public void btnAddClick(View v) {
// Create progress dialog to show status
dialog = ProgressDialog.show(MainActivity.this, "Please Wait", "Updating database...");
h = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
dialog.dismiss();
}
};
// Create a new thread
new Thread() {
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
// Time consuming task here
try {
Thread.sleep(1);
UpdateDB();
h.sendEmptyMessage(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
.start();
//UpdateDB();
}
public void btnClearClick(View v) {
// Create progress dialog to show status
dialog = ProgressDialog.show(MainActivity.this, "Please Wait", "Deleting database...");
h = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
dialog.dismiss();
}
};
// Create a new thread
new Thread() {
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
// Time consuming task here
try {
Thread.sleep(1);
ClearDB();
h.sendEmptyMessage(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
.start();
}
public void btnViewClick(View v) {
// Create progress dialog to show status
dialog = ProgressDialog.show(MainActivity.this, "Please Wait", "Displaying records...");
h = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
dialog.dismiss();
}
};
// Create a new thread
new Thread() {
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
// Time consuming task here
try {
Thread.sleep(1);
ViewDB();
h.sendEmptyMessage(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
.start();
}
// Display full database inside TextView
private void displayRecordSet(Cursor cursor) {
String message = "";
// populate the message from the cursor
// Reset cursor to start, checking to see if there's data:
if (cursor.moveToFirst()) {
do {
// Process the data:
int id = cursor.getInt(DBAdapter.COL_ROWID);
String make = cursor.getString(DBAdapter.COL_MAKE);
String model = cursor.getString(DBAdapter.COL_MODEL);
String year = cursor.getString(DBAdapter.COL_YEAR);
String tyreSize = cursor.getString(DBAdapter.COL_TYRESIZE);
String front = cursor.getString(DBAdapter.COL_FRONT);
String rear = cursor.getString(DBAdapter.COL_REAR);
// Append data to the message:
message += "id=" + id
+", make=" + make
+", model=" + model
+", year=" + year
+", tyreSize=" + tyreSize
+", front=" + front
+", rear=" + rear
+"\n";
} while(cursor.moveToNext());
}
// Close the cursor to avoid a resource leak.
cursor.close();
displayText(message);
}
// Checks database file exists during OnCreate();
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
try {
String DB_FULL_PATH = "/data/data/com.digitak.mytyrepressure/databases/myDb";
checkDB = SQLiteDatabase.openDatabase(DB_FULL_PATH , null,
SQLiteDatabase.OPEN_READONLY);
checkDB.close();
} catch (SQLiteException e) {
// database doesn't exist yet.
System.out.println("Database Doesnt Exist...Creating");
openDB();
}
return checkDB != null ? true : false;
}
// Adds 500 Records to the database for testing purposes
public void UpdateDB() {
int x = 0;
while (x < 500) {
myDb.insertRow("Ford", "KA", "1996-2003", "155/70R13", "31", "26");
x++;
}
}
public void ViewDB() {
Cursor cursor = myDb.getAllRows();
displayRecordSet(cursor);
}
public void ClearDB() {
myDb.deleteAll();
}
}
Thank you for your time.
Probably it didn't happen because of leak but why it happened it would be easier to say if we see catlog..
Side note.. WTH is Thread.sleep(1) for???
Side note 2: You shouldn't use threads here at all.. If you need to do task in background in general there is AsyncTask class. Specifically for DB transaction, there are even better content provider and Loader concepts..
Hope I help a bit so you can go in the right direction.
Add this argument when creating Handler: Looper.getMainLooper()
Handler handler = new Handler(Looper.getMainLooper()){...
}
This should remove the warning
Related
I am using the external library SignalR, and I find the Github code in Java I have implemented it successfully and receiving the Log messages such as Connected , Message etc but when I tries to show these messages in the MainActivity EditText and textviews , it is really not working . Following is a code that I modified according to my need now tell me how to modify accordingly in android to receive the messages on Ui.
public class HubClient {
public HubProxy RelayServerHubProxy;
MainActivity mainActivity = new MainActivity();
public HubConnection RelayServerHubConnection;
Context context = null;
public Boolean Connected = false;
public static String ErrorName,ConnectionStatus,MessageReceived;
Logger logger = new Logger() {
#Override
public void log(String message, LogLevel level) {
// TODO Auto-generated method stub
// System.out.println(message);
Log.v("Message Received in Logger", message);
}
};
public HubClient(Context context) {
this.context = context;
mainActivity = new MainActivity();
}
public void Connect(String ServerURI, String SockConnectionType) {
try {
ClientTransport webSockTransport = null;
RelayServerHubConnection = new HubConnection(ServerURI);
// creating hub prox object
RelayServerHubProxy = RelayServerHubConnection
.createHubProxy("MyHub");
// Start the connection
RelayServerHubConnection.start().done(new Action<Void>() {
#Override
public void run(Void obj) throws Exception {
// TODO Auto-generated method stub
Log.v("Connection Status", "Connection done");
}
});
// Subscribe to the error event
RelayServerHubConnection.error(new ErrorCallback() {
public void onError(Throwable error) {
// TODO Auto-generated method stub
error.printStackTrace();
Log.v("WE've GOt erroe", error.getMessage());
ErrorName = error.getMessage();
//mainActivity.ShowToast(error.getMessage());
}
});
// Subscribe to the connected event
RelayServerHubConnection.connected(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Log.v("Connected", "Connected");
Connected = true;
// Toast.makeText(mainActivity, "Connected",
// Toast.LENGTH_LONG).show();
}
});
// Subscribe to the closed event
RelayServerHubConnection.closed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Log.v("Connection is", "Closed");
}
});
RelayServerHubProxy.subscribe(new Object() {
#SuppressWarnings("unused")
public void messageReceived(String name, String message) {
Log.v("Server Message", name + message);
// Toast.makeText(context, message,
// Toast.LENGTH_LONG).show();
MessageReceived = name+message;
}
});
// Subscribe to the received event
RelayServerHubConnection.received(new MessageReceivedHandler() {
#Override
public void onMessageReceived(JsonElement json) {
//how to show this message on again mainactivity Textview
Log.v("onMessagReceived", json.toString());
}
});
RelayServerHubConnection.stateChanged(new StateChangedCallback() {
#Override
public void stateChanged(ConnectionState oldState,
ConnectionState newState) {
// TODO Auto-generated method stub
if (newState == microsoft.aspnet.signalr.client.ConnectionState.Connected)
{
// how to show Connected status in Textview?
} else if (oldState == microsoft.aspnet.signalr.client.ConnectionState.Disconnected) {
// Show Message here
}
}
});
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
public void SendMessageToServer(String messageToServer1) {
try {
RelayServerHubProxy.invoke("MessageFromClient",
(String) messageToServer1);
RelayServerHubConnection.error(new ErrorCallback() {
public void onError(Throwable error) {
// TODO Auto-generated method stub
error.printStackTrace();
//How to show message of error on Main Activity ?
}
});
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
Log.v("Exception", e.toString());
}
}
}
Now I have commented what I want in the functions. Notice that All function is using Runnable . So please tell me how to modify this to use in android
To show an alertDialog paste this function in your HubClient object:
private void showError(final String message) {
((Activity)context).runOnUiThread(new Runnable() {
public void run() {
new AlertDialog.Builder(context)
.setTitle("Error")
.setMessage(message)
.setPositiveButton("Ok", null)
.show();
}
});
}
You can call it inside your error callback
To show a message in a TextView use this one:
private void updateTextView(final String message) {
((Activity)context).runOnUiThread(new Runnable() {
public void run() {
// mTextView must be referenced by HubClient
mTextView.setText(message);
}
});
}
I have an app that sends a file through a socket. While doing this I want to show the progress in a ProgressDialog. The app sends the file perfectly but I'm not able to make the dialog appear.
public class ProgressDialogActivity extends Activity {
private ProgressDialog downloadDialog = null;
private String filePath;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
filePath = getIntent().getExtras().getString("filePath");
downloadDialog = new ProgressDialog(this);
Task myTask = new Task();
myTask.execute(0);
}
private void showMessage(final String msg) {
this.runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), msg, `enter code here`Toast.LENGTH_SHORT).show();
}
});
}
private class Task extends AsyncTask<Integer, Integer, Boolean> implements Observer
{
private Thread t;
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
downloadDialog.setTitle("SENDING");
downloadDialog.setMessage("................");
downloadDialog.setCancelable(false);
downloadDialog.setIndeterminate(false);
// downloadDialog.setMax(100);
downloadDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
downloadDialog.show();
}
#Override
protected Boolean doInBackground(Integer... params) {
SendFile send = new SendFile(filePath);
downloadDialog.setMax(0);
t = new Thread(send);
send.registerObserver(this);
// try {
// Thread.sleep(10000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
t.start();
return true;
}
#Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
int counter = values[0].intValue();
downloadDialog.setProgress(counter);
if(filePath != null)
{
downloadDialog.setMessage(filePath+"...");
}
}
#Override
public void update(Subject subject) {
// TODO Auto-generated method stub
if(subject instanceof SendFile)
{
SendFile e = (SendFile) subject;
if(e.getException() != null)
{
t.interrupt();
showMessage(e.getException());
} else
{
if(!e.isStarted())
{
initializeProgressBar(e.getNumIter());
} else
{
refreshProgressBar(e.getNumIter());
}
if(e.isSent())
{
t.interrupt();
showMessage("File sent");
}
}
}
}
public void initializeProgressBar(int max){
downloadDialog.setMax(max);
}
public void refreshProgressBar(int amount){
publishProgress(downloadDialog.getMax()-amount);
}
#Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if(downloadDialog != null)
{
downloadDialog.dismiss();
}
finish();
}
#Override
protected void onCancelled() {
// TODO Auto-generated method stub
super.onCancelled();
t.interrupt();
showMessage("TASK CANCELLED");
}
};
}
SendFile is the class that contains the socket to send the files.
I think the problem is due to I'm calling the thread inside the AssyncTask because when I make Thread.sleep(10000) I can see the ProgressDialog for that time, but I don't know how to fix it.
Also, when I run the debugger I can see that the variable 'counter' is incremented every time I call it, but if I add a watch with 'downloadDialog.getProgress()' the progress is always 0.
You are creating an AsyncTask, which doInBackground() method RUNS IN BACKGROUND. In there, you don't do anything, but start a new thread... Now this thread does the work, but your AsyncTask finishes, because it has nothing to do after starting the other thread... So, your ProgressDialog is shown for some milliseconds, then your AsyncTask finishes and the ProgressDialog is hidden again. But the thread that is doing the work is still running, only your AsyncTask has finished.
Solution : Either use an AsyncTask OR use a thread.
You need to call publishProgress on doinBackground()
Example:
protected String doInBackground(Void... params) {
try {
int i = 0;
Log.i("Thread","1");
Thread.sleep(1000);
publishProgress(i++);
Log.i("Thread","2");
Thread.sleep(1000);
publishProgress(i++);
Log.i("Thread","3");
Thread.sleep(1000);
Log.i("Thread","4");
Thread.sleep(1000);
Log.i("Thread","5");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "done";
}
I'm developing DES decryption in Android platform.
this is my main
package com.example.crack;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
public class Main extends Activity {
public final static String EXTRA_MESSAGE = "com.example.crack.MESSAGE";
public final static String EXTRA_PLAINTEXT = "com.example.crack.PLAINTEXT";
public final static int ENCRYPTION_REQUEST = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void sendMessage(View view) {
Intent intent = new Intent(this, encryption.class);
EditText editText = (EditText) findViewById(R.id.input_message);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
startActivityForResult(intent, ENCRYPTION_REQUEST);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request it is that we're responding to
if (requestCode == ENCRYPTION_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
String result = data.getStringExtra(encryption.EXTRA_ENCRYPTION_RETURN);
Intent intent = new Intent(this, DisplayMessage.class);
intent.putExtra(EXTRA_MESSAGE, result);
startActivity(intent);
}
}
}
}
and this is the partial of my encrpytion
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.encryption);
Intent intent = getIntent();
message = intent.getStringExtra(Main.EXTRA_MESSAGE);
//Dictionary
is = getResources().openRawResource(R.raw.english);
in = new BufferedReader(new InputStreamReader(is));
readDic();
String result = "";
try {
result = decryptBruteForce();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Intent returnIntent = new Intent();
returnIntent.putExtra(EXTRA_ENCRYPTION_RETURN,result);
setResult(RESULT_OK,returnIntent);
finish();
}
when i click on the button, it calls the sendMessage function, while it is running the decryption the screen just black out until it finish running.
I had try using progress bar follow this guide, but not working, I need a button that can stop the process while running.
And is it possible to set a log on view, which show what the function is doing right now? like what is shown in the IDE log? Example, showing what key is the decryption trying right now.
Or maybe just a progress bar or please wait will do too.
I tried to change the sendMessage to this, yet it still black out and crash
public void sendMessage(View view) {
final Intent intent = new Intent(this, encryption.class);
view.setEnabled(false);
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute() {
pd = new ProgressDialog(context);
pd.setTitle("Processing...");
pd.setMessage("Please wait.");
pd.setCancelable(false);
pd.setIndeterminate(true);
pd.show();
}
#Override
protected Void doInBackground(Void... arg0) {
try {
//Do something...
EditText editText = (EditText) findViewById(R.id.input_message);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
startActivityForResult(intent, ENCRYPTION_REQUEST);
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (pd!=null) {
pd.dismiss();
b.setEnabled(true);
}
}
};
task.execute((Void[])null);
}
if I put sleep to 50000, it did not crash, but still it black out.
You can do it with a Thread and a Handler. While you try each combination, you update the progress bar.
private int mProgressStatus = 0;
private Handler mHandler = new Handler();
protected void onCreate(Bundle savedInstanceState)
{
.... // Other initializations
mProgress = (ProgressBar) findViewById(R.id.progress_bar);
mProgress.setMax(dictionaryLength);
// Start lengthy operation in a background thread
new Thread(new Runnable() {
public void run() {
for (int i=0 ; i<dictionaryLength ; i++)
{
mProgressStatus = decryptBruteForce(i);
// Update the progress bar
mHandler.post(new Runnable() {
public void run() {
mProgress.setProgress(mProgressStatus);
}
});
}
}
}).start();
}
However i recommend you to use AsyncTask to do background operations while you need to update the UI to show the progress or info about whats going on.
http://developer.android.com/intl/es/reference/android/os/AsyncTask.html
Its a good habit to add a cancel control in your loop, so you can finish it from outside of the AsyncTask (for example another button in you UI).
private class DecryptTask extends AsyncTask<String, Integer, Long> {
protected Long doInBackground(String... words)
{
long wordsDecrypted = 0;
for (int i = 0; i < words.length ; i++) {
wordsDecrypted += decryptBruteForce(i);
publishProgress(i);
// Escape early if cancel() is called
if (isCancelled())
break;
}
return wordsDecrypted;
}
protected void onProgressUpdate(Integer... progress) {
mProgress.setProgress(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Decrypted " + result + " words");
}
}
And you can cancel the AsyncTask from outside with the cancel method:
http://developer.android.com/intl/es/reference/android/os/AsyncTask.html#cancel(boolean)
PD: Codes are not tested, just examples to show how it works
I am developing an android application where I receive eeg signal from bluetooth and display it in real time using achartengine. I use an async task to display the chart and update it. But, I get ConcurrentModificationException everytime. The graph is displayed for sometime and then it gives that error. Below is my code.
mstart.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0)
{
// TODO Auto-generated method stub
// tv.setText("Fetal Heart rate loading..");
// index = 0;
flag = true;
if(fhr_alg!=null)
fhr_alg = null;
fhr_alg = new AddStringTask();
algo_done = false;
/*curr = 5;
counter = 0;*/
//// a1.setFlag(true);
//a1.setMax(0);
Thread tt = new Thread()
{
public void run()
{
try{
sleep(600);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
fhr_alg.execute();
}
}
};tt.start();
if (view_eeg1== null) {
LinearLayout layout_eeg1 = (LinearLayout) findViewById(R.id.layout2);
view_eeg1= ChartFactory.getLineChartView(BluetoothConnect.this, eeg1, renderer_eeg1);
// layout_eeg1.
layout_eeg1.addView(view_eeg1);
} else {
view_eeg1.repaint();}
// w1.loadUrl("javascript:callJS()");
mstart.setEnabled(false);
}
});
class AddStringTask extends android.os.AsyncTask<Void, Integer, Integer> {
#Override
protected void onPostExecute(Integer result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
algo_done=true;
//Toast.makeText(Html.this, "Done Algo !", Toast.LENGTH_SHORT).show();
}
#SuppressLint("UseValueOf")
#Override
protected Integer doInBackground(Void... unused) {
try {
for(int r=0;r<=5000;r++){
//Thread.sleep(300);
series1.add(r,data[r]);
// w2.loadUrl("javascript:count(\""+data[r]+"\")");
if(r<=250){
renderer_eeg1.setXAxisMax(250);
}
else if(r>250){
double maxX = series1.getMaxX();
double minX = maxX - 250;
renderer_eeg1.setXAxisMin(minX);
renderer_eeg1.setXAxisMax(maxX);
}
view_eeg1.repaint();
publishProgress((int)data[r]);
SystemClock.sleep(600);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (0);
}
#Override
protected void onProgressUpdate(Integer ... value) {
int fhr=value[0];
view_eeg1.repaint();
w2.loadUrl("javascript:count(\""+fhr+"\")");
//a1.setfhr(curr, fhr);
//curr++;
}
}
can anyone tell me why am I getting this error and how to solve it.
Thanks
problem updating the UI into a Thread that is not an UI Thread so u
have to use a doinbackground as below and remove the code that
modifies the UI in doInbackground
Why does this app stop answering then I press play? It sometimes show a "the application is not responding" but it works if I wait.
It works nice on my emulator, but not on my phone (or any other phone I tried).
All it does is streaming sound.
package comunicera.se;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.ListActivity;
import android.content.Context;
import android.media.MediaPlayer;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ProgressBar;
import android.widget.TextView;
public class Godnattsaga extends ListActivity {
/** Called when the activity is first created. */
ListView list;
TextView spelandesSagqa;
//private ProgressDialog mProgressDialog;
ProgressBar myProgressBar;
int myProgress = 0;
MediaPlayer mp = new MediaPlayer();
String BASEURL = "http://godnattsaga.nu/sagor";
public static long glCurrentSaga = 0;
public static String giCode = null;
int giAntalSagor = 0;
int possWhenPaused = 0;
ProgressBar myBufferProgressBar;
TextView buffrarText;
int progress;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try
{
new Thread(buffer).start();
String lsSagor = getFileFromUrl(BASEURL+"/gratisSagor.txt");
final String[] laList = lsSagor.split("~");
giAntalSagor = laList.length;
//String saga = laList[0].replaceAll("#", "\n");
String[] laSaga = laList[0].split("#");
final String[] guiLaList = new String[giAntalSagor];
for (int i = 0; i < giAntalSagor; i++)
{
guiLaList[i] = laList[i].replaceAll("#", "\n");
}
changeSpelandesSaga(laSaga[0]);
setList (guiLaList);
ListView list = getListView();
list.setTextFilterEnabled(true);
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
String liCode = kop(id);
glCurrentSaga = id;
String[] laSaga = laList[(int) glCurrentSaga].split("#");
changeSpelandesSaga(laSaga[0]);
}
});
final Button button = (Button) findViewById(R.id.SpelaPause);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
selectDownloadOrPLay(laList);
}
});
glCurrentSaga = 0;
changeSpelandesSaga(laSaga[0]);
}
catch (Exception e)
{
changeSpelandesSaga("Check your connection, are you in flightmode?");
}
}
public void selectDownloadOrPLay(String[] laList) {
String[] laSaga = laList[(int) glCurrentSaga].split("#");
String url = BASEURL+"/gratis/"+laSaga[0].replaceAll(" ", "_")+".mp3";
if (mp.isPlaying())
{
mp.pause();
possWhenPaused=mp.getCurrentPosition();
}
else if (possWhenPaused != 0)
{
mp.start();
}
else
{
startSaga (url);
}
}
private String kop(long id)
{
mp.pause();
return "gratis";
}
public void setList (String[] laList)
{
/*
*
final String[] lAList = new String[3];
lAList[0] = "Saga 1 \n";
lAList[1] = "Saga 2 \n";
lAList[2] = "Saga 3";
setList (lAList);
*
*/
setContentView(R.layout.main);
ArrayAdapter<String> appointmentList = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, laList);
list=(ListView)findViewById(android.R.id.list);
list.setAdapter(appointmentList);
}
public void changeSpelandesSaga(String sagaRubrik)
{
possWhenPaused = 0;
TextView t = new TextView(this);
t=(TextView)findViewById(R.id.spelandesSaga);
t.setText(Html.fromHtml("<b>"+sagaRubrik+"</b>"));
}
private void startSaga(String url)
{
try {
mp.reset();
mp.setDataSource(url);
mp.prepare();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mp.start();
myProgressBar=(ProgressBar)findViewById(R.id.mProgressDialog);
new Thread(myThread).start();
}
private Runnable myThread = new Runnable(){
#Override
public void run() {
// TODO Auto-generated method stub
while (myProgress<100){
try{
myHandle.sendMessage(myHandle.obtainMessage());
Thread.sleep(1000);
}
catch(Throwable t){
}
}
}
Handler myHandle = new Handler(){
double poss = 0.0;
double sagaleng = 0.0;
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
poss = mp.getCurrentPosition();
sagaleng = mp.getDuration();
progress = (int) ((int)poss / sagaleng * 100);
myProgress = progress;
myProgressBar.setProgress(progress);
}
};
};
public static String getFileFromUrl(String url)
{
InputStream content = null;
try
{
HttpGet httpGet = new HttpGet(url);
HttpClient httpclient = new DefaultHttpClient();
// Execute HTTP Get Request
HttpResponse response = httpclient.execute(httpGet);
content = response.getEntity().getContent();
}
catch (Exception e)
{
showNoConnection ();
return null;
}
BufferedReader rd = new BufferedReader(new InputStreamReader(content), 4096);
String line;
StringBuilder sb = new StringBuilder();
try {
while ((line = rd.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
rd.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sb.toString();
}
public boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
boolean connected = cm.getActiveNetworkInfo().isConnectedOrConnecting();
return connected;
}
private static void showNoConnection()
{
}
private Runnable buffer = new Runnable(){
#Override
public void run() {
// TODO Auto-generated method stub
while (myProgress<100){
try{
myHandle.sendMessage(myHandle.obtainMessage());
Thread.sleep(1000);
}
catch(Throwable t)
{
}
}
}
Handler myHandle = new Handler(){
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
//SpelaPause.setImageURI("pauseicon");
myBufferProgressBar = (ProgressBar)findViewById(R.id.mBuffrar);
TextView bufferText = (TextView)findViewById(R.id.buffrarText);
if (mp.isPlaying() && progress == 0)
{
myBufferProgressBar.setVisibility(View.VISIBLE);
bufferText.setVisibility(View.VISIBLE);
}
else
{
myBufferProgressBar.setVisibility(View.INVISIBLE);
bufferText.setVisibility(View.INVISIBLE);
}
}
};
};
}
If your application uses internet, it is possible, that the phone has worse connection than your comp. For example, if they both run on the SAME WiFi, at the same point, phones are connected MUCH worse than PC. Slower connection - you have to wait...
Read http://developer.android.com/guide/practices/design/responsiveness.html and http://developer.android.com/guide/practices/design/performance.html - VERY useful. For example, you will know the name of your problem - bad responsiveness (not performance) - for better further searches. :-)
All long-lasting tasks should be run in separate thread, not in UI thread. You call getFileFromUrl(..) from onCreate(..) method. This cause hangings.
I recommend you not to do any time consuming task in onCreate(..) method. In general an activity won't be shown till onCreate(..) is finished.
You are using getFileFromUrl in your onCreate method. Your method just performs the download action, which in case could last some time. You should always move long running tasks into it's own thread and notify the UI thread only.
Consider never running big logic in the UI thread, the UI thread should only be responsible for UI stuff.
To download a file in an async manner try to use the AsyncTask: http://developer.android.com/reference/android/os/AsyncTask.html
This code works, without responsiveness problems. But the buffering takes to long time so I need another solution.
I'm posting some code if someone else have the same problem
package comunicera.se;
import java.io.IOException;
import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class GodnattsagaTest1 extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button button = (Button) findViewById(R.id.SpelaPause);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
selectDownloadOrPLay();
}
});
}
public void selectDownloadOrPLay() {
Toast.makeText(getApplicationContext(), "Before ... ", Toast.LENGTH_SHORT).show();
Saga.startSaga ();
Toast.makeText(getApplicationContext(), "after ... ", Toast.LENGTH_SHORT).show();
}
}
class Saga
{
static MediaPlayer mp = new MediaPlayer();
static void startSaga()
{
new Thread(spelaSaga).start();
}
private static Runnable spelaSaga = new Runnable(){
#Override
public void run() {
// TODO Auto-generated method stub
try {
mp.reset();
mp.setDataSource("http://godnattsaga.nu/sagor/gratis/Fisken.mp3");
mp.prepare();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mp.start();
}
};
}
I believe it has something to do with the progress bar you use. I use one and it slows my app. Not sure if the progress bar must slow the app or there is another way to avoid this though.