I am new to android.
I am trying to build a simple android application: User clicks the button and a progress dialog appears for 5 seconds.
I used ProgressDialog.show() and got a problem with the context parameter.
Here is my xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="#+id/btnDialog2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/btnDialog2" />
</LinearLayout>
And here is my code:
public class Dialog22Activity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btnDialog2 = (Button)findViewById(R.id.btnDialog2);
btnDialog2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final ProgressDialog dialog = ProgressDialog.show(getBaseContext(),
"Progress dialog", "Loading...", true);
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
dialog.dismiss();
} catch (InterruptedException e) {
}
}
}).start();
}
});
}
}
If i change the context parameter of ProgressDialog.show() from getBaseContext() to v.getContext() my program run normally.
So I wanna ask what is the meanning of context parameter here?
Thanks for your helps.
Just use Dialog22Activity.this instead of getContext() or WhatEverContextFunction() you want, when ever you are within this class and you'll be cool :)
You can refer the android docs for these explanations please see this
http://developer.android.com/reference/android/content/Context.html
getContext() is not defined in an Activity. It's used in a View (or View subclass) to get a reference to the enclosing context (an Activity).
The context in ProgressDialog.show(context) refers to the parent context of this ProgressDialog.
BaseContext effectively returns which ever context is being wrapped by ContextWrapper.
By looking at the code, I can say that this is likely an Activity or Application however ContextWrapper has over 40 known direct and indirect children.
The problem is that this means that what the method returns may be ambiguous and I would rather use getContext() or the Activity, FragmentActivity, ActionBarActivity etc. directly, so that I know what I’m holding on to and that I’m holding a reference to something that can cause a memory leak. Also, I have the additional benefit of being able to take advantage of methods that are provided by these classes.
In case you want to use a ProgressDialog in an external class to an activity, you would create an instance of a Context inside this class and ProgressDialog would use its context:
public class DownloadTask extends AsyncTask<URL, Integer, Void>{
ProgressDialog progressDialog;
private Context context;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(context);
}
If you are showing the progress dialog on current Activity, use classname.class or 'this' keyword for context.
import androidx.appcompat.app.AppCompatActivity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.webkit.WebView;
import android.view.View;
import android.webkit.WebViewClient;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.JsResult;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private WebView webView;
private ProgressDialog progressDialog;
startWebView("http://.../mobile/");
}
private void startWebView(String url) {
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
webView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setUseWideViewPort(true);
webView.getSettings().setLoadWithOverviewMode(true);
progressDialog = new ProgressDialog(this);
progressDialog.setTitle("Loading...");
progressDialog.setMessage("Wait while loading...");
progressDialog.setCancelable(false); // disable dismiss by tapping outside of the dialog
progressDialog.show();
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(getApplicationContext(), "Error:" + description, Toast.LENGTH_SHORT).show();
}
});
webView.loadUrl(url);
}
}
its the activity context. use:
public class Dialog22Activity extends Activity {
private Activity activity;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
activity = this;
Button btnDialog2 = (Button)findViewById(R.id.btnDialog2);
btnDialog2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final ProgressDialog dialog = ProgressDialog.show(activity,
"Progress dialog", "Loading...", true);
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
dialog.dismiss();
} catch (InterruptedException e) {
}
}
}).start();
}
});
}
}
information about context: What is 'Context' on Android?
Related
I am trying AsyncTask. I cannot understand how to return the result.I am also confused on doInBackground() has return type Void . Why does it need return null; if I return null how will I get value from this method.
package com.example.shikkok_services;
import android.app.Dialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class MyTask extends AsyncTask<Void, Integer, Void> {
//progressBar holo UI te kaj kore tai Context dorkar tai MyTask e construtor decler korlam.Inner class hole eita dorkar silo na
Context context;
Handler handler;
Dialog dialog;
TextView txtprogrss;
ProgressBar progress;
Button btnCancel;
MyTask(Context context, Handler handler){
this.context=context;
this.handler=handler;
}
MyTask(Context context){
this.context=context;
this.handler=handler;
}
//--------------------------------onPreExecute()............................................
#Override
protected void onPreExecute() {
super.onPreExecute();
// create dialog
dialog=new Dialog(context);
dialog.setCancelable(true);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.pogressdialog);
dialog.show();
txtprogrss=(TextView) dialog.findViewById(R.id.txtProgress);
progress=(ProgressBar)dialog.findViewById(R.id.progressBar2);
btnCancel=(Button)dialog.findViewById(R.id.btnProgress);
//progress=new ProgressBar(context);
btnCancel.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
MyTask.this.cancel(true);
dialog.dismiss();
}
});
dialog.show();
}
//--------------------------------doInBackground()...........................
#Override
protected Void doInBackground(Void... arg0) {
//Kaj hobe backgournd e not UI e
// do tasks and update msg
for (int i = 0; i < 10; i++) {
if(isCancelled()){
break;
}else{
Log.e("In Background","current value;"+ i);
publishProgress(i);
//joto bar publishProgress() call hobe toto bar OnProgressUpdate hobe..
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
//------------------------------onProgressUpdate().....................................
#Override
protected void onProgressUpdate(Integer... values) {
//dowonload hole koto percent hosse seita dhore dhore UI te dekhalte parbo
super.onProgressUpdate(values);
// update dialog progress
progress.setProgress(values[0]);
txtprogrss.setText("progress update"+ values[0]+"%");
}
//-----------------------------OonPostExecute()...........................................
#Override
protected void onPostExecute(Void result) {
// jokhon kaj ses hoe jabe tokhon ei method e asben then UI te chole asben
super.onPostExecute(result);
// handler.sent message
dialog.dismiss();
Toast.makeText(context, "Finished", Toast.LENGTH_LONG).show();
}
}
I am also confuse doInBackground is return type Void .Why it is need return null; if I return null how get value from this method.please tell me.
This is because that is what you have made it. You can return a type you just have to change the class definition ex.
public class MyTask extends AsyncTask<Void, Integer, String> { // changed last param
With this, doInBackground() will be expected to return a String type to onPostExecute(). Which means you would also have to change that method to
#Override
protected void onPostExecute(String result) {
You would then obviously change your return statement in doInBackground() to return someString.
I used String as an example but you could change that.
As far as returning value after AsyncTask finishes
See this answer about using an interface. It is really easy to implement and will update your Activity when the task finishes.
Also please read (or re-read) the AsyncTask docs
AsyncTask must return null because you said so declaring this: AsyncTask<Void, Integer, Void>. The third parameter determines what doInBackground() returns and therefore what onPostExecute() gets.
Change this datatype to make it return whetever you want, this way you'll receive it as a parameter in the onPostExecute() method and you can even update Views in the main UI Thread from within this method (you can even update them from anywhere besides doInBackground()).
For getting value from asynchronous task call it like this:
String result= new MyTask ().execute().get();
class MyTask extends AsyncTask<String, String, String>
{
protected String doInBackground(String... params)
return somevalue;
}
}
I have a problem with closing a custom dialog. I have two classes
class 1-> AndroidHTMLActivity
class 2-> CustomizeDialog
In my AndroidHTMLActivity I use java interface which is call from javascript, in this class i call CustomizeDialog
public class AndroidHTMLActivity extends Activity {
WebView myBrowser;
setContentView(R.layout.main);
myBrowser = (WebView)findViewById(R.id.mybrowser);
myBrowser.addJavascriptInterface(new MyJavaScriptInterface(this), "AndroidFunction");
myBrowser.getSettings().setJavaScriptEnabled(true);
myBrowser.loadUrl("file:///android_asset/mypage.html");
}
public class MyJavaScriptInterface {
Context mContext;
MyJavaScriptInterface(Context c) {
mContext = c;
}
public void openAndroidDialog(){
CustomizeDialog customizeDialog = new CustomizeDialog(mContext);
customizeDialog.show();
}
CustomizeDialog .java
public class CustomizeDialog extends Dialog {
Context ctx ;
public CustomizeDialog(Context context) {
super(context);
ctx = context;
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
MyThread downloadThread = new MyThread();
downloadThread.start();
}
public class MyThread extends Thread {
#Override
public void run() {
try {
handler.post(new MyRunnable());
}
}
}
static public class MyRunnable implements Runnable {
public void run() {
// here i want to close this customized dialog
}
}
Here i can't use finish() method, I want to close the customized dialog box via the thread. Anyone has any idea about this?
Well I know this question is asked in the past and maybe already answered but haven't shared the correct answer but I still want to share this since I also got the same problem. Well here's what I did.
1st create the base class let say and create a static declaration for dialog.
public class Dialogs {
static Dialog dialog;
}
2nd is to put your custom dialog.
public void customDialog(Context context){
dialog = new Dialog(context);
dialog.setContentView(R.layout.dialog_login);
dialog.setTitle(title);
//... other parts here
dialog.show();
}
then the dialog dismiss:
public static void dismissDialog(){
dialog.dismiss();
}
and on the other class to close the currect customDialog just call
Dialogs.dismissDialog();
That's it. :) Hope it helps.
close it with outside handler like this
App.HANDLER.post(new Runnable() {
#Override
public void run() {
dismiss();
cancel();
}
});
App is a application class
I'm relatively new to android development and I'm trying to make a WebView that will allow me to launch the android camera app. How can I go about calling a method in the main class from with my JavaScriptInterface?
Thanks.
public class MainActivity extends Activity {
public static final int MEDIA_TYPE_IMAGE = 1888;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView mainWebView = (WebView) findViewById(R.id.mainWebView);
mainWebView.addJavascriptInterface(new JavaScriptInterface(this), "Android");
WebSettings webSettings = mainWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mainWebView.setWebViewClient(new MyCustomWebViewClient());
//mainWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
mainWebView.loadUrl("file:///mnt/sdcard/page.html");
}
private class MyCustomWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
public void takePicture() {
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, MEDIA_TYPE_IMAGE);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MEDIA_TYPE_IMAGE) {
Bitmap photo = (Bitmap) data.getExtras().get("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
}}
}
package com.cargowise.view;
import android.content.Context;
import android.os.Handler;
import android.widget.Toast;
public class JavaScriptInterface {
Context mContext;
/** Instantiate the interface and set the context */
JavaScriptInterface(Context c) {
mContext = c;
}
public void takePic() {
MainActivity.takePicture();
}
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
You have stored the context which you should be able to use to access your MainActivity.
Change this:
public void takePic() {
MainActivity.takePicture();
}
To this:
public void takePic() {
((MainActivity)mContext).takePicture();
}
Note: you might want to add some type-checking or limit the type of the context that is given to a MainActivity to enforce correct behavior.
The suggestion of calling ((MainActivity)mContext).takePicture() is (probably) wrong, at least for me it failed. The reason is that the call will be not on the main/UI thread, but rather on some another thread.
Also, you MUST put the #JavascriptInterface annotation before each interface method.
The right way to place calls to main UI thread, which in turn will be able to do everything as usual on that thread, is this:
...inside JavaScriptInterface class
public void takePic() {
((MainActivity)mContext).post(new Runnable() {
#Override
public void run() {
((MainActivity)mContext).takePicture();
}
});
}
In Kotlin it would look much simpler:
#JavascriptInterface
fun takePic() {
(mContext as MainActivity).mainWebView?.post {
(mContext as MainActivity).takePicture()
}
}
Full example of integration of WebView with Android backend, with calls bak and forth between JS and Android, is here: https://github.com/latitov/Android_WebViewApp_FullScreen
Quick summary: I'm making an application that parses a binary file, stores vertices and their properties, and displays them in openGL. I'm trying to implement a ProgressDialog while it parses, but I'm having considerable trouble. I've tried implementing this in many places, but this is my current setup:
public class PointViewer extends Activity{
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
filePath = extras.getString("file_path");
mGLView = new GLSurfaceView(this);
theRenderer = new OpenGLRenderer();
mGLView.setRenderer(theRenderer);
//Parse the file and set the arrays
theRenderer.setLAS(filePath);
setContentView(mGLView);
}
...
}
The Rendering class...
public class OpenGLRenderer extends Activity implements GLSurfaceView.Renderer {
...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void setLAS (String fileName){
new ProgressTask(this).execute();
}
...
/*
* The class for the progress dialog
*/
private class ProgressTask extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
private Context context;
//private List<Message> messages;
public ProgressTask(Context ctx) {
context = ctx;
dialog = new ProgressDialog(context);
}
/** progress dialog to show user that the backup is processing. */
protected void onPreExecute() {
this.dialog.setMessage("Progress start");
this.dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
if (success) {
Toast.makeText(context, "OK", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Error", Toast.LENGTH_LONG).show();
}
}
protected Boolean doInBackground(final String... args) {
try{
ptCloud = new PointCloud(args[0]);
...
dialog.setProgress(percentParsed);
return true;
} catch (Exception e){
Log.e("tag", "error", e);
return false;
}
}
}
When I call dialog = new ProgressDialog(context); It errors on a null pointer exception, I'm assuming because there is a context issue... Does anyone have any ideas?
First, you shouldn't create OpenGLRenderer yourself, because its an Activity and is supposed to be managed by system. When you create OpenGLRenderer yourself, then this activity has its context incorrectly initialized. And when your create ProgressDialog with invalid context, you receive NullPointerException.
But even if you start OpenGlRenderer correctly, your app will still crash at line:
dialog.setProgress(percentParsed);
You should use publishProgress instead and update ProgressDialog in AsyncTask's onProgressUpdate function. That's because you can't update UI from non-ui thread.
maybe try replaceing "this" with "OpenGLRenderer.this" inside your setLAS() method. It doesn't seem like it from the code you've posted but sometimes if you are making that call from a different object type it will try to pass in an OnClickListener (or whatever object your calling from) instead of an activity, thus the object has no context. Like I said doesn't seem like that is the case, but worth a shot.
Also where are you calling setLAS() from? perhaps post that section of your code too.
Edit:
Try modifying your setLAS() method to have a Context parameter and pass it in from your first activity, and just pass it along from the second activity to the async task instead of using the context from the second activity.
I have a tabgroup having multiple activities. In one of the tabs i have two activities between whom i want to place a progress dialog.For this i am using Asynk Task. Following is my AsynkTask class which i have made an inner class for AboutUs activity:
private class TheTask extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
progDialog = ProgressDialog.show(AboutUs.this.getParent(), "Loading... ",
"please wait....", true);
}
#Override
protected Void doInBackground(Void... params) {
final Intent aboutusIntent = new Intent(getParent(), Departments.class);
final TabGroupActivity parentActivity = (TabGroupActivity)getParent();
parentActivity.startChildActivity("Departments", aboutusIntent);
return null;
}
#Override
protected void onPostExecute(Void result) {
if(progDialog.isShowing())
{
progDialog.dismiss();
}
}
}
I am calling this class in my AboutUs activity :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aboutus);
.
.
.
.
/* Button for going to Departments */
Button ourdepbtn = (Button) findViewById(R.id.departmentsbutton);
ourdepbtn.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
//ourDepartments();
new TheTask().execute();
return false;
}
});
}
However this does'nt start a new activity i.e. Departments. The progress dialog appears and then disappears but activity never loads.
Any suggestions..??
First, you cannot start an activity from a non GUI thread (which Async doInBackground() is). Just start directly inside your Button.onClick() (why you use onTouch?) listener.
If you want to show up a ProgressDialog for the new Activity as soon as possible, you need to create it in the new (child) Activity onCreate(), as your ProgressDialog is connected to the new (child) activity (is it?). Take care about the order of creating layouts (create the ProgressDialog after calling setContentView()).
I am not very sure why you want to show that ProgressDialog. Is there something which delays the display of the childActivity? You loading some data? Then, the Dialog should be related to that loading task (Async I guess).
private class TheTask extends AsyncTask{
Context con;
Intent aboutusIntent;
TabGroupActivity parentActivity;
private TheTask(Context context)
{
this.con=context;
}
#Override
protected void onPreExecute() {
progDialog = ProgressDialog.show(con, "Loading... ",
"please wait....", true);
}
#Override
protected Void doInBackground(Void... params) {
aboutusIntent = new Intent(con, Departments.class);
parentActivity = (TabGroupActivity)getParent();
return null;
}
#Override
protected void onPostExecute(Void result) {
if(progDialog.isShowing())
{
progDialog.dismiss();
}
parentActivity.startChildActivity("Departments", aboutusIntent);
}
}
Thanks for your suggestions Oliver :)