Getting rid of the black screen - android

This question has probably been asked a lot many times.. Yes! I am facing the so called "black screen problem"..
My first activity is which the main activity, in which login is done, and this activity is followed by the next one which is a simple summary report of the user's account.
Now, for this report, i fetch the dataset, parse it and use it to build the table dynamically.
The villan black screen appears here!! The report, as in the table is rendered properly, but upon that screen, this black tranluscent layer keeps appearing.
I tried everything, using handlers, asynctask, translucent theme but nothing helps!! The villan still appears when my summary report loads. It goes away if i press the "Back" button, and the screen appears normal, as it is expected to be when it loads the first time.. I cant figure out what exactly is going wrong, whether, its my coding approach(dynamically generating the table) or it is an emulator problem or what.
My emulator details are as follows:
CPU:ARM
Target: Android 2.3.3
skin: WVGA800
sd card:1024M
Someone please rescue me!!
EDIT:
In my Second activity i do the following:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_summary_report);
ad = new AlertDialog.Builder(this).create();
boolean is = IsConnectedToNetwork();
if (is == true){
Handler execWS = new Handler();
execWS.post(callWS);//Fetch Data via web service and parse it
if(result != null){
Handler genUI = new Handler();
genUI.post(createUI);// generate the table based on "result". ie. in a for loop i create textviews and append it to the table layout
}
}
else{
Error = "Connection Failed. Try Again!";
}
if(Error.length() != 0){
ad.setMessage(Error);
ad.setTitle("Error..");
ad.show();
}
}
My Xml layout for the second activity..
<?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:baselineAligned="false"
android:gravity="center"
android:orientation="vertical">
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:contentDescription="#string/Logo"
android:src="#drawable/complogo"
android:gravity="top"/>
<TextView
android:id="#+id/lblLoginInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_horizontal"/>
</TableLayout>
<TableLayout
android:id="#+id/tblSummRep"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="4"
android:padding="5dip">
</TableLayout>
<TableLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="5dip">
<TextView
android:id="#+id/AppName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/AppName"
android:textColor="#ff6600" />
<TextView
android:id="#+id/AppVersion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/AppVersion"
android:textColor="#ff6600" />
<TextView
android:id="#+id/Disclaimer"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/Disclaimer"
android:textColor="#ff6600" />
</TableLayout>
</LinearLayout>
I append the textview to "tblSummRep"..
UPDATE
my asynctask class..
private class ShareWork extends AsyncTask<Void, Void, Boolean>{
ProgressDialog pDlg;
//String[][] result = null;
protected void onPreExecute(){
pDlg.setMessage("Please wait while the Report Loads...");
pDlg.show();
}
#Override
protected Boolean doInBackground(Void... params) {
boolean RetVal = false;
//my fetch code
return RetVal;
}
protected void onPostExecute(Boolean value){
if(value == true){
pDlg.setMessage("Please try again later!!");
pDlg.show();
}
else{
createUI.run();
}
}
}

I do not know what do you refer to by "black screen problem", but you state that you are fetching data (I guess from a remote server) and that happens. That sounds to me about blocking the UI thread. In which method of the activity are you fetching the data (maybe in the onCreate)? You should not perform time-consuming actions on the graphical thread, such as querying a remote server (which could take some seconds). In these cases always an AsyncTask should be used. The user should receive some feedback about what is going on in the background, so using a ProgressBar is normally recommendable (or at least a spinner).
You can take a look about how to solve a similar problem with an AsyncTask here.
Update
You have just posted your code. The problem lies (as I presumed) in this line of code:
execWS.post(callWS);//Fetch Data via web service and parse it
I guess this is a WS call. You are blocking here the UI thread. Create an AsyncTask the same way as the one of the link I provided, and upon completion of the task execute the rest of the code (display error or the dynamic table with the data).
Your AsyncTask could look like this (I have not tried it):
private class LoadTableTask extends AsyncTask<URL, Integer, Object> {
protected Object doInBackground(URL... urls) {
Handler execWS = new Handler();
execWS.post(urls[0]);//Fetch Data via web service and parse it
return result;
}
protected void onProgressUpdate(Integer... progress) {
//Not used in your case. It would be a good idea to create an undefined progress dialog in your case
}
protected void onPostExecute(Object result) {
if(result != null){
Handler genUI = new Handler();
genUI.post(createUI);// generate the table based on "result". ie. in a for loop i create textviews and append it to the table layout
}
}
}
Your onCreate() method would be replaced by:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_summary_report);
ad = new AlertDialog.Builder(this).create();
boolean is = IsConnectedToNetwork();
if (is == true){
new LoadTableTask().execute(callWS);
}
else{
Error = "Connection Failed. Try Again!";
}
if(Error.length() != 0){
ad.setMessage(Error);
ad.setTitle("Error..");
ad.show();
}
}

Related

Invisible Progress Bar not showing up through code

I'm making a project Android application that takes an image URL, downloads the image and displays the image. In case of an image of bigger size i want to show the user an indeterminate progress that the image is being downloading.
Java Code:
public class MainActivity extends AppCompatActivity {
ImageView downloadedImg;
ProgressBar progressBar;
Handler handler;
public void downloadImage(View view){
progressBar.setVisibility(View.VISIBLE);
ImageDownloader task = new ImageDownloader();
Bitmap myimage;
try {
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
downloadedImg.setImageBitmap(myimage);
}
catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downloadedImg = (ImageView)findViewById(R.id.imageView);
progressBar = (ProgressBar)findViewById(R.id.pbar);
handler = new Handler();
}
public class ImageDownloader extends AsyncTask<String,Void,Bitmap>{
protected void onPreExecute(){
super.onPreExecute();
//progressBar.setVisibility(View.VISIBLE);
}
#Override
protected Bitmap doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.connect();
InputStream inputStream = connection.getInputStream();
Bitmap mybitmap = BitmapFactory.decodeStream(inputStream);
return mybitmap;
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
handler.post(new Runnable() {
#Override
public void run() {
progressBar.setVisibility(View.GONE);
downloadedImg.setVisibility(View.VISIBLE);
}
});
}
}
public void reset(View view){
downloadedImg.setVisibility(View.GONE);
progressBar.setVisibility(View.INVISIBLE);
}
}
XML code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="match_parent"
tools:context="com.example.syeddanish.downloadingimages.MainActivity">
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:onClick="downloadImage"
android:text="Download Image" />
<Button
android:id="#+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/button"
android:onClick="reset"
android:text="Reset" />
<ProgressBar
android:id="#+id/pbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:indeterminate="true"
android:visibility="invisible" />
<ImageView
android:id="#+id/imageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:visibility="gone"
android:layout_below="#+id/button1" />
</RelativeLayout>
The issue i'm facing is that i want the progress bar to become visible when the download starts(i.e when "Download Image button is pressed"). I'm trying to do this in two ways i.e
By using progressbar.setVisibility(View.VISIBLE); in the start of
the onClick method of "Download Image" button.
or
By using progressbar.setVisibility(View.VISIBLE); in theonPreExecute() method of the ASyncTask but the progress bardoes not shows up using any of the above mentioned ways.
Can anyone please point out what i am doing wrong?
Does this code compile and run without NetworkOnMainThreadException?
Your problem is the usage of get()
In this part:
Bitmap myimage;
try {
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
downloadedImg.setImageBitmap(myimage);
}
you try to get an image from task.execute(...), but task.get() as per docu:
[...]Waits if necessary for the computation to complete, and then retrieves its result.[...]
So you are waiting for your "task" to execute on the main thread and blocking it, until done. Because of that, your progress
is never visible, because the UI-Thread is blocked. And once your task finishes,
the progress is set back to be invisible.
Moreover, do not reinvent the weel. Use one of the libraries available out there
for image downloading and caching.
For example: Picasso, Glide
Both also provide the functionality to use a (1) fallback and (2) loading image.
If you still like to try it on your own, then do not do the Pokémon- "gotta catch'em all" way of catching your exceptions, but instead, handle specific Exceptions that might occur and display a message to the user, send it your crash tracker, etc. Only catch exceptions that you expect to be thrown, otherwise...let it crash.
I do not see, why you should catch an exception there.
AsyncTask, Activities and memory leaks
Next is, that AsyncTasks are not tidily coupled to the Activities
life cycle. When you run your task and it executes in background, but
your activity finishes, this task will still be alive and leaks a reference to your activity. This causes the memory leaks, because the GC can't properly do it's job, to clean after you.
Make your AsyncTask at least a static class and stop/kill the task, once your activity finishes.
Multiple Tasks
Next thing, check if you already download the image, once the user clicked the button, or you're going to create multiple tasks.
So, make your ImageDownloader a member of your activity and check if it is already executing or done. (Take it out of your method and put it below the activity class head). When your activity calls onPause() or onDestroy(), kill the task with fire.
Be aware of orientation changes, too.
Android Task API instead of AsyncTask
I highly recommend to use the android task api. (com.google.android.gms.tasks)
It works very well for tasks, both running on the Main- or Workerthreads. Include continuations, provides Future like functionality and can be coupled with Activities.
References: gms Task API Doc
try put downloadedImg.setImageBitmap(myimage); inside onPostExecute(Bitmap bitmap)handler and change:
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
to:
task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg");
also put Bitmap myimage; as global variable on your Asynctask class and change:
Bitmap mybitmap = BitmapFactory.decodeStream(inputStream);
return mybitmap;
to:
myimage= BitmapFactory.decodeStream(inputStream);
on doInBackground
Consider using pBar.setAlpha(1f);
It helped when I'm stuck on a similar problem.

How can I use if/while statements in Android SDK?

I am very new to Android SDK so that question may be very simple.
I try to make am app that shows the current time. I know how to get the current time but i somehow need to update the time. So i try putting a while/if statement that updates the time outside onCreate() and inside main Activity class but 4 errors pop up saying "unexpected end of Decleration.
I cant really find a way to solve this so any help would be much appreciated.
I get the idea that a longer example will be more useful for you.
Make a layout for the application, call the file 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: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.timedemo.MainActivity">
<TextView
android:id="#+id/textClock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignTop="#+id/textView" />
</LinearLayout>
Make a file called MainActivity.java, make it extends Activity (or something else that extends Activity)
Init your layout in the onCreate method.
Use a handler to run code at a delayed time, instead of halting the thread.
public class MainActivity extends AppCompatActivity {
//Handler can be used to send Runnables (code to run) to a specific Thread.
//In this case the UI-thread.
Handler handler = new Handler();
//TextView variable defined in Class-scope.
TextView myTextClock;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Load the layout from activity_main.xml into this Activity.
setContentView(R.layout.activity_main);
//Find the textclock that is mentioned in the activity_main.xml
//Use the ID to find the right View.
//As you can see in the xml-file, the id is 'textClock'.
//Looks like this in the XML --> <TextView android:id="#+id/textClock" />
myTextClock = (TextView) this.findViewById(R.id.textClock);
//Tell the Handler to execute this code at an interval.
handler.postDelayed(codeToRun, 1000);
}
//The runnable contains the code that will be run every second.
Runnable codeToRun = new Runnable() {
#Override
public void run() {
updateTime();
}
};
public void updateTime(){
//Code to update the Clock on the UI-thread
//see: http://developer.android.com/reference/java/text/SimpleDateFormat.html
DateFormat sdf = DateFormat.getDateTimeInstance();
myTextClock.setText(sdf.format(new Date()));
//Make sure it runs the next time too.
handler.postDelayed(codeToRun, 1000);
}
}
Hope this helps you get on the right path.
I'd suggest you use ScheduledThreadPoolExecutor class instead of a while loop. There is an example in this tutorial on how to create a clock app. It can be useful as a starting point.
class ClockTask implements Runnable {
#Override
public void run() {
updateClock();
}
}
ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
se.scheduleAtFixedRate(new ClockTask(), 0, 1000, TimeUnit.MICROSECONDS);
I'm not sure how you plan to make this, but keep in mind that you do not stall the Main Thread. So avoid a construction like this:
while(true){ Thread.sleep(1000); updateTime(); }
A better approach would to use Handler, for example:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
updateTime();
}
}, 1000);
http://developer.android.com/reference/android/os/Handler.html#postDelayed(java.lang.Runnable,%20long)
Hope this helps ;-)

Why does my Android app's view only update under a specific circumstance?

I am working on an Android app that is behaving oddly. One of the first things this app does upon start up, is to start a listening thread that listens to a "server" app, on the same device, to get data. Once this data is received by the listening thread, I use it to update the main view. This, however only works if my app is started after the server app.
First a few details. My app and the server app are on the same device. They communicate with each other via UDP (the server app is a port of a Windows application). My app uses fragments, but the view I want to update is not within a fragment. Now some code.
content_main.xml
<RelativeLayout>
<LinearLayout>
<ImageView
android:id="#+id/my_image_id"
android:src="#drawable/my_image" />
</LinearLayout>
<LinearLayout>
<!-- fragment code here -->
</LinearLayout>
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState){
Listener myListener = new Listener(this);
Thread listenerThread = new Thread(myListener);
listenerThread.setName("My Listener Thread");
listenerThread.start();
}
}
Listener.java
public class Listener implements Runnable {
public Listener (Activity mainActivity) {this.mainActivity = mainActivity;}
private Activity mainActivity;
private ImageView myImageView;
private NewData newData;
#Override
public void run(){
while(true){
// Here is where my app gets the data from the server via UDP.
// This always works, I am always getting the correct data.
myImageView = (ImageView) mainActivity.findViewById(R.id.my_image_id);
mainActivity.runOnUiThread(new Runnable(){
#Override
public void run(){
if(newData == 1){
myImageView.setImageResource(R.drawable.new_image_01);
} else if(newData == 2){
myImageView.setImageResource(R.drawable.new_image_02);
} else {
myImageView.setImageResource(R.drawable.error_image);
}
}
});
}
}
}
Like I said, if I start my app after the server app, then this all works perfectly. The images always changes when the new data changes. However, if I start my app before the server app, or if I restart the server app while my app is still running, then the images never changes, even though I am still getting the correct data from the server app.
What can I do to make sure the view can update at any time?
EDIT: I moved where I get the view to outside of the while loop (as a test) and now the code doesn't work at all.
I gave it a try. apparently your code is working alright, if the thread starts after the activity is been initialized, i don't really know how your server app works so i tried to mimic something like this.
public class TestThreadActivity extends AppCompatActivity {
private Button restart_Button;
private ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_thread);
Toolbar toolbar = (Toolbar) findViewById(R.id.my_custom_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
initializeUI();
}
private void initializeUI() {
restart_Button = (Button) findViewById(R.id.TestThreadActivity_restart_button);
imageView = (ImageView) findViewById(R.id.TestThreadActivity_imageView);
final Listener myListener = new Listener(this);
restart_Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
imageView.setImageResource(R.drawable.piccolo);
final Thread listenerThread = new Thread(myListener);
listenerThread.setName("My Listener Thread");
listenerThread.start();
}
});
}
public class Listener implements Runnable {
public Listener (Activity mainActivity) {this.mainActivity = mainActivity;}
private Activity mainActivity;
private ImageView myImageView;
int newData = 0;
#Override
public void run(){
while(true){
// Here is where my app gets the data from the server via UDP.
// This always works, I am always getting the correct data.
newData = (new Random()).nextInt(3);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myImageView = (ImageView) mainActivity.findViewById(R.id.TestThreadActivity_imageView);
mainActivity.runOnUiThread(new Runnable(){
#Override
public void run(){
System.out.println("newData: "+newData);
if(newData == 1){
myImageView.setImageResource(R.drawable.gohan);
} else if(newData == 2){
myImageView.setImageResource(R.drawable.goku);
} else {
myImageView.setImageResource(R.drawable.piccolo);
}
}
});
}
}
}
}
activity_test_thread.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"
tools:context="activities.list.first.TestThreadActivity">
<include layout="#layout/my_custom_toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="4dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="#+id/TestThreadActivity_restart_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_weight="0.5"
android:text="Start"
android:contentDescription="this will restart the thread"
android:textAllCaps="false" />
</LinearLayout>
<ImageView
android:id="#+id/TestThreadActivity_imageView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="#drawable/gohan" />
</LinearLayout>
</LinearLayout>
Output

how to avoid lag when displaying a large String?

In one of my apps I have to display the Terms of Service which is a kind of a huge HTML-formatted String. Displaying this String in a TextView causes a noticeable lag on mid- to high-end devices (Nexus 5, SGS 4) and an up to 4 seconds freeze on low-end devices.
I managed to reduce the frame drop by about 60% with help of a simple task to move HTML parsing off the main Thread:
public class FromHTMLTask extends AsyncTask<String, Void, Spanned> {
private OnHTMLParseCompleteListener listener;
public FromHTMLTask(OnHTMLParseCompleteListener listener) {
this.listener = listener;
}
public interface OnHTMLParseCompleteListener {
void onHtmlParsed(Spanned text);
}
#Override
protected Spanned doInBackground(String... params) {
return Html.fromHtml(params[0]);
}
#Override
protected void onPostExecute(Spanned result) {
super.onPostExecute(result);
if (listener != null)
listener.onHtmlParsed(result);
}
}
However, the setText() method itself causes a noticeable delay when displaying the processed text and the Choreographer still reports about 35 dropped frames on low-end devices.
Since I cannot call setText() from a background Thread, is there any way to avoid this lag except of splitting the String into multiple parts and performing a lazy load?
TextView was not designed to show large texts. I suppose WebView should work much faster especially if you need to show html.
WebView webView;
String html;
webView.loadDataWithBaseURL("", html, "text/html", "UTF-8", "");
In case you insist using a TextView , you can place it inside a NestedScrollView for a better performance .
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/about"
/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

How to use progresbar with handler to update main UI in android?

I need to display ProgressBar on button action and also need to update same activity page after successful action. ProgressBar is getting displayed but it hangs (it interrupts and hangs) on action process. Circle bar does not animate.
Code sample : ProgessBar is added in layout xml
<ProgressBar
android:id="#+id/loginProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:visibility="invisible"
android:layout_marginTop="100dp" />
Code behind : on button action
public void onClick(View view)
{
if(loginProgressBar ==null)
{
loginProgressBar = (ProgressBar)findViewById(R.id.loginProgressBar);
}
loginProgressBar.setVisibility(View.VISIBLE);
myHandler.post(new Runnable()
{
public void run()
{
Intent intent = new Intent(LoginActivity.this,RegisterActivity.class);
startActivity(intent);
}
});
}
It seems that myHandler is updating main UI and at the same time. ProgressBar is also part of Main UI, so it hangs.
Please provide solution so that ProgressBar works without any interruption.
What you need is an AsyncTask.
Take a look at the example in the link provided, it is exactly what you are looking for !
Hope it helps !

Categories

Resources