How to show images with indirect link/URL using Glide - java

I am trying to download blog features images form a WordPress blog page and then load them later.
Right now, every time the user scrolls down and up the image load again and again. Any idea...plzzz..I tried many solutions, for example, this one:
Preload multiple images with Glide
But, it didn't work.
I am using implementation 'com.github.bumptech.glide:glide:3.7.0'
And this is my code:
RecyclerViewAdapter
public void getthumbnail(String imageurl, final ImageView imageView, final int position){
ServiceWrapper serviceWrapper = new ServiceWrapper(null);
Call<GetThumbnail> call = serviceWrapper.getThumbnailCall(imageurl);
call.enqueue(new Callback<GetThumbnail>() {
#Override
public void onResponse(Call<GetThumbnail> call, Response<GetThumbnail> response) {
if (response.body() != null && response.isSuccessful()) {
try {
if (response.body().getMediaDetails()!=null){
// Log.e("recycler adapter", " image is here-- " + response.body().getMediaDetails().getSizes().getThumbnail().getSourceUrl());
// Log.e("Full IMG SIZE - ", " THIS IS FULL IMAGE URL-- " + response.body().getMediaDetails().getSizes().getFull().getSourceUrl());
imagepath.add(position, response.body().getMediaDetails().getSizes().getFull().getSourceUrl());
Glide.with(mContext)
.load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(imageView);
}else {
}
}catch (Exception e){
// Log.e("adapter", "fail not media tag "+ e.toString());
}
}
}
#Override
public void onFailure(Call<GetThumbnail> call, Throwable t) {
// Log.e("adapter", " faile image "+t.toString());
}
});
}
UPDATE
I found this code and I put it on top of the other Glide code but it didn't work:
Glide.with(mContext)
.load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
.downloadOnly(new SimpleTarget<File>() {
#Override
public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {
}
});
UPDATE:
Now I used this code and it doesnt download the images faster:
Glide.with(mContext)
.load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
.downloadOnly(new SimpleTarget<File>() {
#Override
public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {
Glide.with(mContext)
.load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(imageView);
}
});
Here is the complete ViewAdapter.java
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.v7.widget.CardView;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class RecyclerViewAdapter extends
RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ArrayList<Model> dataset;
private Context mContext;
private ArrayList<Model> list;
private RecyclerViewAdapter adapter;
private RecyclerView recyclerView;
private LinearLayoutManager mLayoutManager;
public static List<WPPost> mListPost;
ArrayList<String> imagepath = new ArrayList<>();
private String baseURL = "https://www.myfitbytes.com/";
public RecyclerViewAdapter(ArrayList<Model> mlist, Context context) {
this.dataset = mlist;
this.mContext = context;
}
public static class ImageTypeViewHolder extends RecyclerView.ViewHolder{
TextView title, subtitle, date;
ImageView imageView;
CardView cardview;
public ImageTypeViewHolder(View itemView) {
super(itemView);
this.title = (TextView) itemView.findViewById(R.id.title);
//this.subtitle = (TextView) itemView.findViewById(R.id.subtitle);
this.date = (TextView) itemView.findViewById(R.id.date);
this.imageView = (ImageView) itemView.findViewById(R.id.Icon);
this.cardview = (CardView) itemView.findViewById(R.id.cardview);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from( parent.getContext()).inflate(R.layout.postdetails, parent, false);
return new ImageTypeViewHolder(view) ;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final Model object = dataset.get(position);
// Log.d("RecyclerViewAdapter", "IMAGE="+object.Image);
imagepath.add(position, "");
if (Build.VERSION.SDK_INT >= 24)
{
//( (ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle , Html.FROM_HTML_MODE_LEGACY));
( (ImageTypeViewHolder) holder).title.setText( Html.fromHtml(object.title , Html.FROM_HTML_MODE_LEGACY) );
( (ImageTypeViewHolder) holder).date.setText( Html.fromHtml(object.date , Html.FROM_HTML_MODE_LEGACY) );
}
else
{
//( (ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle ));
( (ImageTypeViewHolder) holder).title.setText( Html.fromHtml(object.title ));
( (ImageTypeViewHolder) holder).date.setText( Html.fromHtml(object.date ));
}
( (ImageTypeViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, WPPostDetails.class);
intent.putExtra("itemPosition", position);
mContext.startActivity(intent);
}
});
try {
getthumbnail(object.Image, ( (ImageTypeViewHolder) holder).imageView, position);
}catch (Exception e){
// Log.e("adapter ","failed to get image "+e.toString() );
}
/// dataset.get(position)
}
public void getthumbnail(String imageurl, final ImageView imageView, final int position){
ServiceWrapper serviceWrapper = new ServiceWrapper(null);
Call<GetThumbnail> call = serviceWrapper.getThumbnailCall(imageurl);
call.enqueue(new Callback<GetThumbnail>() {
#Override
public void onResponse(Call<GetThumbnail> call, final Response<GetThumbnail> response) {
if (response.body() != null && response.isSuccessful()) {
try {
if (response.body().getMediaDetails()!=null){
// Log.e("recycler adapter", " image is here-- " + response.body().getMediaDetails().getSizes().getThumbnail().getSourceUrl());
// Log.e("Full IMG SIZE - ", " THIS IS FULL IMAGE URL-- " + response.body().getMediaDetails().getSizes().getFull().getSourceUrl());
imagepath.add(position, response.body().getMediaDetails().getSizes().getFull().getSourceUrl());
Glide.with(mContext)
.load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
.downloadOnly(new SimpleTarget<File>() {
#Override
public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {
Glide.with(mContext)
.load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(imageView);
}
});
}else {
}
}catch (Exception e){
// Log.e("adapter", "fail not media tag "+ e.toString());
}
}
}
#Override
public void onFailure(Call<GetThumbnail> call, Throwable t) {
// Log.e("adapter", " faile image "+t.toString());
}
});
}
#Override
public int getItemCount() {
return dataset.size() ;
}
}
UPDATE
So, now that I tried to update glide 3 to 4.x I am getting the following in error in build.gradle.
All com.android.support libraries must use the exact same version specification (mixing versions can lead to runtime crashes). Found versions 27.1.1, 27.1.0, 26.1.0. Examples include com.android.support:support-compat:27.1.1 and com.android.support:animated-vector-drawable:27.1.0 less... (⌘F1)
There are some combinations of libraries, or tools and libraries, that are incompatible, or can lead to bugs. One such incompatibility is compiling with a version of the Android support libraries that is not the latest version (or in particular, a version lower than your targetSdkVersion).
And the code is:
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.myfitbytes"
minSdkVersion 14
targetSdkVersion 26
versionCode 3
versionName "3.0"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support:support-v4:26.1.0'
//library for wordpress rest api
implementation 'com.android.support:cardview-v7:26.1.0'
implementation 'com.android.support:recyclerview-v7:26.0.0-beta2'
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
implementation 'com.squareup.okhttp:okhttp:2.4.0'
implementation 'com.squareup.okhttp3:okhttp:2.0.2'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
//implementation 'com.github.bumptech.glide:glide:3.7.0'
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
implementation 'com.android.volley:volley:1.0.0'
implementation 'org.ocpsoft.prettytime:prettytime:4.0.1.Final'
//Firebase
implementation 'com.google.firebase:firebase-core:16.0.4'
implementation 'com.google.firebase:firebase-messaging:17.3.3'
implementation 'org.apache.httpcomponents:httpcore:4.4.1'
//implementation 'org.apache.httpcomponents:httpclient:4.5.6'
//implementation group: 'org.apache.httpcomponents' , name: 'httpclient- android' , version: '4.3.5.1'
implementation files('libs/google-http-client-1.24.1.jar')
implementation files('libs/httpclient-4.5.3.jar')
//bottom nav
implementation 'com.aurelhubert:ahbottomnavigation:2.1.0'
//picasso to download image from url faster
implementation 'com.squareup.picasso:picasso:2.71828'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
apply plugin: 'com.google.gms.google-services'
And, this line is in red:
implementation 'com.android.support:appcompat-v7:26.1.0'

The loading delay problem and image item disposition comes from onBindViewHolder method where you call a webservice in it. Everytime a list item is appeared in scrolling, onBindViewHolder is called to initialize the view with correct values. So you should not call a webservice here at all (but in the code it is called everytime). As Glide creates a queue of requests, it guarantees that the image would be downloaded only one time because it caches them. Also it guarantees that the image would be loaded if the ImageView is in visible area of the RecyclerView in scrolling process.
On the other hand, reaching the image url in your case needs two level of webservice api-s. So we should combine Glide procedure and retrieving the image url procedure to reach the best performance. Using Glide-OkHttp3-Integration library, I have developed this two level of asynchronous calls which makes the Glide aware of your data flow.
• Note that you should clean and rebuild your project to create GlideApp class in compile time.
ViewAdapter.java
// some code blocks
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final Model object = dataset.get(position);
if (Build.VERSION.SDK_INT >= 24) {
// ( (ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle , Html.FROM_HTML_MODE_LEGACY));
((ImageTypeViewHolder) holder).title.setText(Html.fromHtml(object.title , Html.FROM_HTML_MODE_LEGACY));
((ImageTypeViewHolder) holder).date.setText(Html.fromHtml(object.date , Html.FROM_HTML_MODE_LEGACY));
} else {
// ((ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle));
((ImageTypeViewHolder) holder).title.setText(Html.fromHtml(object.title));
((ImageTypeViewHolder) holder).date.setText(Html.fromHtml(object.date));
}
((ImageTypeViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, WPPostDetails.class);
intent.putExtra("itemPosition", position);
mContext.startActivity(intent);
}
});
JsonApiGlideUrl url = new JsonApiGlideUrl(object.Image);
GlideApp.with(imageView.getContext())
.load(url)
.into(imageView);
}
// some code blocks
OkHttpAppGlideModule.java
import android.content.Context;
import android.support.annotation.NonNull;
import com.bumptech.glide.Glide;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;
import java.io.InputStream;
/**
* Registers OkHttp related classes via Glide's annotation processor.
*
* <p>For Applications that depend on this library and include an
* {#link AppGlideModule} and Glide's annotation processor, this class
* will be automatically included.
*/
#GlideModule
public final class OkHttpAppGlideModule extends AppGlideModule {
#Override
public void registerComponents(#NonNull Context context, #NonNull Glide glide, #NonNull Registry registry) {
registry.replace(JsonApiGlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
}
#Override
public boolean isManifestParsingEnabled() {
return false;
}
}
JsonApiGlideUrl.java
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.Headers;
import java.net.URL;
public class JsonApiGlideUrl extends GlideUrl {
public JsonApiGlideUrl(URL url) {
super(url);
}
public JsonApiGlideUrl(String url) {
super(url);
}
public JsonApiGlideUrl(URL url, Headers headers) {
super(url, headers);
}
public JsonApiGlideUrl(String url, Headers headers) {
super(url, headers);
}
}
OkHttpUrlLoader.java
import android.support.annotation.NonNull;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.model.ModelLoaderFactory;
import com.bumptech.glide.load.model.MultiModelLoaderFactory;
import java.io.InputStream;
import okhttp3.Call;
import okhttp3.OkHttpClient;
/**
* A simple model loader for fetching media over http/https using OkHttp.
*/
public class OkHttpUrlLoader implements ModelLoader<JsonApiGlideUrl, InputStream> {
private final Call.Factory client;
// Public API.
#SuppressWarnings("WeakerAccess")
public OkHttpUrlLoader(#NonNull Call.Factory client) {
this.client = client;
}
#Override
public boolean handles(#NonNull JsonApiGlideUrl url) {
return true;
}
#Override
public LoadData<InputStream> buildLoadData(#NonNull JsonApiGlideUrl model, int width, int height, #NonNull Options options) {
return new LoadData<>(model, new OkHttpStreamFetcher(client, model));
}
/**
* The default factory for {#link OkHttpUrlLoader}s.
*/
// Public API.
#SuppressWarnings("WeakerAccess")
public static class Factory implements ModelLoaderFactory<JsonApiGlideUrl, InputStream> {
private static volatile Call.Factory internalClient;
private final Call.Factory client;
private static Call.Factory getInternalClient() {
if (internalClient == null) {
synchronized (Factory.class) {
if (internalClient == null) {
internalClient = new OkHttpClient();
}
}
}
return internalClient;
}
/**
* Constructor for a new Factory that runs requests using a static singleton client.
*/
public Factory() {
this(getInternalClient());
}
/**
* Constructor for a new Factory that runs requests using given client.
*
* #param client this is typically an instance of {#code OkHttpClient}.
*/
public Factory(#NonNull Call.Factory client) {
this.client = client;
}
#NonNull
#Override
public ModelLoader<JsonApiGlideUrl, InputStream> build(#NonNull MultiModelLoaderFactory multiFactory) {
return new OkHttpUrlLoader(client);
}
#Override
public void teardown() {
// Do nothing, this instance doesn't own the client.
}
}
}
OkHttpStreamFetcher.java
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.HttpException;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.util.ContentLengthInputStream;
import com.bumptech.glide.util.Preconditions;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
/**
* Fetches an {#link InputStream} using the okhttp library.
*/
public class OkHttpStreamFetcher implements DataFetcher<InputStream>, okhttp3.Callback {
private static final String TAG = "OkHttpFetcher";
private final Call.Factory client;
private final JsonApiGlideUrl url;
private OkHttpJsonApiFetcher okHttpJsonApiFetcher;
private InputStream stream;
private ResponseBody responseBody;
private DataCallback<? super InputStream> callback;
// call may be accessed on the main thread while the object is in use on other threads. All other
// accesses to variables may occur on different threads, but only one at a time.
private volatile Call call;
// Public API.
#SuppressWarnings("WeakerAccess")
public OkHttpStreamFetcher(Call.Factory client, JsonApiGlideUrl url) {
this.client = client;
this.url = url;
}
#Override
public void loadData(#NonNull Priority priority, #NonNull final DataCallback<? super InputStream> callback) {
okHttpJsonApiFetcher = new OkHttpJsonApiFetcher(client, url);
okHttpJsonApiFetcher.loadData(new DataCallback<GlideUrl>() {
#Override
public void onDataReady(#Nullable GlideUrl data) {
Request.Builder requestBuilder = new Request.Builder().url(data.toStringUrl());
for (Map.Entry<String, String> headerEntry : data.getHeaders().entrySet()) {
String key = headerEntry.getKey();
requestBuilder.addHeader(key, headerEntry.getValue());
}
Request request = requestBuilder.build();
OkHttpStreamFetcher.this.callback = callback;
call = client.newCall(request);
call.enqueue(OkHttpStreamFetcher.this);
}
#Override
public void onLoadFailed(#NonNull Exception e) {
callback.onLoadFailed(e);
}
});
}
#Override
public void onFailure(#NonNull Call call, #NonNull IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "OkHttp failed to obtain result", e);
}
callback.onLoadFailed(e);
}
#Override
public void onResponse(#NonNull Call call, #NonNull Response response) {
responseBody = response.body();
if (response.isSuccessful()) {
long contentLength = Preconditions.checkNotNull(responseBody).contentLength();
stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
callback.onDataReady(stream);
} else {
callback.onLoadFailed(new HttpException(response.message(), response.code()));
}
}
#Override
public void cleanup() {
okHttpJsonApiFetcher.cleanup();
try {
if (stream != null) {
stream.close();
}
} catch (IOException e) {
// Ignored
}
if (responseBody != null) {
responseBody.close();
}
callback = null;
}
#Override
public void cancel() {
okHttpJsonApiFetcher.cancel();
Call local = call;
if (local != null) {
local.cancel();
}
}
#NonNull
#Override
public Class<InputStream> getDataClass() {
return InputStream.class;
}
#NonNull
#Override
public DataSource getDataSource() {
return DataSource.REMOTE;
}
}
OkHttpJsonApiFetcher.java
import android.support.annotation.NonNull;
import android.util.Log;
import com.bumptech.glide.load.HttpException;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
/**
* Fetches an {#link InputStream} using the okhttp library.
*/
public class OkHttpJsonApiFetcher implements okhttp3.Callback {
private static final String TAG = "OkHttpJsonApiFetcher";
private final Call.Factory client;
private final JsonApiGlideUrl url;
private ResponseBody responseBody;
private DataFetcher.DataCallback<? super GlideUrl> callback;
// call may be accessed on the main thread while the object is in use on other threads. All other
// accesses to variables may occur on different threads, but only one at a time.
private volatile Call call;
// Public API.
#SuppressWarnings("WeakerAccess")
public OkHttpJsonApiFetcher(Call.Factory client, JsonApiGlideUrl url) {
this.client = client;
this.url = url;
}
public void loadData(#NonNull final DataFetcher.DataCallback<? super GlideUrl> callback) {
Request.Builder requestBuilder = new Request.Builder().get().url(url.toStringUrl());
for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
String key = headerEntry.getKey();
requestBuilder.addHeader(key, headerEntry.getValue());
}
Request request = requestBuilder.build();
this.callback = callback;
call = client.newCall(request);
call.enqueue(this);
}
#Override
public void onFailure(#NonNull Call call, #NonNull IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "OkHttp failed to obtain result", e);
}
callback.onLoadFailed(e);
}
#Override
public void onResponse(#NonNull Call call, #NonNull Response response) {
responseBody = response.body();
if (response.isSuccessful() && responseBody != null) {
try {
String json = responseBody.string();
String url = JsonApiDataModel.getSourceUrl(json);
callback.onDataReady(new GlideUrl(url));
} catch (IOException e) {
callback.onLoadFailed(new HttpException(response.message(), response.code()));
e.printStackTrace();
}
} else {
callback.onLoadFailed(new HttpException(response.message(), response.code()));
}
}
public void cleanup() {
if (responseBody != null) {
responseBody.close();
}
callback = null;
}
public void cancel() {
Call local = call;
if (local != null) {
local.cancel();
}
}
}
JsonApiDataModel.java
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class JsonApiDataModel {
#SerializedName("media_details")
MediaDetails mediaDetails;
public static String getSourceUrl(String json) {
return new Gson().fromJson(json, JsonApiDataModel.class).mediaDetails.sizes.full.sourceUrl;
}
public class MediaDetails {
#SerializedName("sizes")
Sizes sizes;
}
public class Sizes {
// you can use full, medium or thumbnail here!
#SerializedName("full")
Full full;
}
public class Full {
#SerializedName("source_url")
String sourceUrl;
}
}
.
Test Code & Visual Result:
import com.aminography.glideapplication.glide.okhttp3.GlideApp;
import com.aminography.glideapplication.glide.okhttp3.JsonApiGlideUrl;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView imageView = findViewById(R.id.imageView);
TextView textView = findViewById(R.id.textView);
String sourceUrl = "https://www.myfitbytes.com/wp-json/wp/v2/media/2811";
textView.setText("JsonApiGlideUrl:\n\n" + sourceUrl);
final JsonApiGlideUrl url = new JsonApiGlideUrl(sourceUrl);
GlideApp.with(MainActivity.this).load(url).into(imageView);
}
}

• First of all, I strongly recommend you to use Glide v4.
The loading delay problem and image item disposition comes from onBindViewHolder method where you call a webservice in it. Everytime a list item is appeared in scrolling, onBindViewHolder is called to initialize the view with correct values. So you should not call a webservice here at all (but in the code it is called everytime). As Glide creates a queue of requests, it guarantees that the image would be downloaded only one time because it caches them. Also it guarantees that the image would be loaded if the ImageView is in visible area of the RecyclerView in scrolling process. In addition, by setting diskCacheStrategy to DiskCacheStrategy.ALL, Glide shows an image which is resized according to the ImageView size.
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final Model object = dataset.get(position);
if (Build.VERSION.SDK_INT >= 24) {
// ( (ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle , Html.FROM_HTML_MODE_LEGACY));
((ImageTypeViewHolder) holder).title.setText(Html.fromHtml(object.title , Html.FROM_HTML_MODE_LEGACY));
((ImageTypeViewHolder) holder).date.setText(Html.fromHtml(object.date , Html.FROM_HTML_MODE_LEGACY));
} else {
// ((ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle));
((ImageTypeViewHolder) holder).title.setText( Html.fromHtml(object.title));
((ImageTypeViewHolder) holder).date.setText( Html.fromHtml(object.date));
}
((ImageTypeViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, WPPostDetails.class);
intent.putExtra("itemPosition", position);
mContext.startActivity(intent);
}
});
Glide.with(imageView.getContext())
.load(object.Image)
.apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL))
.into(imageView);
}
By the above changes, your RecyclerView should work smoothly as well as fast. If you want to make Glide more integrated with RecyclerView, you can follow this. But I think this is not necessary and the previous level is enough.

The current version for Glide is '4.8.0'. Any reason you don't want to work with that version? https://github.com/bumptech/glide
https://github.com/bumptech/glide/blob/master/samples/flickr/src/main/java/com/bumptech/glide/samples/flickr/FlickrPhotoGrid.java
You need to use a RecyclerView. Here is an example:
grid.addItemDecoration(new RecyclerView.ItemDecoration() {
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
outRect.set(gridMargin, gridMargin, gridMargin, gridMargin);
}
});
grid.setRecyclerListener(new RecyclerView.RecyclerListener() {
#Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
PhotoViewHolder photoViewHolder = (PhotoViewHolder) holder;
GlideApp.with(FlickrPhotoGrid.this).clear(photoViewHolder.imageView);
}
});

Related

My app is crashing after I implement In-App-Update from Play Store

My app is building successfully but when I open it it closes by itself...
I was able to successfully implement In-App-Review! But Update is failing and crashing my app on start.
I have an error in AppUpdateManager. I reproduced the code from scratch line by line... And the app crashed on its own, after build, when I called the App Update Manager:
private final AppUpdateManager mAppUpdateManager = AppUpdateManagerFactory.create(this);
Lib to Implement: https://developer.android.com/guide/playcore/in-app-updates
My MainActivity
package com.baraokeskina;
import com.baraokeskina.ReviewsApp.ReviewsManager;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.google.android.gms.tasks.Task;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.play.core.appupdate.AppUpdateInfo;
import com.google.android.play.core.appupdate.AppUpdateManager;
import com.google.android.play.core.appupdate.AppUpdateManagerFactory;
import com.google.android.play.core.install.InstallStateUpdatedListener;
import com.google.android.play.core.install.model.AppUpdateType;
import com.google.android.play.core.install.model.InstallStatus;
import com.google.android.play.core.install.model.UpdateAvailability;
import com.google.android.play.core.review.ReviewInfo;
import com.google.android.play.core.review.ReviewManager;
import com.google.android.play.core.review.ReviewManagerFactory;
import com.swmansion.reanimated.BuildConfig;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
#Override
protected String getMainComponentName() {
return "BaraokeSkina";
}
private ReviewInfo reviewInfo;
private ReviewManager manager;
private static final int RC_APP_UPDATE = 22;
private final AppUpdateManager mAppUpdateManager = AppUpdateManagerFactory.create(this);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
activateUpdate();
if (new ReviewsManager().getDaysAppInstaled(this) >= 4) {
activateReviewInfo();
}
}
void activateUpdate(){
Task<AppUpdateInfo> appUpdateInfoTask = mAppUpdateManager.getAppUpdateInfo();
appUpdateInfoTask.addOnSuccessListener(result -> {
if (result.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& result.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
try {
mAppUpdateManager.startUpdateFlowForResult(result, AppUpdateType.FLEXIBLE, MainActivity.this, RC_APP_UPDATE);
} catch (IntentSender.SendIntentException e) {
System.out.println(e.getMessage());
}
}
});
mAppUpdateManager.registerListener(installStateUpdatedListener);
}
private final InstallStateUpdatedListener installStateUpdatedListener = installState -> {
if (installState.installStatus() == InstallStatus.DOWNLOADED) {
showCompleteUpdate();
}
};
#Override
protected void onStop() {
super.onStop();
if (mAppUpdateManager != null) {
mAppUpdateManager.unregisterListener(installStateUpdatedListener);
}
}
private void showCompleteUpdate() {
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), "Atualização pronta para ser Instalada...",
Snackbar.LENGTH_INDEFINITE);
snackbar.setAction("Instalar", view -> mAppUpdateManager.completeUpdate());
snackbar.show();
}
void activateReviewInfo()
{
Activity context = this;
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(() -> {
manager = ReviewManagerFactory.create(context);
Task<ReviewInfo> request = manager.requestReviewFlow();
request.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
reviewInfo = task.getResult();
Task<Void> flow = manager.launchReviewFlow(context, reviewInfo);
flow.addOnCompleteListener(result -> {
});
}
});
request.addOnFailureListener(e -> System.out.println(e.getMessage()));
}, 15000);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_APP_UPDATE && resultCode != RESULT_OK) {
Toast.makeText(this, "Cancelado", Toast.LENGTH_SHORT).show();
}
}
/**
* Returns the instance of the {#link ReactActivityDelegate}. There the RootView is created and
* you can specify the rendered you wish to use (Fabric or the older renderer).
*/
#Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new MainActivityDelegate(this, getMainComponentName());
}
public static class MainActivityDelegate extends ReactActivityDelegate {
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
super(activity, mainComponentName);
}
#Override
protected ReactRootView createRootView() {
ReactRootView reactRootView = new ReactRootView(getContext());
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
return reactRootView;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
reviewInfo = null;
manager = null;
}
}
Bild.gradle implementations
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'com.facebook.android:facebook-android-sdk:[4,5)'
implementation 'com.google.android.material:material:1.1.0'
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:0.68.1!!" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
implementation project(':react-native-fbsdk-next')
implementation project(':react-native-linear-gradient')
implementation project(':react-native-svg')
implementation "androidx.multidex:multidex:2.0.1"
implementation project(':react-native-vector-icons')
implementation project(':watermelondb')
implementation project(':watermelondb-jsi')
implementation 'com.google.android.gms:play-services-tasks:18.0.2'
implementation project(path: ":#react-native-firebase_analytics")
implementation project(path: ":#react-native-firebase_inAppMessaging")
implementation 'com.google.android.play:review:2.0.1'
implementation 'com.google.android.play:app-update:2.0.1'
implementation 'com.google.android.play:asset-delivery:2.0.1'
implementation 'com.google.android.play:feature-delivery:2.0.1'
}
My Default Config - Build.gradle:
defaultConfig {
applicationId "com.baraokeskina"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 12
versionName "1.0.11"
multiDexEnabled true
resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
vectorDrawables.useSupportLibrary = true
if (isNewArchitectureEnabled()) {
// We configure the NDK build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
ndkBuild {
arguments "APP_PLATFORM=android-21",
"APP_STL=c++_shared",
"NDK_TOOLCHAIN_VERSION=clang",
"GENERATED_SRC_DIR=$buildDir/generated/source",
"PROJECT_BUILD_DIR=$buildDir",
"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build"
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
cppFlags "-std=c++17"
// Make sure this target name is the same you specify inside the
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
targets "baraokeskina_appmodules"
// Fix for windows limit on number of character in file paths and in command lines
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
arguments "NDK_OUT=${rootProject.projectDir.getParent()}\\.cxx",
"NDK_APP_SHORT_COMMANDS=true"
}
}
}
if (!enableSeparateBuildPerCPUArchitecture) {
ndk {
abiFilters (*reactNativeArchitectures())
}
}
}
}
I Has resolved this question
The problem is
AppUpdateManagerFactory.create(this)
Only Can be instancied on one time.

Can you use Flutter MethodChannel to return a native map from Java

I am attempting to to create a widget from a native view navigation map using method channels and AndroidViews but I keep running into this problem:
E/MethodChannel#flutter/platform_views( 2258): Failed to handle method call
E/MethodChannel#flutter/platform_views( 2258): java.lang.IllegalArgumentException: Cannot add a null child view to a ViewGroup.
Here is the flutter Code :
Main.dart
import 'navigation_view.dart';
import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart';
import 'package:flutter/material.dart';
import 'customButton1.dart';
import 'Constantes.dart';
void main() => runApp(MaterialApp(home: TextViewExample()));
class TextViewExample extends StatefulWidget {
#override
_TextViewExampleState createState() => _TextViewExampleState();
}
class _TextViewExampleState extends State<TextViewExample>
with SingleTickerProviderStateMixin {
#override
void initState() {
super.initState();
}
Widget build(BuildContext context) {
// var s = NavigationView(
// onNavigationViewCreated: _onNavigationViewCreated,
// );
double screenWidth, screenHeight;
Size size = MediaQuery.of(context).size;
screenHeight = size.height;
screenWidth = size.width;
print("FLUTTER INIT");
return Scaffold(
body: SafeArea(
child: Stack(children: [
Positioned(
width: screenWidth,
height: screenHeight - 220,
child: Container(
child: NavigationView(
onNavigationViewCreated: _onNavigationViewCreated,
),
),
),
Positioned(
bottom: 75,
child: Container(
height: screenHeight,
width: screenWidth,
void _onNavigationViewCreated(NavigationViewController controller) {}
}
Here is navigation_view.dart
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
typedef void NavigationViewCreatedCallback(NavigationViewController controller);
class NavigationView extends StatefulWidget {
const NavigationView({
Key key,
this.onNavigationViewCreated,
}) : super(key: key);
final NavigationViewCreatedCallback onNavigationViewCreated;
#override
State<StatefulWidget> createState() => _NavigationViewState();
}
class _NavigationViewState extends State<NavigationView> {
#override
Widget build(BuildContext context) {
if (defaultTargetPlatform == TargetPlatform.android) {
return AndroidView(
viewType: 'com.Mavic.Cabinn/navigationview',
onPlatformViewCreated: _onPlatformViewCreated,
);
}
return Text(
'$defaultTargetPlatform is not yet supported by the navigation_view plugin');
}
void _onPlatformViewCreated(int id) {
if (widget.onNavigationViewCreated == null) {
return;
}
widget.onNavigationViewCreated(new NavigationViewController._(id));
}
}
class NavigationViewController {
NavigationViewController._(int id)
: _channel = new MethodChannel(
'com.Mavic.Cabinn/navigationview$id');
final MethodChannel _channel;
// Future<void> setNavigation() async {
// try {
// Future.delayed(const Duration(seconds: 1), () async {
// await _channel.invokeMethod('EmpezarNavegacion');
//
// return;
// });
// } on PlatformException catch (e) {
// print(e);
// }
// Future<void> setNavigation() async {
// assert(AndroidView != null);
// return _channel.invokeMethod('EmpezarNavegacion');
// }
//}
Future<dynamic> setNavigation() async {
String message;
try {
final String result = await _channel.invokeMethod('EmpezarNagevacion');
message = result;
} on PlatformException catch (e) {
print(message);
}
}
}
And Finally the Java Code
package com.example.embeded_java_test;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.location.Location;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.AbsoluteSizeSpan;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.mapbox.api.directions.v5.DirectionsCriteria;
import com.mapbox.api.directions.v5.models.BannerInstructions;
import com.mapbox.api.directions.v5.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute;
import com.example.embeded_java_test.R;
import com.mapbox.services.android.navigation.ui.v5.NavigationView;
import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions;
import com.mapbox.services.android.navigation.ui.v5.OnNavigationReadyCallback;
//import com.mapbox.services.android.navigation.ui.v5.listeners.BannerInstructionsListener;
//import com.mapbox.services.android.navigation.ui.v5.listeners.InstructionListListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.BannerInstructionsListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.InstructionListListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.NavigationListener;
//import com.mapbox.services.android.navigation.ui.v5.listeners.SpeechAnnouncementListener;
//import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
import com.mapbox.services.android.navigation.ui.v5.listeners.SpeechAnnouncementListener;
import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;
import java.util.Locale;
import java.util.concurrent.Future;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import org.jetbrains.annotations.NotNull;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformView;
import com.example.embeded_java_test.MainActivity;
public class EmbeddedNavigationActivity extends AppCompatActivity implements OnNavigationReadyCallback,
NavigationListener, ProgressChangeListener, InstructionListListener, SpeechAnnouncementListener,
BannerInstructionsListener,PlatformView, MethodCallHandler {
private Point ORIGIN = Point.fromLngLat(-77.03194990754128, 38.909664963450105);
private Point DESTINATION = Point.fromLngLat(-77.0270025730133, 38.91057077063121);
private final int INITIAL_ZOOM = 16;
private NavigationView navigationView;
private View spacer;
private TextView speedWidget;
private final MethodChannel methodChannel;
private boolean bottomSheetVisible = true;
private boolean instructionListShown = false;
private NavigationMapRoute navigationMapRoute;
// #Override
// public void onCreate(#Nullable Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
// navigationView = findViewById(R.id.navigationView);
// navigationView.onCreate(savedInstanceState);
// setTheme(R.style.Theme_AppCompat_Light_NoActionBar);
// //initNightMode();
#Override
public void dispose() {}
private Context context;
private Activity activity;
private Bundle savedInstance;
public EmbeddedNavigationActivity(Context currentContext, Activity currentActivity, Bundle currentBundle,BinaryMessenger messenger, int id)
{
new MainActivity();
MainActivity newMain = new MainActivity();
this.activity=this;
System.out.println(activity + "Activity");
this.context=this;
System.out.println(context + "Context");
System.out.println(activity);
Log.i("Here", "Constructor!!!");
System.out.println(activity + " This Activity");
this.savedInstance=currentBundle;
System.out.println(currentContext + "Context");
//
methodChannel = new MethodChannel(messenger, "com.Mavic.Cabinn/navigationview_" + id);
methodChannel.setMethodCallHandler(this);
}
#Override
public View getView() {
Log.i("Here", "GETVIEW");
return navigationView;
}
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
Log.i("MSG", "CALLING SET TEXT");
switch (methodCall.method) {
case "EmpezarNavegacion":
EmpezarNavegacion(methodCall, result);
result.success(null);
break;
default:
result.notImplemented();
}
}
public void EmpezarNavegacion(MethodCall methodCall, Result result)
{
double LtLang = (double) methodCall.arguments;
result.success(null);
Mapbox.getInstance(context, activity.getString(R.string.access_token));
activity.setContentView(R.layout.cabinn_nav);
navigationView =activity.findViewById(R.id.navigationView);
//super.onCreate(savedInstanceState);
//Mapbox.getInstance(this,getString(R.string.access_token));
//navigationView =(NavigationView)findViewById(R.id.navigationView);
if(navigationView==null)
{
Log.e("ERROR NAVEGACION","NAVIGATION VIEW ES NULL, NO ESTA SETEADO EL CONTENT");
return;
}
//fabNightModeToggle = findViewById(R.id.fabToggleNightMode);
//speedWidget = findViewById(R.id.speed_limit);
//spacer = findViewById(R.id.spacer);
//setSpeedWidgetAnchor(R.id.summaryBottomSheet);
// ORIGIN=ORIGEN;
// DESTINATION=DESTINO;
CameraPosition initialPosition = new CameraPosition.Builder()
.target(new LatLng(ORIGIN.latitude(), ORIGIN.longitude()))
.zoom(INITIAL_ZOOM)
.build();
//navigationView.onCreate(savedInstanceState);
navigationView.onCreate(this.savedInstance);
navigationView.initialize(this, initialPosition);
}
#Override
public void onNavigationReady(boolean isRunning) {
//navigationView.findViewById(R.id.instructionLayoutText).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.instructionListLayout).setVisibility(View.INVISIBLE);
//navigationView.findViewById(R.id.maneuverView).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.summaryBottomSheet).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.feedbackFab).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.subStepText).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.subStepLayout).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.summaryContentLayout).setVisibility(View.INVISIBLE);
//navigationView.findViewById(R.id.subManeuverView).setVisibility(View.INVISIBLE);
//navigationView.findViewById(R.id.stepDistanceText).setVisibility(View.INVISIBLE);
//navigationView.findViewById(R.id.stepPrimaryText).setVisibility(View.INVISIBLE);
//navigationView.findViewById(R.id.stepSecondaryText).setVisibility(View.INVISIBLE);
fetchRoute();
}
public void onStart_() {
Log.i("NAV","NAVIGATION START");
navigationView.onStart();
}
public void onResume_() {
navigationView.onResume();
}
public void onLowMemory_() {
navigationView.onLowMemory();
}
public void onBackPressed_() {
// If the navigation view didn't need to do anything, call super
if (!navigationView.onBackPressed()) {
super.onBackPressed();
}
}
protected void onSaveInstanceState_(Bundle outState) {
navigationView.onSaveInstanceState(outState);
}
protected void onRestoreInstanceState_(Bundle savedInstanceState) {
navigationView.onRestoreInstanceState(savedInstanceState);
}
public void onPause_() {
navigationView.onPause();
}
public void onStop_() {
navigationView.onStop();
}
protected void onDestroy_() {
navigationView.onDestroy();
if (isFinishing()) {
saveNightModeToPreferences(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
}
}
#Override
public void onCancelNavigation() {
// Navigation canceled, finish the activity
finish();
}
#Override
public void onNavigationFinished() {
// Intentionally empty
}
#Override
public void onNavigationRunning() {
// Intentionally empty
}
#Override
public void onProgressChange(Location location, RouteProgress routeProgress) {
setSpeed(location);
}
#Override
public void onInstructionListVisibilityChanged(boolean shown) {
instructionListShown = shown;
speedWidget.setVisibility(shown ? View.GONE : View.VISIBLE);
if (instructionListShown) {
// fabNightModeToggle.hide();
} else if (bottomSheetVisible) {
//fabNightModeToggle.show();
}
}
#Override
public SpeechAnnouncement willVoice(SpeechAnnouncement announcement) {
return SpeechAnnouncement.builder().announcement("All announcements will be the same.").build();
}
#Override
public BannerInstructions willDisplay(BannerInstructions instructions) {
return instructions;
}
private void startNavigation(DirectionsRoute directionsRoute) {
NavigationViewOptions.Builder options =
NavigationViewOptions.builder()
.navigationListener(this)
.directionsRoute(directionsRoute)
.shouldSimulateRoute(true)
.progressChangeListener(this);
//.instructionListListener(this)
//.speechAnnouncementListener(this)
// .bannerInstructionsListener(this);
setBottomSheetCallback(options);
//setupNightModeFab();
navigationView.startNavigation(options.build());
}
private void fetchRoute() {
NavigationRoute.builder(this.context)
.accessToken(this.activity.getString(R.string.access_token))
.origin(ORIGIN)
.voiceUnits(DirectionsCriteria.METRIC)
.destination(DESTINATION)
.alternatives(true)
.build()
.getRoute(new Callback<DirectionsResponse>() {
#Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
if(response.body() == null)
{
Log.e("ERROR RUTA","NO RUTA ENCONTRADA");
return;
}else if(response.body().routes().size()==0)
{
Log.e("ERROR RUTA","SIN RUTA ENCONTRADA");
return;
}
DirectionsRoute currentRoute = response.body().routes().get(0);
//navigationMapRoute.addRoute(currentRoute);
startNavigation(currentRoute);
}
#Override
public void onFailure(Call<DirectionsResponse> call, Throwable t) {
}
});
}
void simpleCallBack(Call<DirectionsResponse> call, Response<DirectionsResponse> response)
{
DirectionsRoute directionsRoute = response.body().routes().get(0);
startNavigation(directionsRoute);
}
private void setSpeedWidgetAnchor(#IdRes int res) {
//CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) spacer.getLayoutParams();
//layoutParams.setAnchorId(res);
//spacer.setLayoutParams(layoutParams);
}
private void setBottomSheetCallback(NavigationViewOptions.Builder options) {
options.bottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
switch (newState) {
case BottomSheetBehavior.STATE_HIDDEN:
bottomSheetVisible = false;
//fabNightModeToggle.hide();
setSpeedWidgetAnchor(R.id.recenterBtn);
break;
case BottomSheetBehavior.STATE_EXPANDED:
bottomSheetVisible = true;
break;
case BottomSheetBehavior.STATE_SETTLING:
if (!bottomSheetVisible) {
// View needs to be anchored to the bottom sheet before it is finished expanding
// because of the animation
//fabNightModeToggle.show();
setSpeedWidgetAnchor(R.id.summaryBottomSheet);
}
break;
default:
return;
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
}
});
}
private void setupNightModeFab() {
//fabNightModeToggle.setOnClickListener(view -> toggleNightMode());
}
private void toggleNightMode() {
int currentNightMode = getCurrentNightMode();
alternateNightMode(currentNightMode);
}
private void initNightMode() {
// int nightMode = retrieveNightModeFromPreferences();
//AppCompatDelegate.setDefaultNightMode(nightMode);
}
private int getCurrentNightMode() {
return getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK;
}
private void alternateNightMode(int currentNightMode) {
int newNightMode;
if (currentNightMode == Configuration.UI_MODE_NIGHT_YES) {
newNightMode = AppCompatDelegate.MODE_NIGHT_NO;
} else {
newNightMode = AppCompatDelegate.MODE_NIGHT_YES;
}
saveNightModeToPreferences(newNightMode);
recreate();
}
private void saveNightModeToPreferences(int nightMode) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = preferences.edit();
//editor.putInt(getString(R.string.current_night_mode), nightMode);
editor.apply();
}
private void setSpeed(Location location) {
String string = String.format("%d\nMPH", (int) (location.getSpeed() * 2.2369));
//int mphTextSize = getResources().getDimensionPixelSize(R.dimen.mph_text_size);
//int speedTextSize = getResources().getDimensionPixelSize(R.dimen.speed_text_size);
SpannableString spannableString = new SpannableString(string);
// spannableString.setSpan(new AbsoluteSizeSpan(mphTextSize),
// string.length() - 4, string.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
// spannableString.setSpan(new AbsoluteSizeSpan(speedTextSize),
// 0, string.length() - 3, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
}
I used this article as reference in order to attempt to replicate this but I hit many a speed bump trying to get this to work properly: https://medium.com/flutter-community/flutter-platformview-how-to-create-flutter-widgets-from-native-views-366e378115b6
This is my flutter doctor output:
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.12.13+hotfix.9, on Linux, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Android Studio (version 3.6)
[✓] Connected device (1 available)
• No issues found!
Like I was saying ive been attempting to find a null value and searched high and low for questions similar to this one but Ive had no such luck as this is not something Ive seen done. I also checked if there were any plugins to create and embedded map and unfortunately there arent any at the moment.

cant pass GeoDataClient in placeAutocomplete adapter?

I am trying to make a google place autocomplete adapter. But im getting the following error: Ive been sstuck on this for 2 days now :( so any help would be greatly appreciated!!
cant pass mGeoDataClient
The error i am recieving
Here is my MapClass:
import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.widget.AutoCompleteTextView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.location.places.PlaceDetectionClient;
import com.google.android.gms.location.places.GeoDataClient;
import com.google.android.gms.location.places.Places;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MapActivity extends AppCompatActivity implements OnMapReadyCallback {
protected GeoDataClient mGeoDataClient;
private PlaceDetectionClient mPlaceDetectionClient;
private static final LatLngBounds BOUNDS_GREATER_SYDNEY = new LatLngBounds(
new LatLng(-34.041458, 150.790100), new LatLng(-33.682247, 151.383362));
#Override
public void onMapReady(GoogleMap googleMap) {
Toast.makeText(this, "Map is ready", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onMapReady: map is ready");
mMap = googleMap;
if(mLocationPermissionGranted){
init();
}
}
private static final String TAG = "MapActivity";
private static final String FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
private static final String COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1234;
private static final float DEFAULT_ZOOM = 15f;
//widgets
private AutoCompleteTextView mSearchText;
private boolean mLocationPermissionGranted = false;
private GoogleMap mMap;
private FusedLocationProviderClient mFusedLocationProviderClient;
private PlaceAutocompleteAdapter mplaceAutocompleteAdapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
mSearchText = (AutoCompleteTextView) findViewById(R.id.input_search);
getLocationPermission();
}
private void init(){
mPlaceDetectionClient = Places.getPlaceDetectionClient(this);
mGeoDataClient = Places.getGeoDataClient(this);
mSearchText.setAdapter(mplaceAutocompleteAdapter);
Log.d(TAG, "init: initializing");
mplaceAutocompleteAdapter = new PlaceAutocompleteAdapter(this, mGeoDataClient, BOUNDS_GREATER_SYDNEY, null);
mSearchText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
if(actionId == EditorInfo.IME_ACTION_SEARCH
|| actionId == EditorInfo.IME_ACTION_DONE
|| keyEvent.getAction() == KeyEvent.ACTION_DOWN
|| keyEvent.getAction() == KeyEvent.KEYCODE_ENTER){
//execute our method for searching
geoLocate();
}
return false;
}
});
}
private void geoLocate(){
Log.d(TAG, "geoLocate: geolocating");
String searchString = mSearchText.getText().toString();
Geocoder geocoder = new Geocoder(MapActivity.this);
List<Address> list = new ArrayList<>();
try{
list = geocoder.getFromLocationName(searchString, 1);
}catch (IOException e){
Log.e(TAG, "geoLocate: IOException: " + e.getMessage() );
}
if(list.size() > 0){
Address address = list.get(0);
Log.d(TAG, "geoLocate: found a location: " + address.toString());
//Toast.makeText(this, address.toString(), Toast.LENGTH_SHORT).show();
}
}
private void moveCamera(LatLng latLng, float zoom){
Log.d(TAG, "moveCamera: moving te camera to: lat" + latLng.latitude + ", lng: " + latLng.longitude);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, zoom));
}
private void initMap(){
Log.d(TAG, "initMap: Initializing map");
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(MapActivity.this);
}
private void getLocationPermission(){
Log.d(TAG, "GetLocationPermission: getting location permissions");
String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION};
if(ContextCompat.checkSelfPermission(this.getApplicationContext(),
FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
if(ContextCompat.checkSelfPermission(this.getApplicationContext(),
COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
mLocationPermissionGranted = true;
initMap();
}else {
ActivityCompat.requestPermissions(this,
permissions,LOCATION_PERMISSION_REQUEST_CODE);
}
}else {
ActivityCompat.requestPermissions(this,
permissions,LOCATION_PERMISSION_REQUEST_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
Log.d(TAG, "onRequestPermissionResult: called");
mLocationPermissionGranted = false;
switch (requestCode){
case LOCATION_PERMISSION_REQUEST_CODE:{
if(grantResults.length > 0){
for (int i = 0; i < grantResults.length; i++){
if (grantResults[i] != PackageManager.PERMISSION_GRANTED){
mLocationPermissionGranted = false;
Log.d(TAG, "onRequestPermissionResult: permission failed ");
return;
}
}
Log.d(TAG, "onRequestPermissionResult: permission failed ");
mLocationPermissionGranted = true;
//initialize our map
initMap();
}
}
}
}
}
Here is my app build gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.tw276.ghkjhk"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:support-media-compat:28.0.0 '
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.google.android.libraries.places:places-compat:1.0.0'
implementation 'com.google.android.gms:play-services-location:16.0.0'
implementation 'com.google.android.gms:play-services-maps:16.1.0'
implementation 'com.google.maps.android:android-maps-utils:0.5'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.android.volley:volley:1.1.1'
implementation 'com.android.support:design:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
and here is my adapter class:
import android.content.Context;
import android.graphics.Typeface;
import android.text.style.CharacterStyle;
import android.text.style.StyleSpan;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.common.data.DataBufferUtils;
import com.google.android.gms.location.places.AutocompleteFilter;
import com.google.android.gms.location.places.AutocompletePrediction;
import com.google.android.gms.location.places.AutocompletePredictionBufferResponse;
import com.google.android.gms.location.places.GeoDataClient;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.tasks.RuntimeExecutionException;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Adapter that handles Autocomplete requests from the Places Geo Data Client.
* {#link AutocompletePrediction} results from the API are frozen and stored directly in this
* adapter. (See {#link AutocompletePrediction#freeze()}.)
*/
public class PlaceAutocompleteAdapter
extends ArrayAdapter<AutocompletePrediction> implements Filterable {
private static final String TAG = "PlaceAutocomplete";
private static final CharacterStyle STYLE_BOLD = new StyleSpan(Typeface.BOLD);
/**
* Current results returned by this adapter.
*/
private ArrayList<AutocompletePrediction> mResultList;
/**
* Handles autocomplete requests.
*/
private GeoDataClient mGeoDataClient;
/**
* The bounds used for Places Geo Data autocomplete API requests.
*/
private LatLngBounds mBounds;
/**
* The autocomplete filter used to restrict queries to a specific set of place types.
*/
private AutocompleteFilter mPlaceFilter;
/**
* Initializes with a resource for text rows and autocomplete query bounds.
*
* #see android.widget.ArrayAdapter#ArrayAdapter(android.content.Context, int)
*/
public PlaceAutocompleteAdapter(Context context, GeoDataClient geoDataClient,
LatLngBounds bounds, AutocompleteFilter filter) {
super(context, android.R.layout.simple_expandable_list_item_2, android.R.id.text1);
mGeoDataClient = geoDataClient;
mBounds = bounds;
mPlaceFilter = filter;
}
/**
* Sets the bounds for all subsequent queries.
*/
public void setBounds(LatLngBounds bounds) {
mBounds = bounds;
}
/**
* Returns the number of results received in the last autocomplete query.
*/
#Override
public int getCount() {
return mResultList.size();
}
/**
* Returns an item from the last autocomplete query.
*/
#Override
public AutocompletePrediction getItem(int position) {
return mResultList.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = super.getView(position, convertView, parent);
// Sets the primary and secondary text for a row.
// Note that getPrimaryText() and getSecondaryText() return a CharSequence that may contain
// styling based on the given CharacterStyle.
AutocompletePrediction item = getItem(position);
TextView textView1 = (TextView) row.findViewById(android.R.id.text1);
TextView textView2 = (TextView) row.findViewById(android.R.id.text2);
textView1.setText(item.getPrimaryText(STYLE_BOLD));
textView2.setText(item.getSecondaryText(STYLE_BOLD));
return row;
}
/**
* Returns the filter for the current set of autocomplete results.
*/
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
// We need a separate list to store the results, since
// this is run asynchronously.
ArrayList<AutocompletePrediction> filterData = new ArrayList<>();
// Skip the autocomplete query if no constraints are given.
if (constraint != null) {
// Query the autocomplete API for the (constraint) search string.
filterData = getAutocomplete(constraint);
}
results.values = filterData;
if (filterData != null) {
results.count = filterData.size();
} else {
results.count = 0;
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
// The API returned at least one result, update the data.
mResultList = (ArrayList<AutocompletePrediction>) results.values;
notifyDataSetChanged();
} else {
// The API did not return any results, invalidate the data set.
notifyDataSetInvalidated();
}
}
#Override
public CharSequence convertResultToString(Object resultValue) {
// Override this method to display a readable result in the AutocompleteTextView
// when clicked.
if (resultValue instanceof AutocompletePrediction) {
return ((AutocompletePrediction) resultValue).getFullText(null);
} else {
return super.convertResultToString(resultValue);
}
}
};
}
/**
* Submits an autocomplete query to the Places Geo Data Autocomplete API.
* Results are returned as frozen AutocompletePrediction objects, ready to be cached.
* Returns an empty list if no results were found.
* Returns null if the API client is not available or the query did not complete
* successfully.
* This method MUST be called off the main UI thread, as it will block until data is returned
* from the API, which may include a network request.
*
* #param constraint Autocomplete query string
* #return Results from the autocomplete API or null if the query was not successful.
* #see GeoDataClient#getAutocompletePredictions(String, LatLngBounds, AutocompleteFilter)
* #see AutocompletePrediction#freeze()
*/
private ArrayList<AutocompletePrediction> getAutocomplete(CharSequence constraint) {
Log.i(TAG, "Starting autocomplete query for: " + constraint);
// Submit the query to the autocomplete API and retrieve a PendingResult that will
// contain the results when the query completes.
Task<AutocompletePredictionBufferResponse> results =
mGeoDataClient.getAutocompletePredictions(constraint.toString(), mBounds,
mPlaceFilter);
// This method should have been called off the main UI thread. Block and wait for at most
// 60s for a result from the API.
try {
Tasks.await(results, 60, TimeUnit.SECONDS);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
e.printStackTrace();
}
try {
AutocompletePredictionBufferResponse autocompletePredictions = results.getResult();
Log.i(TAG, "Query completed. Received " + autocompletePredictions.getCount()
+ " predictions.");
// Freeze the results immutable representation that can be stored safely.
return DataBufferUtils.freezeAndClose(autocompletePredictions);
} catch (RuntimeExecutionException e) {
// If the query did not complete successfully return null
Toast.makeText(getContext(), "Error contacting API: " + e.toString(),
Toast.LENGTH_SHORT).show();
Log.e(TAG, "Error getting autocomplete prediction API call", e);
return null;
}
}
}
The exact class the PlaceAutocompleteAdapter constructor expects is
com.google.android.gms.location.places.GeoDataClient
While you're importing, erroneously
com.google.android.libraries.places.compat.GeoDataClient
inside your MapActivity class

Error: Element value must be a constant expression

I am trying to merge 2 android studio projects into one.
Here's my app level build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "com.cricketbuzz"
minSdkVersion 19
targetSdkVersion 23
versionCode 1
versionName "1.0"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
debuggable true
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.android.support:cardview-v7:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.github.JakeWharton:ViewPagerIndicator:2.4.1#aar'
compile 'com.android.support:multidex:1.0.0'
compile 'com.cricketbuzzsdk:CricketBuzzSDK:1.0.0'
compile 'com.wang.avi:library:2.1.3'
compile project(':basketball')
}
Here's my library build.gradle
apply plugin: 'com.android.library'
android {
signingConfigs {
config {
}
}
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
// applicationId "com.gmail.jorgegilcavazos.ballislife"
minSdkVersion 19
targetSdkVersion 23
versionCode 3
versionName "0.1.0"
signingConfig signingConfigs.config
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/LICENCE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE.txt'
}
productFlavors {
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.1.2'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.mcxiaoke.volley:library:1.0.19'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.google.android.gms:play-services-gcm:8.3.0'
compile 'com.android.support:design:23.4.0'
compile 'com.android.support:support-v4:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.android.support:cardview-v7:23.4.0'
compile 'com.android.support:customtabs:23.3.0'
compile 'net.dean.jraw:JRAW:0.9.0'
compile 'com.google.code.gson:gson:2.7'
compile 'com.jakewharton:butterknife:8.4.0'
}
The error I am getting is :
C:\Users\karanc\AndroidStudioProjects\CricketBuzz\basketball\src\main\java\com\gmail\jorgegilcavazos\ballislife\features\games\GameAdapter.java
Error:(112, 23) error: element value must be a constant expression
C:\Users\karanc\AndroidStudioProjects\CricketBuzz\basketball\src\main\java\com\gmail\jorgegilcavazos\ballislife\features\gamethread\CommentThreadFragment.java
Error:(127, 22) error: constant expression required
Here are GameAdapter & CommentThread files:
GameAdapter.java
package com.gmail.jorgegilcavazos.ballislife.features.games;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.gmail.jorgegilcavazos.ballislife.features.data.NbaGame;
import com.gmail.jorgegilcavazos.ballislife.R;
import com.gmail.jorgegilcavazos.ballislife.util.Utilities;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import static android.support.design.R.styleable.RecyclerView;
/**
* RecyclerView Adapter used by the {#link GamesFragment} to display a list of games.
*/
public class GameAdapter extends RecyclerView.Adapter<GameAdapter.GameViewHolder> {
private Context context;
private List<NbaGame> nbaGameList;
private GamesFragment.GameItemListener gameItemListener;
public GameAdapter(List<NbaGame> nbaGames,
GamesFragment.GameItemListener itemListener) {
nbaGameList = nbaGames;
gameItemListener = itemListener;
}
#Override
public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_game,
parent, false);
context = parent.getContext();
return new GameViewHolder(view);
}
#Override
public void onBindViewHolder(final GameViewHolder holder, int position) {
NbaGame nbaGame = nbaGameList.get(position);
int resKeyHome = context.getResources().getIdentifier(nbaGame.getHomeTeamAbbr()
.toLowerCase(), "drawable", context.getPackageName());
int resKeyAway = context.getResources().getIdentifier(nbaGame.getAwayTeamAbbr()
.toLowerCase(), "drawable", context.getPackageName());
holder.tvHomeTeam.setText(nbaGame.getHomeTeamAbbr());
holder.tvAwayTeam.setText(nbaGame.getAwayTeamAbbr());
holder.ivHomeLogo.setImageResource(resKeyHome);
holder.ivAwayLogo.setImageResource(resKeyAway);
holder.tvHomeScore.setText(nbaGame.getHomeTeamScore());
holder.tvAwayScore.setText(nbaGame.getAwayTeamScore());
holder.tvClock.setText(nbaGame.getGameClock());
holder.tvPeriod.setText(Utilities.getPeriodString(nbaGame.getPeriodValue(),
nbaGame.getPeriodName()));
holder.tvHomeScore.setVisibility(View.GONE);
holder.tvAwayScore.setVisibility(View.GONE);
holder.tvClock.setVisibility(View.GONE);
holder.tvPeriod.setVisibility(View.GONE);
holder.tvFinal.setVisibility(View.GONE);
holder.tvTime.setVisibility(View.GONE);
switch (nbaGame.getGameStatus()) {
case NbaGame.PRE_GAME:
holder.tvTime.setVisibility(View.VISIBLE);
holder.tvTime.setText(nbaGame.getPeriodStatus());
break;
case NbaGame.IN_GAME:
holder.tvHomeScore.setVisibility(View.VISIBLE);
holder.tvAwayScore.setVisibility(View.VISIBLE);
holder.tvClock.setVisibility(View.VISIBLE);
holder.tvPeriod.setVisibility(View.VISIBLE);
break;
case NbaGame.POST_GAME:
holder.tvHomeScore.setVisibility(View.VISIBLE);
holder.tvAwayScore.setVisibility(View.VISIBLE);
holder.tvFinal.setVisibility(View.VISIBLE);
holder.tvFinal.setText("FINAL");
break;
}
holder.container.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
gameItemListener.onGameClick(nbaGameList.get(holder.getAdapterPosition()));
}
});
}
#Override
public int getItemCount() {
return null != nbaGameList ? nbaGameList.size() : 0;
}
public void swap(List<NbaGame> data) {
nbaGameList.clear();
nbaGameList.addAll(data);
notifyDataSetChanged();
}
public static class GameViewHolder extends RecyclerView.ViewHolder {
View container;
#BindView(R.id.homelabel) TextView tvHomeTeam;
#BindView(R.id.awaylabel) TextView tvAwayTeam;
#BindView(R.id.homescore) TextView tvHomeScore;
#BindView(R.id.awayscore) TextView tvAwayScore;
#BindView(R.id.clock) TextView tvClock;
#BindView(R.id.period) TextView tvPeriod;
#BindView(R.id.extraLabel) TextView tvTime;
#BindView(R.id.extraLabel2) TextView tvFinal;
#BindView(R.id.homeicon) ImageView ivHomeLogo;
#BindView(R.id.awayicon) ImageView ivAwayLogo;
public GameViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
container = view;
}
}
}
CommentThread.java
package com.gmail.jorgegilcavazos.ballislife.features.gamethread;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import com.gmail.jorgegilcavazos.ballislife.features.shared.CommentAdapter;
import com.gmail.jorgegilcavazos.ballislife.R;
import com.gmail.jorgegilcavazos.ballislife.util.AuthListener;
import com.gmail.jorgegilcavazos.ballislife.util.MyDebug;
import com.gmail.jorgegilcavazos.ballislife.network.RedditAuthentication;
import com.gmail.jorgegilcavazos.ballislife.util.RedditUtils;
import net.dean.jraw.http.SubmissionRequest;
import net.dean.jraw.models.CommentNode;
import net.dean.jraw.models.CommentSort;
import net.dean.jraw.models.Listing;
import net.dean.jraw.models.Submission;
import net.dean.jraw.paginators.Sorting;
import net.dean.jraw.paginators.SubredditPaginator;
import java.util.ArrayList;
import java.util.List;
public class CommentThreadFragment extends Fragment {
private static final String TAG = "CommentThreadFragment";
public interface SubmissionListingFetchListener {
void onSuccess(Listing<Submission> submissions);
void onFailure(String message);
}
public interface FullSubmissionFetchListener {
void onSuccess(Submission submission);
void onFailure(String message);
}
public static final String HOME_TEAM_KEY = "HOME_TEAM";
public static final String AWAY_TEAM_KEY = "AWAY_TEAM";
public static final String THREAD_TYPE_KEY = "THREAD_TYPE";
private static final String NBA_SUBREDDIT = "nba";
private static final int SEARCH_LIMIT = 100;
private static final int RETRY_FIND_SUBMISSION = 0;
private static final int RETRY_FETCH_COMMENTS = 1;
private String mHomeTeam;
private String mAwayTeam;
private String mThreadId;
private boolean mFoundThreadId;
private RedditUtils.GameThreadType mThreadType;
Context mContext;
View rootView;
RecyclerView mRecyclerView;
RecyclerView.LayoutManager mLayoutManager;
CommentAdapter mCommentAdapter;
ProgressBar mProgressBar;
Snackbar mSnackbar;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mHomeTeam = getArguments().getString(HOME_TEAM_KEY);
mAwayTeam = getArguments().getString(AWAY_TEAM_KEY);
mThreadType = (RedditUtils.GameThreadType) getArguments().get(THREAD_TYPE_KEY);
}
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_comment_thread, container, false);
mProgressBar = (ProgressBar) rootView.findViewById(R.id.progressBar);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.comment_thread_rv);
mLayoutManager = new LinearLayoutManager(mContext);
mRecyclerView.setLayoutManager(mLayoutManager);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mRecyclerView.setNestedScrollingEnabled(false);
} else {
ViewCompat.setNestedScrollingEnabled(mRecyclerView, false);
}
return rootView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mContext = getActivity();
if (mFoundThreadId) {
fetchComments();
} else {
findGameSubmission();
}
}
#Override
public void onPause() {
dismissSnackbar();
super.onPause();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_refresh:
dismissSnackbar();
if (mFoundThreadId) {
fetchComments();
} else {
findGameSubmission();
}
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Starts a {#link FetchSubmissionListing} task that retrieves a list of submissions in the
* /r/nba subreddit. If it is successfully retrieved, it tries to find the one that belongs
* to this game and shows its comment tree.
*/
private void findGameSubmission() {
AuthListener authListener = new AuthListener() {
#Override
public void onSuccess() {
findGameSubmission();
}
#Override
public void onFailure() {
showSnackBar("Failed to connect to Reddit", true, RETRY_FIND_SUBMISSION);
}
};
SubmissionListingFetchListener fetchListener = new SubmissionListingFetchListener() {
#Override
public void onSuccess(Listing<Submission> submissions) {
mThreadId = RedditUtils.findNbaGameThreadId(submissions, mThreadType,
mHomeTeam, mAwayTeam);
if (mThreadId != null) {
mFoundThreadId = true;
fetchComments();
} else {
mFoundThreadId = false;
showSnackBar("No comment thread found", true, RETRY_FIND_SUBMISSION);
}
}
#Override
public void onFailure(String message) {
showSnackBar(message, true, RETRY_FIND_SUBMISSION);
}
};
new FetchSubmissionListing(mContext, NBA_SUBREDDIT, SEARCH_LIMIT, Sorting.NEW,
fetchListener, authListener).execute();
}
/**
* Starts a {#link FetchFullSubmission} task that retrieves the Submission of the given
* submissionId. A "full" submissions is one that also contains its comment tree.
*/
private void fetchComments() {
AuthListener authListener = new AuthListener() {
#Override
public void onSuccess() {
fetchComments();
}
#Override
public void onFailure() {
showSnackBar("Failed to connect to Reddit", true, RETRY_FETCH_COMMENTS);
}
};
FullSubmissionFetchListener fetchListener = new FullSubmissionFetchListener() {
#Override
public void onSuccess(Submission submission) {
loadComments(submission);
}
#Override
public void onFailure(String message) {
showSnackBar(message, true, RETRY_FIND_SUBMISSION);
}
};
new FetchFullSubmission(mContext, mThreadId, fetchListener, authListener).execute();
}
/**
* Loads a tree of comments into the RecyclerView, given a Reddit Submission.
*/
private void loadComments(Submission submission) {
Iterable<CommentNode> iterable = submission.getComments().walkTree();
List<CommentNode> commentNodes = new ArrayList<>();
for (CommentNode node : iterable) {
commentNodes.add(node);
}
mCommentAdapter = new CommentAdapter(mContext, commentNodes);
mRecyclerView.setAdapter(mCommentAdapter);
}
private void showSnackBar(String message, boolean retry, final int retryCode) {
mSnackbar = Snackbar.make(rootView, message,
Snackbar.LENGTH_INDEFINITE);
if (retry) {
mSnackbar.setAction("RETRY", new View.OnClickListener() {
#Override
public void onClick(View v) {
switch (retryCode) {
case RETRY_FIND_SUBMISSION:
findGameSubmission();
break;
case RETRY_FETCH_COMMENTS:
fetchComments();
break;
}
}
});
}
mSnackbar.show();
mProgressBar.setVisibility(View.GONE);
}
private void dismissSnackbar() {
if (mSnackbar != null && mSnackbar.isShown()) {
mSnackbar.dismiss();
}
}
/**
* Retrieves a Listing of Reddit Submissions, given a subreddit, a limit of submissions and a
* sorting option.
*/
private class FetchSubmissionListing extends AsyncTask<Void, Void, Listing<Submission>> {
private Context mContext;
private String mSubreddit;
private int mLimit;
private Sorting mSorting;
private SubmissionListingFetchListener mFetchListener;
private AuthListener mAuthListener;
public FetchSubmissionListing(Context context, String subreddit, int limit, Sorting sorting,
SubmissionListingFetchListener fetchListener,
AuthListener authListener) {
mContext = context;
mSubreddit = subreddit;
mLimit = limit;
mSorting = sorting;
mFetchListener = fetchListener;
mAuthListener = authListener;
}
#Override
protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.GONE);
}
#Override
protected Listing<Submission> doInBackground(Void... params) {
RedditAuthentication redditAuthentication = RedditAuthentication.getInstance();
if (redditAuthentication.getRedditClient().isAuthenticated()) {
SubredditPaginator paginator = new SubredditPaginator(
redditAuthentication.getRedditClient(), mSubreddit);
paginator.setLimit(mLimit);
paginator.setSorting(mSorting);
try {
return paginator.next(false /* forceNetwork */);
} catch (Exception e) {
if (MyDebug.LOG) {
Log.d(TAG, "Reddit auth error on FetchSubmissionListing.");
}
}
} else {
mFetchListener.onFailure("Failed to connect to Reddit");
}
return null;
}
#Override
protected void onPostExecute(Listing<Submission> submissions) {
if (submissions != null) {
mFetchListener.onSuccess(submissions);
} else {
if (!RedditAuthentication.getInstance().getRedditClient().isAuthenticated()) {
// Attempt to authenticate once.
RedditAuthentication.getInstance().authenticate(mContext, mAuthListener);
}
mFetchListener.onFailure("Failed to connect to Reddit");
}
}
}
/**
* Retrieves a "full" Reddit submission given a Reddit submisisonId. A "full" submission is one
* that also contains its comment tree.
* The sorting of the thread is determined by mThreadType (Live game or post game).
*/
private class FetchFullSubmission extends AsyncTask<Void, Void, Submission> {
private Context mContext;
private String mThreadId;
private FullSubmissionFetchListener mFetchListener;
private AuthListener mAuthListener;
public FetchFullSubmission(Context context, String threadId,
FullSubmissionFetchListener fetchListener,
AuthListener authListener) {
mContext = context;
mThreadId = threadId;
mFetchListener = fetchListener;
mAuthListener = authListener;
}
#Override
protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.GONE);
}
#Override
protected Submission doInBackground(Void... params) {
if (mThreadId == null) {
return null;
}
SubmissionRequest.Builder builder = new SubmissionRequest.Builder(mThreadId);
switch (mThreadType) {
case LIVE_GAME_THREAD:
builder.sort(CommentSort.NEW);
break;
case POST_GAME_THREAD:
builder.sort(CommentSort.TOP);
break;
default:
builder.sort(CommentSort.TOP);
break;
}
SubmissionRequest submissionRequest = builder.build();
try {
return RedditAuthentication.getInstance()
.getRedditClient().getSubmission(submissionRequest);
} catch (Exception e) {
if (MyDebug.LOG) {
Log.d(TAG, "Could not load submission in FetchFullSubmission.");
}
}
return null;
}
#Override
protected void onPostExecute(Submission submission) {
mProgressBar.setVisibility(View.GONE);
if (submission != null) {
mFetchListener.onSuccess(submission);
mRecyclerView.setVisibility(View.VISIBLE);
} else {
if (!RedditAuthentication.getInstance().getRedditClient().isAuthenticated()) {
// Attempt to re-authenticate once.
RedditAuthentication.getInstance().authenticate(mContext, mAuthListener);
}
mFetchListener.onFailure("Failed to connect to Reddit");
}
}
}
}
How to get rid of this??
Screenshots of errors
:
You have implemented Butterknife in your library project. Butterknife doesnot work for library project.For more details you can follow this link
https://github.com/JakeWharton/butterknife/issues/45
As pointed out on this github issue, it can work by using R2.id instead of R.id when we are using Butterknife in library project.

Google recognizer and pocketsphinx in two different classes, how to loop them?

Yesterday i ask a simplified question of my problem, but think its too simplified.
What my programm should do, is to hear a keyword and when he hear it, he should listen to what i said. (like if you told to siri or google now, by saying siri or ok google).
I'm using pocketsphinx for the keyword and the google speechrecognizer for the longer parts. It works, but only for one time. The pocketsphinx is in the MainActivity and the google recognizer is in an extra class (Jarvis).
The programm starts with the pocketsphinx listener, when he hear the KEYPHRASE, he starts the google listener by calling jarvis.startListener() (by the next()-method) and there is the problem, when the googlelistener is done, i dont come back from the Jarvis-class to the MainActivity to call the next() method again.
(when the google recognizer is done, the last things he do is in the onResult() in Jarvis-class, but from there i cant call the next()-method from MainActivity-class)
MainActivity
package com.example.superuser.jarvis;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import edu.cmu.pocketsphinx.Assets;
import edu.cmu.pocketsphinx.Hypothesis;
import edu.cmu.pocketsphinx.SpeechRecognizer;
import edu.cmu.pocketsphinx.SpeechRecognizerSetup;
import static android.widget.Toast.makeText;
import static edu.cmu.pocketsphinx.SpeechRecognizerSetup.defaultSetup;
public class MainActivity extends Activity implements edu.cmu.pocketsphinx.RecognitionListener {
private String LOG_TAG = "Jarvis_hears_anything";
private TextView tv;
private Jarvis jarvis;
private boolean wannahearjarvis = false;
/* Named searches allow to quickly reconfigure the decoder */
private static final String KWS_SEARCH = "wakeup";
/* Keyword we are looking for to activate menu */
private static final String KEYPHRASE = "jarvis";
private edu.cmu.pocketsphinx.SpeechRecognizer recognizer;
//private HashMap<String, Integer> captions;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button button = (Button) findViewById(R.id.b1);
tv = (TextView) findViewById(R.id.tv1);
//captions = new HashMap<String, Integer>();
//captions.put(KWS_SEARCH, R.string.kws_caption);
jarvis = new Jarvis(getApplicationContext());
new AsyncTask<Void, Void, Exception>() {
#Override
protected Exception doInBackground(Void... params) {
try {
Assets assets = new Assets(MainActivity.this);
File assetDir = assets.syncAssets();
setupRecognizer(assetDir);
} catch (IOException e) {
return e;
}
return null;
}
#Override
protected void onPostExecute(Exception result) {
if (result != null) {
((TextView) findViewById(R.id.tv1))
.setText("Failed to init recognizer " + result);
} else {
//switchSearch(KWS_SEARCH);
recognizer.startListening(KWS_SEARCH);
}
}
}.execute();
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "geht", Toast.LENGTH_SHORT).show();
}
});
}
public void next(){
if (wannahearjarvis){
recognizer.startListening(KWS_SEARCH);
wannahearjarvis = false;
}
else{
jarvis.startListening();
wannahearjarvis = true;
}
}
#Override
public void onDestroy() {
super.onDestroy();
recognizer.cancel();
recognizer.shutdown();
}
/**
* In partial result we get quick updates about current hypothesis. In
* keyword spotting mode we can react here, in other modes we need to wait
* for final result in onResult.
*/
#Override
public void onPartialResult(Hypothesis hypothesis) {
if (hypothesis == null)
return;
String text = hypothesis.getHypstr();
if (text.equals(KEYPHRASE)){
tv.append("found");
recognizer.stop();
//switchSearch(KWS_SEARCH);
}
else {
//((TextView) findViewById(R.id.tv1)).append(text+"PR");
//Log.i(LOG_TAG, text+"PR");
}
}
/**
* This callback is called when we stop the recognizer.
*/
#Override
public void onResult(Hypothesis hypothesis) {
//((TextView) findViewById(R.id.tv1)).setText("");
((TextView) findViewById(R.id.tv1)).append("oR");
if (hypothesis != null) {
String text = hypothesis.getHypstr();
makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
next();
}
#Override
public void onBeginningOfSpeech() {
}
/**
* We stop recognizer here to get a final result
*/
#Override
public void onEndOfSpeech() {
if (!recognizer.getSearchName().equals(KWS_SEARCH)){
tv.append("fuck");
}
//switchSearch(KWS_SEARCH);
}
/*private void switchSearch(String searchName) {
recognizer.stop();
// If we are not spotting, start listening with timeout (10000 ms or 10 seconds).
if (searchName.equals(KWS_SEARCH))
recognizer.startListening(searchName);
else
recognizer.startListening(searchName, 10000);
//String caption = getResources().getString(captions.get(searchName));
//((TextView) findViewById(R.id.tv1)).setText(caption);
//((TextView) findViewById(R.id.tv1)).append(caption);
}*/
private void setupRecognizer(File assetsDir) throws IOException {
// The recognizer can be configured to perform multiple searches
// of different kind and switch between them
recognizer = defaultSetup()
.setAcousticModel(new File(assetsDir, "en-us-ptm"))
.setDictionary(new File(assetsDir, "cmudict-en-us.dict"))
// To disable logging of raw audio comment out this call (takes a lot of space on the device)
.setRawLogDir(assetsDir)
// Threshold to tune for keyphrase to balance between false alarms and misses
.setKeywordThreshold(1e-20f)
// Use context-independent phonetic search, context-dependent is too slow for mobile
.setBoolean("-allphone_ci", true)
.getRecognizer();
recognizer.addListener(this);
/** In your application you might not need to add all those searches.
* They are added here for demonstration. You can leave just one.
*/
// Create keyword-activation search.
recognizer.addKeyphraseSearch(KWS_SEARCH, KEYPHRASE);
}
#Override
public void onError(Exception error) {
((TextView) findViewById(R.id.tv1)).setText(error.getMessage());
}
#Override
public void onTimeout() {
//switchSearch(KWS_SEARCH);
}
}
Jarvis
package com.example.superuser.jarvis;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.widget.Toast;
import java.util.ArrayList;
public class Jarvis implements RecognitionListener{
private AudioManager audiom;
private SpeechRecognizer speech;
private Intent recogIntent;
private Toast m;
private Context c;
private String text;
public Jarvis(Context context){
speech = SpeechRecognizer.createSpeechRecognizer(context);
speech.setRecognitionListener(this);
recogIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
recogIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "de");
//recogIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, context.getPackageName());
m = new Toast(context);
c=context;
}
public void startListening(){
speech.startListening(recogIntent);
}
public void destroy(){
speech.stopListening();
speech.cancel();
speech.destroy();
}
#Override
public void onReadyForSpeech(Bundle params) {
}
#Override
public void onBeginningOfSpeech() {
}
#Override
public void onRmsChanged(float rmsdB) {
}
#Override
public void onBufferReceived(byte[] buffer) {
}
#Override
public void onEndOfSpeech() {
}
#Override
public void onError(int error) {
}
#Override
public void onResults(Bundle results) {
ArrayList<String> matches = results
.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
Toast.makeText(c, matches.get(0), Toast.LENGTH_LONG).show();
speech.cancel();
//tried
//MainActivity m = new MainActivity();
//m.next();
//but got a Nullpointer Exception
}
#Override
public void onPartialResults(Bundle partialResults) {
}
#Override
public void onEvent(int eventType, Bundle params) {
}
}
You can store reference to the main activity in Jarvis object in a field:
class Jarvis {
....
private MainActivity m;
....
public Jarvis(MainActivity m) {
this.m = m;
}
....
public void onResults(Bundle results) {
....
m.next();
}
You can also send intents to the main activity as described here. This might be overkill in your case though.

Categories